本文讲的是谈谈企业的持续交付流水线设计,有一天,业务人员急冲冲的跑过来,对你说生产上出现了一个严重BUG,必须要尽快修复。你听完问题描述后,胸有成竹坐定并迅速定位问题,随后改动了一行代码并提交,系统开始自动编译、各个环境自动化测试、发布上线。几分钟后,生产环境上该BUG已经被修复掉。
上面所提到的场景,这是不是很美妙?但是想必不少读者要忍不住要吐槽了,这太不实际了:新功能上线测试不要时间么?新增了功能肯定要做回归测试,这都需要一定的时间。况且怎么可以随便部署上线?还得通过预发演练、走发布审批流程。其实这些过程大家也都清楚,那么不妨从另一个角度思考下,是否可以把这个过程中所有需要人工线下操作的环节都通过一个平台自动化实现掉呢?
这些其实都是本文要为大家一一解读的,事实上上述的例子虽然有些理想化,但是却可以作为一个终极目标,并非没有实现的可能。
本文目录:
一、什么是持续交付?
二、设计持续交付四大关键要素
三、落地持续交付五大注意事项
四、总结
一、什么是持续交付?
首先来了解下持续交付的概念,在*中持续交付的定义如下:
持续交付(Continuous delivery,缩写为 CD),是一种软件工程方法,让软件产品的产出过程在一个短周期内完成,以保证软件可以稳定、持续的保持在随时可以发布的状况。它的目标在于让软件的编译、测试与发布变得更快更频繁。这种方式可以减少软件开发的成本与时间,减少风险。
好吧,看定义总是很抽象的,我们从两个维度来理解持续交付,一个是范围,一个是宗旨。
先说说范围,软件研发的生命周期大家想必都很了解,大致包括如下几个阶段,需求、设计、构建(包括开发、编译)、测试(系统集成测试、用户验收测试、非功能性测试)、发布上线。
持续集成覆盖构建、测试两个阶段,关注于代码的提交、编译、测试。持续部署意在保障每一个代码提交,都能自动化的部署到生产环境上;持续交付和持续部署有些类似,而是保障从原始需求到最终交付上线全过程的稳定可靠,但是不强求自动化部署到生产环境上,在最终发布上线时,可以人工介入,也可以自动部署。
再看看持续交付的宗旨,持续交付的核心宗旨是:保证每次提交代码都产生一个可发布的版本。下图是持续交付的一个核心流程图,代码提交触发构建和单元测试,完成后触发自动化测试,根据自动化测试的结果进行审批是否进行用户验收测试,用户验收测试通过后进行发布上线。中间每一个环节都会产生反馈,一旦失败就终止当前交付流程。
通过这范围和宗旨两方面,是否已经有些了解持续交付是什么了呢?还是有些泛?不急,接下来我们针对持续交付的整个流程进行拆分。
从代码提交开始,我们可以把整个持续交付归纳出四个关键要素:持续集成、自动化测试、自动化部署、流水线。
二、设计持续交付四大关键要素
持续集成
在传统瀑布开发模式下,通常很长一段时间内,代码都是不稳定且不可用的;待到功能开发完毕了,才会进入集成阶段,这时问题出现了:团队规模越大,要开发的需求越多,这个周期就越长,集成阶段花费的代价也就越大,项目风险也越大,项目的进度极不可控。
而在敏捷过程中,将代码开发和集成按模块拆分成多个小阶段,每一阶段完成后都会进行集成,这在一定程度上减少了风险。
持续集成要求代码的开发和功能集成并行进行,相辅相成,要求至少做到每日编译甚至代码提交即触发编译。构建时会对整个应用的所有模块进行编译,并伴随单元测试以及代码质量分析等动作。如果编译失败了或者单元测试失败了,那么必须要立即修复问题,直到构建成功。总之,要求代码库的代码持续处于可用状态。
持续集成的时间一定要尽可能的短,尤其是代码提交触发构建的场景下。否则试想:一支20余人的开发团队,每次构建(编译+单元测试+代码质量分析)需要花费20多分钟;而每次代码提交时触发构建,会产生大量的编译任务排队,并且会不停增加;编译发生问题时较难定位,因为在上次开始编译到这次编译中间,会有多人提交,很难快速确认是由谁的提交导致的编译失败。
持续集成的时间通常建议在5分钟以内,90秒内完成是极好的。因此对于代码的编译、单元测试都一定要注意时间。在分布式场景下,应用可能会依赖于很多外部应用或者中间件,单元测试不一定非要连通真实环境,会带来请求响应时间的损耗,并且一般也要求单元测试可以在离线环境下可执行,所以可以采用Mock的方式,提升单元测试速度。同样,由于要控制每次构建的时间,不建议在持续集成流程中去做集成测试(SIT),这个可以交给集测流水线去处理,由测试人员在集成测试环节继续跟进。
持续集成保证了代码始终是可用的,编译正确并且通过所有单元测试。这是持续交付流水线的第一步。
自动化测试
在整个软件过程中,测试可以分为两类:功能测试(冒烟测试、系统集成测试(SIT)、用户验收测试(UAT))、非功能性测试(压力测试、稳定性测试、安全测试)等。非功能性测试姑且不论,功能性测试如系统集成测试、用户验收测试等都需要尽可能地覆盖所有的功能模块,功能越是复杂的应用系统,测试起来的工作量也越大。
虽然自动化测试的理念已经普及了好多年,但是大部分企业内部,还是以手工测试为主,甚至大部分企业,对手工测试的投入也都是不足的。原因有很多,比如人员缺乏和时间周期紧张,来不及写自动化测试脚本,或者测试人员的水平不足等。这些确实都是客观存在的原因,但是这样真的是节省了成本吗?事实上对于持续发展的产品而言,每次发布时都需要大量的人力投入去进行测试,会有大量重复的测试工作,发布的次数越多,成本越高,某种程度上这甚至限制了快速频繁发布的能力,由于人力资源的限制,很多企业回归测试时,只能相信开发人员对于功能调整影响范围的预估,缩小回归测试的范围,为线上运行带来了极大的风险。在《持续交付》一书中看到这样一个数字:某组织每次发布软件是花费在手工测试上的钱就有300万美元。自动化测试带来的价值也绝对值得上现在的投入。
想要实现整个持续交付流水线的自动化,实现本文一开始的那个例子,全面的自动化测试不可或缺。只需要花费几分钟至几十分钟,通过了各个环境的自动化测试,便相当于对质量打上了合格标签。可以选择直接部署到生产环境上,或者等待晚上某个时间点进行上线部署。
交付流水线
持续交付是一个大流程,从代码提交一直到部署上线,但是我们在实践过程中发现,这种大流程,未免太大太笨重。在企业真实的情况下,大流程本身没问题,但是其中的环节往往没有这么简单,想要让这个流水线真正能被企业实际使用,还要对大流程进行拆分。我们在实践中把持续交付流水线拆分成三个子流水线:开发流水线、集测流水线、发布流水线。
开发流水线:
面向开发人员和开发环境。开发人员提交代码,触发构建,部署到开发环境中由开发人员进行自测。这个流水线在开发的过程中会频繁进行。
集测流水线:
面向测试人员,同样以构建为开始,基于构建的产物(部署介质),部署到集成测试环境,进行系统集成测试。
发布流水线:
当次发布的所有需求全部通过系统集成测试后,便可以进入后续测试如用户验收测试、非功能性测试等,通过后,则认为已经达到发布上线标准,触发上线申请审批流程,审批通过可以进行自动化发布上线。
在项目中,开发流水线的触发频率最高,集测流水线其次,发布流水线触发的频率最低。
将整个的持续交付流水线拆分为三个子流水线,可以做到面向不同的角色,这样更灵活也更便于使用。当然,不同企业的流程也是有着区别的,不一定严格按照这三个流水线。即使定义成这三个流水线,每个流水线的流程和环节也是不同的,可以结合自己企业的实际流程来拆分。
三、落地持续交付五大注意事项
上面说了很多理论,理论终究要落地实践,流程和关键环节也已经比较清楚了,但是在实际落地时还是会有很多问题和细节点需要注意。先思考下几个问题:
如何快速支持流程使用过程中的一些微调(如环节的配置字段属性等)?
如何做到流程手工和自动执行的自定义?
如何让每个环境部署的介质对应的是哪次代码提交、哪个交付物有迹可循?
如何直观的查看交付流程目前到了哪个环节、每个环节的状态是什么样的?
如何以环境为视角,看到该环境下正在运行哪些应用?
带着上面几个问题,我们在实践的过程中,梳理出如下几个持续交付能力落地的关键点:
安全
交付流水线的核心是驱动开发、测试、运维、质量等多个部门和角色进行协作,涉及众多的角色和功能、又囊括了各个环境的部署运维操作,安全问题自然不容忽视。
明确责任人:流程中每个环节都要有责任人,在人工执行时,只有该责任人才能执行该环节,同时每个环节执行信息都要有详细的记录和展现,如:操作人、开始时间、结束时间、自动化执行时间等。
环境类型授权:而由于自动化部署的支撑,对于每个环境的部署都可以通过平台一键执行。开发、测试环境尚还好,但是对于预发、生产环境的部署,一般要由运维人员来操作。对于环境类型的细分授权,在人工执行的时候,会更加安全。
发布审批流程:事实上,在企业内部,正常发布上线通常需要经历应用发布审批流程,在生产部署前,根据发布的类型(如正常发布、紧急发布)等来触发不同的上线审批流程,完成上线审批后,才可以执行部署上线的动作。具体的流程可以结合企业内部实际的流程。
流程支持环节、属性自定义
理论上说,一个企业的持续交付流程应该是一致并且基本稳定的,但实际上大部分企业内部不止一套流程,不同部门、不同项目组的过程体系甚至都可能是不同的,姑且不论这种情况的对与错,在尚未统一流程和过程前,这种情况总归是要考虑支持的。即使统一了流程,随着企业的不断发展,流程的一些细节也会持续变化,如一些环节的属性配置等。所以对于流程的环境、属性自定义、可动态扩展等能力在设计时是要重点关注的。
保持部署介质不变,便于追溯
很多企业由于规范的不标准,经常会出现最终上线使用的部署介质和系统集成测试、用户验收测试的部署介质有所不同。比如在用户验收测试阶段,发现了一个问题,有可能开发人员改动后直接打一个包进行部署上线,不再通过系统集成测试,或者通过人为的判断改动影响范围,进行小范围测试。这些都带来了很大的生产隐患。
从标准来说,从系统集成测试开始,后面所有环境应该用的都是同一个介质。在系统集成测试的一开始,进行代码构建,得到部署介质。该介质地址在整个流水线上下文中进行传递,后面每个环境的部署都采用该介质。如果把集测流水线和发布流水线分离开,发布流水线必须要关联一个集成测试流水线,在发布流水线中的环境部署,采用集测流水线中的介质,依旧维持介质一致。如果发现问题需要进行修复,必须要从集测流水线重新开始。对于介质可以使用nexus等介质仓库进行统一管理。
直观的协作看板
一个流水线有多个角色协作参与,从实际参与者视角出发也好、管理者视角出发也罢,都需要一个直观的看板,来整体查看每个应用当前的交付进度,当前处于哪个环节(系统集成测试、用户验收测试环境、预发、生产),以及成功和失败情况。我们提供了两种看板:发布看板、环境看板。发布看板基于产品、微服务的角度,查看每个产品版本在不同环境上的部署情况。体现产品版本、产品修订版本、产品发布版本、产品的微服务及其版本。
环境看板则是从环境的维度,查看每个环境下有哪些应用的哪些版本部署了。如下图所示:
不要一味的自动化,自动和人工要结合
回过头来看,文章开篇的例子并非不可达成,但是要求很高,需要成熟的持续集成体系、完整覆盖的的自动化测试交付,全面的自动化部署能力的支撑,想达到这一步,自然不是一时之功就可以的。在建设的过程中,是少不了人工介入流水线中具体环节的,尤其是测试环节。所以在流水线的设计时,要充分考虑人工执行和自动执行的自定义,如果自动执行失败的话,也要提供人工介入的入口,允许人工选择重新执行、终止流程等动作。
以这些为基础准则,我们底层基于了普元的BPS流程引擎,支撑流程的自定义和扩展。并且,针对于每个环节,都可以配置前置后置事件、人工执行还是自动执行,责任人等。整个流水线从构建开始,以代码的buildNumber贯穿全流程。便于问题、进度的追溯。效果图如下:
四、总结
最后再回头看看开篇的例子,在建设企业的持续交付流水线时,能做到全自动化固然很好,但并非是要立刻实现全自动化的效果,这也不现实。初期首先是结合企业的标准流程和规范,将企业的持续交付流水线打通。可以自动化的环节尽量做到自动化,尚且做不到自动化的就人工介入。
毕竟持续交付的价值绝不仅仅是快,对于大多数企业而言,在提升软件交付效率之外,统一企业的软件交付流程和规范、保证软件交付质量、降低软件发布风险,这才是最重要的。
原文发布时间为: 2017-07-25
本文作者:王海龙
本文来自云栖社区合作伙伴EAWorld,了解相关信息可以关注EAWorld。