2019可信云大会 | 刘婷:城商行持续交付实践与推广

2019年7月3日09:59:00 发表评论 7 浏览

非常高兴有机会能跟大家一起交流学习,我是来自郑州银行信息科技部的刘婷,主要负责我们行的DevOps能力推广,还有相关平台的研发工作。

先简单介绍一下我们行的情况。郑州银行是一个城商行,咱们国家的银行分为国有银行、股份制银行和城商行等等,像宁波有宁波银行、南京有南京银行,我们郑州也有自己的银行,就是郑州银行。郑州银行目前已经在A股和H股上市,并且我们在城商行里也属于第一梯队,我们对科技这块的投入也比较大,像我们在DevOps做持续交付能力建设的过程中,上到行级领导,下到部门总经理再到分管开发工作的副总都是非常支持的。

2019可信云大会 | 刘婷:城商行持续交付实践与推广

这个是我今天介绍的提纲,从四个方面给大家做简单的交流。首先是开展持续交付工作的前提,我们为什么要做持续交付呢,2018年5月份我们银行的新版核心业务系统刚上线,银行的同事都知道这是一个非常大的项目,我们的核心一改,整个银行可能有100多个系统都要跟着改造,改了以后我们积累的需求和开发、测试、运维工作量都变得特别大。在这个背景下,我们就启动了一系列的工作,当时业务部门提出了非常多的需求,可能半年提交的需求比去年全年的1.5倍还要多,而且这些需求也都急着上线,在这种迫切需求的背景下我们怎么满足业务部门的要求,是一件需要好好规划的事情。首先我们把配置管理和环境管理做起来,之后我们又做了很多的自动化的工作,比如说自动化部署、自动化测试等等。像这里列举到的困惑,就是核心刚上线的时候,某个系统遇到的实际问题。因为测试环境是受控的,有专门的环境管理员,当时某个开发人员为了解决测试遇到的问题,一个小时提了11个发版申请,不停地改缺陷,这就占了一个环境管理的人力,这一个人在这一小时内就为这一个系统服务,这是效率非常低的事情,由此可见自动化对我们来说有多么重要。

后来我们又接触到了持续交付的概念,发现它和我们自己本身想做的事情非常相近。首先我们的项目管理已经非常规范,新核心以后,我们从配置到环境再到自动化测试、自动化部署都逐渐起步。然后我们的质量,当时自动化测试只做了接口级别的,对于想做快速交付来说是不够的,因为接口级别从我们的代码覆盖率上来说,覆盖的代码行数比较少,逻辑也是比较少,而且想探测它的覆盖率也不容易,所以后来我们看到持续交付标准,又做了一些单元测试,就是到函数或者方法级别的测试,还有静态代码质量和安全扫描的工作,把我们最关心的规范加入了进去。另外增加了测试频率,原来自动化测试是在临近上线前每晚定时运行,后来我们会在好几个阶段做,有的是提完代码以后运行,有的就是新功能测试的时候,还有夜间的全量运行等等,根据不同的时机测试的范围也不同。说到提升效率,必须要很多工作都自动化了,像部署这件事情,是有很强的通用性。我们原来发布一个版本,最快要15分钟,做了自动化部署以后,编译加上版本替换,包括配置文件和目标版本,加上程序的停止和启动、执行等等,最快可能不到30秒就完成了。慢的话,像我们核心系统慢在全量编译,比如说一百万行代码全量编译就需要五分钟,这个是无法节约的时间。另外关于测试,做了自动化以后,现在核心系统每天晚上可以跑一万五千条案例。如果转化成手工,我们做新核心项目的时候,整个核心才测了五万条案例,我们现在一晚上可以跑一万五千条,这个量级无法对比。另外就是度量反馈,原来很多指标可能是分散在各个平台里的,只有项目管理平台或者自动化测试平台,谁负责这个平台谁关注。现在我们把指标集中起来了,二是指标做的更丰富,更有助于我们做一些决策,后面也会看一些具体的指标示例。

关键要素,这里我想说几点,一个就是标准化。可能在场有的朋友知道,我们也是参加了DevOps运营一体化成熟部的评估,并且从2018年9月份接触到这个标准,到2019年3月份已经过级了,而且是三级,看似好像时间比较短,但实际上我们的项目管理是从2014年开始做。我们的配置管理是从2016年准备启动新核心的时候开始规划的,包括环境管理也是这样,我们的部署发布,其实在2018年的5月份开始做,到9月份已经有将近20个系统已经实现了自动化的部署,我们自动化测试其实在没有做新核心项目之前,对于老系统已经做了两万条的自动化案例,换了新核心以后,因为接口全部变了,所以我们重新做了,在我们去年评估之前我们的核心案例已经达到了八千条。另外,我们这次做的过程,遵循原来的流程,尤其像我们持续交付团队或者测试团队,甚至项目管理或者是架构团队,在我们行被定义为服务支撑型的团队,我们服务的对象可能是开发、测试、运维。我们不能去强推流程,我们要帮助他们节约时间,减轻他们的工作量,所以我们一定要因地制宜,不要造一些新流程,让他们学习新流程,我们是根据现有流程,先找他们的痛点再改进的。另外管理模式这边,我们是从上到下的支撑非常到位,像我们行的科技的规模大概一百多人,本来大家都比较熟,领导再鼎力支持,我们配合的非常好,所以也是很快能做好的一个关键点。

第二部分,给大家看一下我们的持续交付具体是怎么做的。这是我们的工具链,里面的工具大家都看到过了,像我们这个开源项目管理平台Redmine,我们是2014年开始用这个平台,它的开源组件比较丰富,另外官网也会提供一些模板,会有一些项目管理的思想在里面,我们项目管理思想也是借鉴了他们工具的一些思想。其他的像我们常用的标准流水线工具,还有制品库,刚才大家都讲了我不多介绍了。这里我们用了OpenLdap工具做了统一登录,和各个工具链对接起来,没有问题。还有中间这条虚线代表的意思是什么呢,我们在开发测试环境,做了全流程的持续交付,但是在生产环境上只做了自动化部署,为什么呢,我们认为我们在生产环境不需要再重新构建,在开发测试环境就应该做好,生产环境应该是我们测好稳定的包去部署,所以我们生产侧只有自动化部署的平台,后面我们会加自动化测试环节进去。生产环境的自动化测试也有很多要注意的问题,举个例子,比如想在生产环境测试手机银行系统,用谁的账号测试呢,用谁的账号转账呢,这就有一个账户安全问题。所以我们初步规划就是做一些简单的查询或者不需要用户登录的简单操作去验证,因为这个银行的监管还是比较多的,并不是说什么交易都可以在生产做的。

下面给大家介绍流水线的构建策略,我们研发流程是分开发、SIT测试和UAT测试三阶段,开发阶段,主要有一到两条流水线,这个流水线主要是针对我们的特性分支,只要提了代码,就有编译然后单测,比如核心系统有一百万行代码,全量扫描要30分钟,这样我们开发一天提交十几次代码,给他每次半个小时,这一天就在等待中度过了,所以我们把这个全量扫描拆出来,在开发分支开发完了以后会合并到发布分支,提交合并请求会触发代码扫描,如果扫描不通过就不会通过合并请求,对一些小的应用部分,我们直接生成一条流水线,保证这个流水线一般是在10到15分钟内是可以运行完毕的,在SIT阶段,做的就是编译、单测、部署、自动化冒烟测试和SIT测试。UAT也是做编译、单测和部署,自动化冒烟及新功能测试,都通过之后交付给业务人员,让他们开始UAT测试。晚上会跑一些全量的扫描,刚才有朋友问到,像这种安全扫描放到什么时候,我们核心业务系统一次全量安全扫描大概要13个小时,我们就给它放到晚上,可能是三天扫一次。这是我们一个流水线的真实示例,做起来步骤还是比较多的,需要根据自己企业的实际情况定制。

注意事项,这个刚才说到了,高频高效,还有错误的精准推送,我们上了大量的工具链,每个工具链报错都有推送机制,比如邮件推送、短信推送等,如果不能精确到人,更多邮件会被当成垃圾邮件过滤掉。我们的分类是什么呢,像开发阶段,谁提交代码把错误推给谁,自动化测试阶段出错推送给自动化测试的人,自动化部署阶段如果是SQL执行出错推送给提交代码的开发,如果是其他步骤出错推送给自动化部署的人,大概是这样的分类。这个是我们的配置管理的分支策略,和其他的策略都不一样,主要是我们的银行有并行开发的情况,比如说现在开发的一个需求,7月5号窗口上线,但是项目组另外一个人开发的需求是7月18号上线,这个时候我们会有多个上线窗口,属于同一个上线窗口的需求我们汇总为一条发布分支这样管理。环境管理这块儿,我们会有集成测试环境,窗口版本测试环境,长周期跑批环境,专项环境等。专项环境包括性能测试、自动化测试、项目专项。我们每个环境只允许做单独版本的测试,不允许做混合版本的测试,这样的话虽然有一部分远期版本可能无法及时测试,但我们已经覆盖了90%以上的场景。其实在之前,我们的测试环境是按照混合版本测试环境及回归测试环境来划分的,混合版本测试环境中有各个窗口要上线的需求,这样的好处就是所有的需求都有环境测试,在即将上线的时候再进入回归测试环境进行测试。但实际我们发现,有部分需求可能是没经过回归测试环境就直接上线了,这样是有风险的。因为我们的很多UAT测试是业务人员做的,银行的业务流程又比较长,造测试数据都挺麻烦,出于种种原因,一些混合版本没有经过回归进入到生产环境,可能会带一些其他窗口的合并文件进去,从而导致生产缺陷。所以我们特意把测试环境做了分离,宁可不支持所有版本的测试,也要保证环境中版本的纯净,保证测试的版本和上线的内容是一致的。

下面看我们自动化部署,我们用的是商业软件。在我们没有接触到自动化部署之前,我们会用开源工具写一些部署脚本,但是在数据库管理这块,我们一直做得不是特别好,尤其是SQL自动部署,这种是不能重复执行的,所以对SQL版本也要有管理,后来我们采购了一个商业工具,很快,也不贵,我们自己感觉用的不错。过程中总结出来我们做自动化部署要注意的三个问题,一个是规划好这次发的版本是什么,这个是和分支对应起来的。另外就是我们要规划好你发到哪个环境,因为你在做没有做容器之前,我们每次部署更新的只有应用的版本和数据库的版本,我们不会把基础软件或中间件重新装一遍,不同环境中A系统和B系统访问的IP是不同的,环境配置的管理要做好。另外就是步骤的管理,一定是灵活的,有的应用可能这次发布没有SQL,下次发布才有SQL,有的SQL可能在程序启动前执行,有的SQL在程序启动后执行,这个时候我们一定要有一个灵活定制的步骤。SQL一定要有版管理,不然的话SQL的建表和插入语句,重复执行是会报错的。我见过有一些应用,可能在初始的时候做的好,后面新增的SQL只是一些查询的语句或者更新的语句,重复执行是不会报错的,但如果重复执行更新语句还是有风险的,如果要更新的字段代表了一定的状态,因为业务流程驱动状态已经改变了但又因为更新语句重复执行而被重置就会导致生产问题,所以我们一定要做好SQL版本管理,已经执行过的不要重复执行。

测试这块,经典的测试模型大家肯定都知道,我们目前还没有做到金字塔模型,做自动化测试之前我们主要是倒金字塔模型,主要依赖于人工测试,做了DevOps以后,我们觉得是橄榄球的形状,接口测试案例非常多,把所有接口基本覆盖了,而且每个接口的自动化案例在30个以上,但是我们也想做到真正的金字塔模型,后面也会讲具体策略。这个是我们之前在做持续交付核心项目认证成熟度的时候做的分层测试要求,新增代码要求单测覆盖率。比如,我们核心当时开发好了,一百万行的代码,我让开发补充所有单测案例显然不现实,所以我要求新增代码覆盖率,这样要求以后,核心覆盖率从开发人员不会写单测,然后到他做了一两个月以后,覆盖率能达到46%,我们觉得这个效果还是比较好的,虽然我知道很多互联网企业可能会做到90%以上。另外,就是我们的接口测试,这块儿我们是想让测试人员来写,但是想找一个合适的测试开发人员成本也是比较高,并且比较难找,很多有开发经验的人更想做产品开发,而不是做测试工具的开发,所以我们把测试工具做高度的封装。这是我们接口测试的结构。我们行里所有的系统,对外提供服务的接口都经过了服务治理,它的接口的格式都是标准化的,我们会用统一的格式描述,导入到我们的接口测试平台里,生成基础接口,然后再加上我们的协议、报文头及默认数据。通常开源的测试框架需要自己选协议,去实现这个协议,去一层层封装,我们的平台是已经把这些封装好了,接口测试人员可以不用关注你用什么协议,你只要关注调用什么接口完成什么测试就可以了。像我们测试转账功能的时候,最基础的步骤就是先开一个客户,再开一个账户,在进行转账。开客户需要调用五个接口,开账户需要调用三个接口完成,我们都会把这些基础的操作封装成一个组件,比如开客户组件,开账户组件,转账组件,最后我们的案例会用这些组件完成。这样测试人员需要掌握的是,完成一个功能需要调的有什么接口,不需要关心底层的技术。

另外就是度量与反馈建设纲领,在定义一个指标的时候考虑的问题很多,比如像右边定的这些,从名称到公式,到展示的形式。有些指标可能你看当时的时刻点是没有意义的,你需要看趋势。比如我关注自动化测试执行时间,今天执行的两小时,明天是两小时零五分钟,我记不住这些散乱点,也不会定一个统一的阈值,因为随着案例的增加,测试时间是会变长的。我要看一段时间内的变化的趋势,这个是我要考虑好的。另外你选什么样的指标呢,我们通常的指标是KPI考核什么,每次写工作总结的时候,我们汇报什么指标,这些就是我第一次要做的指标。后面我们可能会参考业界的指标,就是行业里的指标,我们不要上去就找网上的模板,把这些指标实现,你在工作中无法用它考核,无法评价你的工作成果,你会发现这个指标没有多久就会废弃。当时我们做第一版是51的指标,经过精简只剩下了30多个了,有很多都是不用的。

这是我们最近增加的指标,我们城商行很多产品的研发是由外包人员完成的,有时候一个产品经理可能会管三到五个产品,手下有几十个外包人员,外包人员每天报工,我今天写了八个小时的代码,一周开发完成一个需求,这个是否准确呢?我们出了这样一个指标,就是每百行代码工作量,即编写完成100行代码需要多长时间,从Gitlab提交的数据和项目管理平台的报工数据算出来的。这个指标还不是很准确,还在进一步修正,因为我们不同团队之间有的产品是拖拉拽开发的,有的开发是一行行敲代码的,效率是不一样的。但我们认为这个指标是有意义的,我们要经过一定阶段的调整和细化,总结出来更精准、更合适的模型。

第三部分就是我们的成果,这里简单给大家介绍一下。其实我们当时从5月份新系统全面上线以后,开始启动研发效能提升的规划,6月份启动了自动化测试和自动化部署项目,9月份自己开始做工具的选型,到12月份决定正式参评,到3月份过评,大概是这样一个步骤。过评以后,我们能够看到一些显著的提升点,一是配置管理工具的转型,去年9月份开始我们核心项目,到今年领导说所有项目要往Gitlab迁移,我们现在迁移已经完成了60%的系统,过程中每周都是一到两场培训,会有专门的配置管理人员驻扎到各个办公室,指导大家怎么使用这个工具。另外我们会建立标准的流水线作业,还有测试分层策略,后面可以看到,我们在推广过程中,会把这些规则进一步细化,希望能够给大家一些参考。最后自动化部署,之前其实已经做了很多系统,在评级的过程中,评级的细则给了我们一些引导,我们加了一些配置项的检查,比如说我们部署过程的时候,一些SQL中包含Drop、Truncate关键字,我们认为这些是危险操作,会弹出告警人工确认,另外有一些基础的业务参数表,平时不会改动的,但是如果检测到SQL语句中包含这些表的名字我们也要人工确认。还有打通上线流程,这是我们研发最喜欢的事情,因为之前上线流程审批很麻烦,要先找业务部门的需求提交人签字,然后找业务部门的负责人签字,再找开发的领导签字,再找运维领导签字,有时候需求做完了,签不了字就上不了线。做完上线流程线上化,我们的开发同事坐在工位上点点就可以完成上线工作的审批了。最后说到度量指标,我们是有专门的团队一直在做,我们评估结束以后还是在不停调整度量指标,后面可以看一下具体的示例。

最后说一下推广的思路,我们把工作做了划分,推广时候要做的几件事,第一是我自己的团队,我肯定要做项目组的选择,我们会出一个基础的框架调研,然后根据这些调研信息来选择我下一个要改造的项目。这里不是说有的项目改造,有的不改造,我们会选择更具代表性的项目先去改造。另外会做一些平台升级,升级内容源于我们调研的内容。还会有质量团队的分工,比如说像我们代码扫描的规则制定,因为每个项目他的技术栈是不一样的,比如说我们有一个项目,种种原因JDK还是1.6版本的,但有的项目已经是1.8版本了,这两个项目在扫描规则上就会有些不一样。还有环境管理团队,我们大家可以看到,还会有一些远期的版本,可能没有环境测试或者说可能要等一段时间再测试,我们是怎么解决的,包括自动化测试团队,他们如何更好的做。最后我们要识别出来,开发团队在持续交付过程中要做什么工作,首先要做工具迁移,其次我们会要求MAVEN改造,有很多项目由于历史原因是用的其他编译工具,一定要强调用MAVEN,这样管理制品的时候才会更方便一些,我们会强制要求进行MAVNE的编译改造,还有单元测试案例的编写。开发人员之前可能没有接触到单元测试,这个是需要学习,并花很多精力去写的一件事情,一定要提前说清楚。这块儿是我们持续交付平台做的比较大的改造,可以看到我们做第一个系统持续交付的时候,它的Jenkins相关的文件有这么多,我们发现推广的时候,每个项目都要建这样的项目,改配置,我改一个基础脚本所有的库都要同步,很麻烦。在jenkins2我们看到了这个共享库的概念,把流水线各个步骤的基础脚本和有关流水线的配置拆开,配置也拆了两部分,一部分关于技术平台的配置,比如项目管理平台、Gitlab、SonarQube等平台的配置,开发可以忽略的。还有一部分就是开发需要自己配的配置,比如你都要什么流水线,都要什么步骤,我们把这个基础步骤和配置都做了分离,分离以后就可以看到新建一个流水线,会给他一个模板化的JenkinsFile文件及配置文件,这个就是我们的一个样例。比如说我想要这个步骤,我把这一段配置加上,不想要就删掉,它就没有了。这样改了以后,我们很轻松可以把部署的配流水线的能力开放出去,流水线模板是固定的,只要知道配置文件怎么写就可以自己完成流水线的配置。

另外就是我们在推广过程中,我们发现很多项目虽然用MAVNE编译,但是非常不规范,比如说这个版本依赖很不清晰,我们发现有部分项目的版本号永远是不变的,永远是1.0.0,这样编译的时候依赖的版本可能都是错误的。我们第一步做的就是编译依赖的管理,比如说我们总结出来的规则,像单体应用,建议他写父POM,把公共依赖及各子模块的版本管理起来,而且单体应用一定是全量编译的,保证所有子模块的版本号都是一致,保证它的依赖一直是最新的。对微服务的依赖管理,我也问过很多人,有的公司可能就是有专门的人来管理,比如说A服务依赖B服务的什么版本,在统一的地方发布,有的是靠开发自己写的,写对写错开发自己负责。我们做了这种,我们要求微服务不管有没有变动,版本号都要递增一位,比如说我是7月5号的上线窗口,对应的版本号是1.21.0,所有的改动都会有一个1.21.0版本的部署包,如果这个服务不改动的话我们也会自动编译一个包,服务之间的调用只能调用上线窗口的目标版本,保证依赖不会乱。因为外包人员流动性比较大,新来的人可能根本没有做过MAVNE,不懂怎么写一个正确的POM文件,培训还需要花很多时间成本,所以只能采取现在这样折中的办法。另外就是我们JDK版本的规范,刚才说了我们有的系统编译是1.6,有的已经升到1.9了,但MAVNE某些版本只支持JDK1.7,不支持1.6。我们可以做不同的Jenkins Slave镜像,匹配不同的JDK版本、MAVEN版本、插件版本等等,但是感谢我们领导的支持,领导发话只要是JDK1.7以下的版本,全部升级。这样做会有一定成本,但长远来看是好的,毕竟太旧的版本官方都已经不维护了。

另外我们对环境使用现状做一些调研,发现我们目前的环境策略能覆盖90%多的测试场景,剩余的场景分紧急版本、远期窗口版本和常规项目版本,排序以后我们发现最需要的环境是紧急版本和常规项目版本,紧急版本我们发现有五个系统,它的紧急版本占了50%紧急项目的版本需求,所以我们紧急版本的环境就建这五个系统,已经能解决很多问题了。其他的系统可能会临时的人为指定它的环境使用的策略,或者对测试策略稍作调整,总之都是有办法解决的。我们环境管理未来的发展方向,就是向容器平台迁移,我们希望做到每个项目都有自己独立的环境,对应唯一的版本,每个需求都有自己的唯一的环境,对应唯一的版本。目前我们也在尝试,我们做了部分系统的基础镜像,应用到自动化测试环境,先跑起来。但这些事情也是有成本的,上了容器以后,容器平台、云原生平台的规模更庞大,它涉及的工具链更多、更丰富,运维也是很大的成本,所以我们也不要一味的追求上容器,一定要考虑清楚这个问题。

最后这个是我们的测试管理发展方向,从下而上是我们近期和远期想做的事情,近期就是场景规划,单元测试在编译后执行,验证程序正确性,接口是冒烟测试和新功能的案例,这些都是在完成功能开发后进行的。还有接口冒烟测试是每次部署版本以后都会运行,是用来验证环境的。另外接口全量回归测试和UI自动化测试,在进入UAT测试后夜间全量执行,我们的UI测试还打算放到一部分生产上运行。再后面要做的就是平台整合,现在有开源工具可以把接口、UI、包括APP的自动化案例调度起来执行,但是没有做到统一的管理,我们的目标就是做到统一管理,案例关联到需求,这样可以统计需求的覆盖度。再说我们的mock发展,随着外围系统测试越来越多,不可能搭一个很大的环境来满足测试需求,我们如果把这个环境全部搭起来的话,可能就是上百套系统,需要的硬件资源及运维成本也是很庞大,这个时候我们会多做一些mock,针对我们要测的系统做专门的接口测试,其他系统通过挡板模拟。再进一步就是覆盖率的获取,一方面是测试迁移,把一部分接口测试转移到单测框架里,利用单元测试框架统计覆盖率。如果是纯接口或者功能测试,可能会采取精准测试的方案,来检查覆盖率进而提高覆盖率。最后我们最想做的事就是让开发写单元测试,并且范围扩展到接口级别,不仅是底层的方法或函数,一直到最顶层的都写。其实目前来看精准测试的结果也是需要开发分析,写同样的案例也许初级开发人员就可以完成,也许比用自动化测试人员的成本更低,所以为什么不直接让开发做呢,开发明明有能力做这件事情。所以我们希望我们测试可以前移,让开发人员做更全面的测试。但这件事情需要很多人的观念做一个转变,所以我们把他放到最后去推进。如果这件事做的足够好,那么开发就可以完成单元测试及接口测试,虽然自动化测试在我的团队,我个人也愿意把自动化测试团队砍掉。

我的分享就这么多,谢谢大家。

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: