您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
关于两种CI/CD策略以及git分支模型的思考
 
来源:dockone.io 发布于 2017-1-22
   次浏览      
 

借这个周末闲适的下午和明媚的阳光,决定把近来项目上的 CI/CD(持续集成/持续交付)策略 以及 git分支模型 和以前的项目做一下分析比较,希望对各位有所帮助,也能有所思考,尤其是那些期望 搭建项目部署流水线 或者想 了解git分支模型 的开发、运维人员。

背景

废话不多说,由于近期做了N次release,所以对自己目前所处的新项目的部署方式有了一定的了解。为了方便,本文就叫该项目为A项目吧。发现A项目的部署方式和我之前接触的TW“传统”CI/CD策略差异比较大(在 TW ,几乎每个项目都有持续集成/持续交付流水线,如果你对它们的概念还不是很清楚,建议阅读 持续交付 这本书,将对你梳理整个交付流程帮助巨大)。

关于A项目的背景,受客户保密协议的限制,我只能透露几点。A项目所属公司为国外某大型电信运营商,主要内容为用户账户自服务平台。该平台涉及诸多内外部服务,如认证、订单跟踪、短信认证等等,数量总数在三十多个左右,而每个服务都是一个独立的子系统,有独立的代码库、独立的机器实例(AWS EC2 实例)用于运行,以及一套独立的jenkins job用于自动化构建和部署(即我们接下来谈的内容)。当然,这也是为什么A项目想往微服务架构迁移的主要目的。

接下来,让我剥去诸多项目的其他内容,仅仅讨论一下它的CI/CD策略,也可以说是它的构建、部署方式。

A项目的CI/CD策略

千言万语还是不及一张图(作者小学美术数学老师教的,望见谅):

上图,为一个独立子项目(如背景中所说的某个服务)在其 jenkins 里面的任务(job)结构图,主要有两种自动化任务,build和deploy:

build - 即构建任务。developer在代码仓库(这里是github上某个私有仓库)某个分支上提交了代码后,自动或者手动地被触发。它会根据对应的分支,如develop、一些feature分支或release分支上,而在其对应的任务上构建、运行各层测试以及生成对应的 AMI 镜像。

deployment - 即部署任务。该任务需要人工手动点击触发,因为很多时候需要改动一些部署配置,比如说选择刚刚build任务生成的哪个分支的那个AMI文件以及更改一些endpoint的值。它会根据你需要部署的环境,利用自动化部署工具chef,基于对应的AMI镜像生成对应的EC2实例、ELB等等资源,让我们的服务在对应的环境中正式地运行起来(当然也伴随着销毁旧的资源的过程)。这个过程如果目标环境是prod的话,其实就是真实的发布了。

这用在该项目组中几乎所有的以服务为单位的子系统之上,也就是说,我们有将近三十套左右类似这样的jenkins任务。

需要说明的是,上图中的黑色圆圈、黑色圆圈加横线和黑色空心圆圈分别代表 完全自动化 、 需要手动更改配置后点击触发 和 需要手动点击出发 三种情况,即如下图所示:

这样的方式有如下几个特点:

以分支和环境为中心 这种策略在构建时以 分支(branch) 来区分构建的产物,如果你的工作模式是在各个不同的分支上开发且测试的话,你可以基于分支的相互独立的进行对应的部署和测试。举个栗子,如果你基于feature1分支构建生成了一个AMI镜像,然后你基于该镜像部署它到qa-1环境中,然后同样的将feature2分支部署到qa-2环境中,然后测试人员就可以同时在两个环境测试不同的功能。

保持了CI/CD中的自动化 构建和部署实际上还是自动化的,不过需要在运行自动化脚本之前,手动更新一些配置,比如该使用哪个AMI镜像等。

自动化测试时间不会特别长 这里所说的特别长其实不容易定义,具体多长时间为长,都是相对而论。个人感觉,只要你觉得不用给各层测试做独立的jenkins任务(全都放在build中),仍然可以清晰的知道什么时候运行什么测试,什么测试出现了问题,即可。

环境之间的递进关系不明显 这种策略下,由于是手动选择和触发部署过程,所以一次代码更改可能不会被部署到所有环境中,可能只会被部署到某一个测试环境中用于测试。所以环境之间的递进(如下文中越来越接近产品环境的)只能体现它对应的部署任务里的一些配置参数上,比如说preprod环境的部署job用的是真实数据库,而QA环境的部署job用的是mock的数据。

B项目的策略及比较

而我曾经接触过的一些项目,同样为了便于说明,这里我们统称它为B项目,不管它的CI/CD工具用的是jenkins还是 go.cd ,它们都会是一种流水线(pipeline)的形式,如下图所示(没错,请叫我灵魂画师,<手动羞耻脸>):

如上图所示,相对A项目的策略来说,这些jenkins任务分的更加细,中间的各层测试视具体项目而言可能包含单元测试、集成测试、回归测试、集成测试等等,然后就是将其部署到Dev环境(开发人员手动测试、验证的环境)。毋庸置疑,这里从开发人员提交代码到部署至Dev环境,包括测试的运行在内,都是自动化的。这意味着如果你的代码没有问题,你不需要做任何事,除了提交代码和看一下这个pipeline的状态。之后的几个环境,由于越来越接近产品环境,而且会提供给不同的人用于测试或者演示(showcase),所以很多时候需要对应的人手动的触发对应的部署/发布。当然,这样的部署/发布过程也是自动化,所以说在发布到产品环境之前,类似的部署/发布方式其实已经被验证过很多次了,而且是一次更改必须强制性地必须经过各个环境的测试和验证。

结合《持续交付》一书中提到的部署流水线的三个目标而言,我们来比较一下A项目和B项目用的这两种部署策略优缺点:

可视化 - 让软件的构建、部署、测试和发布过程对所有人可见,这一点对于合作至关重要。A项目这种分离的任务形式,其实不够直观,也不太能够让开发人员之外的业务人员、管理人员等直观地明白我们在哪里出现了问题,任务的划分也相对简单。B项目的这种策略,任务划分相对直观明了,任何人只要关注这条流水线,就大概知道应该是什么流程出现了问题。

及时反馈 - 持续交付的最大好处其实就是及时反馈了。而这一点在A和B上都有体现,任务的成功与失败都可以给出对应的反馈,告诉我们是否哪儿出了问题。不过A相对来说,反馈方式(可视化程度)更弱一点,反馈周期(集成周期较长)更长一点。

自动化 - 很明显,从上面两个图可以看出,B的自动化程度肯定是高于A的,无论是构建还是部署,A都需要去手动更改配置和手动触发。不过两种策略中间的实现毋庸置疑都是自动化的。

如果只从上面看,其实B项目的策略理应优于A项目的策略的。但是,很显然,“没那麼简单 就能去爱 别的全不看”。还记得我们说过A项目服务众多吗,A的采用这种策略很大一部分原因,个人猜测(还未经验实),一是重视任务之间的 隔离性 ,二是为了便于 管理各个服务之间依赖 。比如,在A项目中,我想把之前feature1的某个测试环境里面的某个服务改为另外一个合适的版本,我只需要在部署时,将部署任务执行前的某个参数改为对应的endpoint就行,这在B项目策略中虽然也是可行的,但A项目的方式相当于在每次部署前都会提醒你这些参数的值,你可以决定是否修改。

当然,我个人觉得这与它们的git分支模型也不无几分关系。接下来就让我们来看看它们分别使用什么样的git分支模型。

A项目的git分支模型

A项目使用的git分支模型 - git flow

简单介绍一下的各种分支:

master - 与产品环境代码保持一致的分支,也就是每次发布完成之后发布的功能分支就要合并于此,以保持master更新。

develop - 开发的主分支,feature和release分支会基于此分支。

feature - 具体要开发的功能的分支,完成后合并到develop。

release - 用于发布新版本的分支,完成后合并到develop和master。

hotfix - 用于紧急修复已发布的产品问题的分支,完成后合并到develop和master。

这种模型的话,理论上来说相对安全。但是一般feature分支都是需要用于开发一个较大的功能才做的分支,在此之上,我们还要建对应的故事卡(敏捷中,一个不可/不宜划分的需求单位)的分支,如下所示:

这么做的好处有:

隔离性比较好,更加安全 所有的功能都会有对应的分支,开发和测试工作不会互相干扰,发布进程也不会受其他未开发完的功能干扰。

分支职责明确 对应的分支做对应的事情,职责明确。

但是缺点也比较明显:

集成的周期太长 如果同时有几个大的功能在各自的分支上开发,每个功能的开发周期都不短的话,那之后他们之间的合并、集成工作将会十分痛苦。如果以《持续集成》这一本书中观点来看,这甚至算不上持续集成。

会有比较多的重复测试 完成分支的测试之后,在集成到主分支之后,还要重复一遍测试。自动化测试重复还可以接受,重复地手动的测试就比较烦人了。

结构相对复杂 分支较多,且存在层级关系(比如故事卡分支出自feature分支,feature分支出自develop分支)。

B项目的git分支模型

对应地,B项目,存在分支的话(我这么说,是因为也有不使用分支的真实项目),以我之前的某个离岸海外项目为例,会像如下图所示:

明显地,这种结构(其实也有种说法是github flow)看起来简单很多。所有分支都是基于develop或者叫master这样的主分支。基于故事卡建分支,合并分支。

这么做有如下好处:

结构相对简单 所有分支的都是以故事卡为单位,结构简单。全部围绕一条主分支。

符合小步提交、持续集成思想 以一张故事卡为集成的最小单位,相对来说集成的周期短,反馈的速度也快,能够及早的遇到问题,从而及早的解决问题。

但是,金无足赤,它有时候也可能会有一些缺点:

feature toggle的引入与测试 这种模型下,为了不让某些没有完成的功能影响已经完成的功能发布进程。在软件的设计初级以及后期测试,都需要把对应的feature toggle加入进来。也就是说,需要确保在各个环境中那些没有完成的功能应该处于disable状态。这无疑增加一部分工作量,也会带来一点风险。不过,这种工作量和风险大部分团队都会承担,毕竟如果计划分析的合理,发生的几率还是挺小的。

隔离性较差 引入feature toggle的很大一部分原因就是为了弥补隔离性上的缺陷。但是如果你主张:所有的分支终究是要合并到一个分支、发布成一个产品的,那这一缺点其实并不重要。

总结

当然,还有很多其他的策略和分支模型(或者没有分支的模型),我这里不再探讨过多。其实就我目前提到的AB两种,甚至可以交叉使用(比如A项目情况用B项目的策略),具体如何采用以及何时适合采用,这个问题可以留给有心的读者自己 思考 。

最后我想说,这几种方式虽然各有优缺点,但相比更加传统的缺乏自动化的方式而言,已然进步太多。

   
次浏览       
相关文章

每日构建解决方案
如何制定有效的配置管理流程
配置管理主要活动及实现方法
构建管理入门
相关文档

配置管理流程
配置管理白皮书
CM09_C配置管理标准
使用SVN进行版本控制
相关课程

配置管理实践
配置管理方法、工具与应用
多层次集成配置管理
产品发布管理
最新活动计划
LLM大模型应用与项目构建 12-26[特惠]
QT应用开发 11-21[线上]
C++高级编程 11-27[北京]
业务建模&领域驱动设计 11-15[北京]
用户研究与用户建模 11-21[北京]
SysML和EA进行系统设计建模 11-28[北京]

软件配置管理的问题、目的
软件配置管理规范
CQWeb 7.1性能测试与调优指南
为什么需要使用ClearCase
ClearCase与RTC的集成
利用ClearQuest 进行测试管理
更多...   

产品发布管理
配置管理方法、实践、工具
多层次集成配置管理
使用CC与CQ进行项目实践
CVS与配置管理
Subversion管理员

配置管理实践(从组织级到项目级)
通号院 配置管理规范与应用
配置管理日构建及持续集成
丹佛斯 ClearCase与配置管理
中国移动 软件配置管理
中国银行 软件配置管理
天津华翼蓝天科技 配置管理与Pvcs