包阅导读总结
1. 环境分支、环境流水线、DevOps、反模式、持续集成
2. 本文介绍了 DevOps 中的反模式——环境分支和环境流水线,指出其存在导致生产事故的风险,无法做到持续集成,替代模式是单流水线和制品晋级,根本治理方案是摒弃环境分支。
3.
– 环境分支和环境流水线
– 常见情况:软件发布经过多个非生产环境测试,很多组织为每个环境拉分支和对应流水线。
– 问题举例:特性 XXX 和 YYY 开发测试过程中,不同环境测试的代码不同,易导致生产事故。
– 原因分析:提升测试灵活性、支持多版本。
– 替代模式
– 单流水线和制品晋级:代码推送到主干触发流水线,制品依次晋级到不同环境测试。
– 治理方案
– 摒弃环境分支,合并分支并建立公共分支的流水线。
思维导图:
文章地址:https://mp.weixin.qq.com/s/g_HnwrNFR6-M22nxcjMk7w
文章来源:mp.weixin.qq.com
作者:姚琪琳
发布时间:2024/7/16 6:47
语言:中文
总字数:3127字
预计阅读时间:13分钟
评分:89分
标签:环境分支,环境流水线,持续集成,DevOps,单流水线
以下为原文内容
本内容来源于用户推荐转载,旨在分享知识与观点,如有侵权请联系删除 联系邮箱 media@ilingban.com
在上一篇文章中,我分享了反模式系列的第一篇:特性分支。今天,我打算来介绍一下DevOps中另一个常见的反模式:环境分支和环境流水线。
在大多数研发组织中,软件要想发布到生产环境,会经过一系列非生产环境的测试。这些非生产环境一般包括:开发环境、测试环境、集成(测试)环境、验收环境、准生产环境等(不同组织可能采用不同的环境组合)。
这本没有问题,但很多组织或团队会在开发时针对每个环境拉出一条分支,比如测试分支、集成分支、验收分支、准生产分支等,开发人员拉出特性分支,从特性分支向不同的环境分支合并代码,每条环境分支会对应一条环境流水线,如测试流水线、集成流水线、验收流水线、准生产流水线等,特性分支到环境流水线的合并会触发环境流水线的构建,流水线通过后会把生成的软件包部(制品)署到相应的环境,进行手工测试。
更有甚者,甚至会给生产环境一个单独的环境分支,特性通过各个环境的测试后,再将特性分支合并到生产分支,触发生产流水线,最终将流水线制品部署到生产环境。
如下图所示:
我把这样的分支和流水线策略叫做环境分支和环境流水线。
需要注意的是,有些分支策略也包含环境分支,但特性分支并不会直接合并到这些环境分支,而是从主干或公共的开发分支上合并到环境分支,这样可以确保环境分支的代码和主干或公共分支上的代码保持一致。这样的环境分支和环境流水线是可以接受的。不过它往往也会忽略持续集成中的一个重要实践,这个我们后面再聊。
乍一看好像没什么问题。一个环境对应一个分支,当特性开发完成开始测试时,很自然地将特性分支合并到对应环境分支并开始测试,从而发挥特性分支的最大功效——不同特性彼此独立、互不影响。这下不但开发彼此独立,连测试都互不影响了。
然而实际上问题则很大。我们来举个例子。
-
特性XXX和YYY同一迭代开始开发,YYY先开发完成提测,将特性分支feature/YYY上的代码合并到了test分支,同时触发流水线并产生制品部署到test环境
-
但YYY的测试发现了bug,被打回修复了
-
特性XXX开发完成提测,将特性分支feature/XXX上的代码合并到了test分支,同时触发流水线并产生制品部署到test环境
-
XXX测试通过
-
XXX提集成环境测试,将特性分支feature/XXX上的代码合并到了integration分支,同时触发流水线并产生制品部署到integration环境
-
XXX集成测试通过
-
XXX提准生产环境测试,将特性分支feature/XXX上的代码合并到了pre-prod分支,同时触发流水线并产生制品部署到pre-prod环境
-
XXX准生产环境测试通过
-
XXX提生产,准备上线,将特性分支feature/XXX上的代码合并到了prod分支,同时触发流水线并产生制品准备部署到prod环境
XXX在test环境的测试是包含YYY的代码的(尽管feature/XXX分支上没有这些代码),XXX的代码尽管在其他环境上也测试通过,但与test环境所测的代码是不同的(不含YYY)。有可能XXX的代码存在bug,但被YYY的某一段代码恰好修复了,但feature/XXX分支上并没有这些代码,在其他环境的测试又恰好没有发现,从而导致生产事故。
你也许会说,测试没发现导致的生产事故,这就是测试的问题了,不是分支策略或流水线策略的问题。确实如此,但实际工作中,很有可能在准生产环境的测试包含其他特性代码,但其他特性测出了问题,临时决定不上线了,而XXX在准生产环境“测试通过了”,可以上线,于是就合并代码上生产了。这时的生产代码与准生产代码已经完全不一样了,但团队却认为XXX是“安全的”。这样一来产生线上事故的风险就十分高了。
我个人在第一次听说这样的实践时一度无法理解,甚至十分震惊。不同环境测试的是不同的包,这样的包怎么敢部署到生产的?
除此之外,如果你认同特性分支是一种反模式,无法做到真正持续集成,你就发现,环境分支和环境流水线也同样无法做到持续集成。它甚至不知道在跟谁集成……
团队在使用特性分支时,很自然地会为不同环境创建分支,以进一步提升特性分支在测试阶段的灵活性(特性分支本身是为了提升开发阶段的灵活性)。毕竟开发已经分开了,如果测试不能分开的话,不同特性之间就会形成等待,影响交付效率。
有了环境分支,再为每个环境分支分别创建一个流水线,以确保合并后触发构建、产生制品并初步验证制品的质量,似乎也成为了顺理成章的事。
还有一种使用环境分支的原因就是多版本。如果代码需要对外提供多个并行的版本,每个版本的迭代不能彼此影响,因此测试也需要隔离。有些团队会在不同的环境测试不同的版本,比如在验收环境测试v1.0,在测试环境测v1.2。我会在下一节讨论它的问题。
要彻底摒弃环境分支和环境流水线,你首先想到的应该就是要摒弃特性分支(手动狗头)。当然,两者并不是紧绑定的。正如上一篇文章中的例子,虽然使用了特性分支,但并没有环境分支,特性分支还是会在一条公共分支上做集成。
其实特性分支并没有原罪,只是它特别容易导致长分支或环境分支,导致无法持续集成,才成为DevOps中的反模式。
在DevOps中替代环境分支和环境流水线的模式是单流水线和制品晋级。其过程如下:
-
代码push或PR合并到主干或公共分支后,触发流水线进行集成和构建,产生制品。
-
通过流水线将这个制品部署到测试环境,开始测试。
-
测试通过后,将相同的制品部署到下一个测试环境(如集成环境)进行测试。
-
测试通过后,还是相同的制品,继续晋级到下一个测试环境(如验收环境或准生产环境)
-
如此类推,直到这个制品最终部署到生产环境。
所有的构建和部署都是在单一流水线上执行,当然部署环节可能需要手工触发。同样一个制品通过在不同环境的测试和验证,最终晋级生产环境。这样我们才能确保最终部署到生产环境的包是通过层层验证的、有质量信心的包。
前面说过,有一种环境分支是从主干或公共分支上合并的,这虽然能确保不同环境分支上的代码一致,但由于环境流水线的存在,没有引入制品晋级机制,不同流水线构建出来的包仍然有可能会产生或多或少的差异,从而带来隐患。
至于多版本问题,更是用错了解决方案。不同的测试环境是用来进行不同级别的测试,不是测试不同的版本。如果代码库要支持多版本,就应该为每个支持的版本准备一套流水线环境。
这就是我们今天要介绍的第二个反模式:环境分支和环境流水线。它的常见程度、危害程度和治理难度如下所示:
很多使用了特性分支的团队都在使用环境分支和环境流水线,即使现在没有使用,未来也很可能会使用。所以最根本的治理方案还是摒弃环境分支。
根本做不到持续集成,而且不同环境测试的都是不同的制品,这与DevOps的理念和主张背道而驰。很有可能产生生产事故。可能有些团队暂时没有产生问题,那只是还没有产生而已。或者产生了问题,但把责任归结于开发人员,而没有意识到这是团队的问题。
相对于特性分支来说要好治理一些。只要把多个环境分支合并成一个公共分支,并且只对这一条公共分支建立流水线即可。你甚至可以仍然使用特性分支。