传统银行有大量的供应商系统,更有甚者,比如我们负责的业务部门,还要重度依赖供应商持续地进行定制化开发和修复。
一般谈到持续交付或自动化部署,都是具备最新架构思维的自主开发方面,或者是利用Ansible、蓝绿部署、容器等实现应用程序的快速部署等方法。
但大多数供应商系统的设计陈旧,变更重度依赖数据库更新(很多逻辑通过存储过程来实现)。面对这样的系统,要实现持续交付,需要另辟蹊径。
我们管理的供应商系统是一个服务于全球包括亚洲和欧洲10个国家和地区的单体应用,是基于.NET和Oracle数据库开发,运行在Windows Server和IIS服务器上的。每个月有超过20个变更需要发布到生产环境。**
我们一直采用月度发布的节奏。每次发布的范围大、风险高,需要全球各地业务部门加班配合测试,执行时间长。由于维护时间窗口(没有业务使用,可停机的时间)只有周末和工作日早上6点至8点,要提高发布频率,只能靠加班,显然不可持续。
一、目标
为了引导各部门实现DevOps,公司定了明确的目标—— 发布次数翻倍,故障数减半。 虽然我们并不关注具体数字,但这也给了所有部门方向与压力。对于我们来说,如何在不加班的情况下实现在工作日发布成了具体目标。
二、重要发现
我们对系统和发布过程做了深入分析,得出以下的重要结论:
大部分的发布是数据补丁,这些数据补丁只影响单个国家或地区,范围小,风险低。如果在工作日就把这些数据补丁发布了,既可大大加快其业务价值的实现,提高业务部门的满意度,也解决了我们“80%的问题”(柏拉图定律)。 剩余的少数有全球影响的其他补丁,则继续在月度发布(周末)完成,但剔除了大部分数据补丁后,其范围已经大大缩小,风险也降低了。**
另外,由于数据补丁只影响单个国家或地区,我们不必拘泥于早上6点至8点这个全球维护时间窗口。因为每个国家或地区的业务时间不一样,我们完全可以根据各个国家或地区的业务时间制定相应的数据补丁发布时间窗口,比如香港是晚上11点到次日8点,欧洲是凌晨2点到下午4点等,给了我们更大的灵活性。
三、实施方案
过去,供应商提供了补丁后,我们IT团队需要手动部署到测试环境,然后通知业务测试。这个过程费时费力,也没有什么价值。考虑到供应商驻场人员可以访问我们网络与Github,我们考虑把这个过程自动化了,拟定了以下的流水线设计:
3.1 测试环境
目标:IT团队不需要介入
- 供应商驻场人员把补丁发布提交到Github的测试分支,触发相应的Jenkins Job;
- Jenkins Job触发公司自研的数据库自动部署工具,把脚本部署到相应的测试环境;
- 我们要求供应商在提供补丁时,也要提供相应的验证脚本,在部署时一同执行;
- 验证通过后,我们通知业务开始验收测试(UAT);
- 验证不通过,验证脚本会抛出异常,部署工具会通知我们执行回滚。
3.2 生产环境
目标:在维护时间窗口定时自动发布
- 当该补丁用户验收测试(UAT)通过后,我们把它合并到Github的master分支,并按公司规定发起发布审批流程;
- 设定相应Jenkins Job的计划执行时间(下一个工作日中该补丁涉及到的国家或地区的维护时间窗口);
- Jenkins Job触发数据库自动部署工具,把脚本部署到生产环境;
- 验证脚本通过后,发布成功;
- 验证不通过,我们将收到通知,上线执行回滚。
四、成果
通过这套方案,我们实现了以下几个目标:
- 大部分的数据补丁不需要等到月度发布才上线,实现了持续交付,大大加快了其业务价值的实现,提高业务满意度;
- IT从部署这项费时费力、价值不大的工作中解放了出来,可以做更有价值的事情,如业务需求或故障分析;
- 补丁发布上线不再是一项高风险的事情,业务和IT都不再对每次发布战战兢兢;
- 大大减少加班时间;
- 每月发布次数从1到2次上升到十几次,由于每次发布的范围小,风险低,也减少了因发布引起的故障数量,满足了公司的DevOps目标。
五、落地难点
实践过程总不是一帆风顺的,我们在过程中也遇到了很多问题,这部分可以分享一些我们针对落地难点的做法,以供参考。
5.1 进度保障
由于日常的交付和维护工作占用了我们几乎全部的工作时间,文中提到的这类重要而不紧急的事情通常都会无疾而终。为了避免这种情况,我们利用每日站会来讨论落地细节和跟踪进度。
我们把站会分为两类:一、三、五讨论日常工作;二、四讨论这个流水线的实施。
这样我们便可确保每天都有进度,并在一个多月的时间内实现了预定目标。
5.2 自动验收
由于发布到生产环境的过程可能是在非工作时间内自动进行的,我们需要有自动验收发布结果的过程,以确保系统在发布后能正常运行;当验收不通过时,触发发布失败,通知我们执行回滚操作。
这就需要供应商在提供补丁脚本时,也要提供验收脚本,作为部署的一部分,自动测试补丁部署后的结果是否符合预期。
举个栗子:
DECLARE
NumberOfPatch_Actual number;
NumberOfPatch_Expect int:=2;
BEGIN
select count(*) into NumberOfPatch_Actual from USERS where a.user_id = 'USERA';
If
NumberOfPatch_Actual <> NumberOfPatch_Expect
then
RAISE_APPLICATION_ERROR(-20001,'Error, This is testing for the log capturing');
END if;
END;
/
这种变相的测试驱动编程(TDD)的思想需要供应商习惯和配合。
5.3 自动回滚
有了自动验收,如何实现自动回滚,从而使整个过程完全自动化,是我们其中一个考虑点。但是由于补丁执行过程有若干步,很难预知每一种的失败情形,最终我们决定还是采用手动回滚比较稳妥。
5.4 失败通知
当验收脚本运行不通过时,意味着发布失败,如何让在工作时间外的我们得到及时的通知,立即上线执行回滚操作,是确保系统正常运行的关键。
但是目前我们的流水线系统只能发出邮件通知,没有针对手机的即时通知手段,这一点仍需要寻找更有效手段。
六、总结
常说的持续交付和自动化部署方案大多是针对自主开发和应用程序的。
对于设计陈旧的供应商系统或遗留系统,多数变更在数据库上实现,要实现持续交付,可能需要另辟蹊径。
在考虑方案前,要深入理解你的系统和发布过程;利用每日站会,持续讨论落地细节和跟踪进度,确保目标达成。
作者:IDCF社区分享嘉宾 刘华
《猎豹行动:硝烟中的敏捷转型之旅》作者