持续交付技术2:全功能CI/CD流水线的搭建

文摘   2024-07-20 11:35   中国香港  

持续集成和持续部署成为现代 DevOps 趋势下的重要环节,很多角色岗位都要求 CI/CD 的相关技能。本文我们将介绍什么是 CI/CD 流水线,以及它是如何搭建的,CI/CD 流水线工具怎么选型。

一、什么是 CI/CD 流水线


CI 代表持续集成(Continuous Integration),CD 代表持续交付(Continuous Delivery)和持续部署(Continuous Deployment)。也可以将它们看作是类似于软件开发生命周期的过程。

现在我们来看一下它是如何工作的。

流水线的阶段

如上图所示,该流水线展示了一个软件在其最终交付给客户或者投入上线之前,它在其生命周期内各个阶段中的移动过程。

接下来我们具体看一下该 CI/CD 流水线。假如我们要构建一款 Web 应用程序,并将它部署在一个现场 Web 服务器上。同时我们有一组开发人员,他们主要负责编写代码,并将代码构建为 Web 应用程序。假设现在开发团队已经将代码提交到版本控制系统(如:Git,SVN)中了。

1、构建阶段

接下来,代码将会经历构建阶段,这也是 CI/CD 流水线的第一阶段。在此之前,开发者已经将他们的代码加上合适的标签,并提交到版本控制系统中了。

假如我们采用的是 Java 语言,那么还需要先进行代码编译。因此,代码在通过版本控制阶段之后,会先在构建阶段予以编译。该阶段会从代码库的各个分支中获取到所有的功能代码,合并后最终通过一个编译器来编译它们。这整个过程都被称为「构建阶段」。

2、测试阶段

构建阶段结束后,将会继续进入到代码的「测试阶段」。在这个阶段中,我们会进行各种各样的测试,单元测试就是其中之一。在该阶段中,我们会测试代码中多个组件间的关系或者单个组件的功能,同时也会进行软件的可用性测试。

3、部署阶段

测试阶段完成后,就要进入「部署阶段」了。在该阶段,代码将会被部署到准生产环境服务器(staging server)或者测试环境服务器(test server)中。同时在该阶段中,我们既可以查看程序代码,也可以在模拟器中运行该应用程序。

4、自动测试阶段

只要我们的代码部署成功,我们就可以运行另一组可用性测试了。该阶段结束后,如果所有的测试都通过了,那么就可以将其部署到生产环境中了。

5、部署到生产环境

另外值得一提的是我们可能在每一个阶段的执行过程中遇到一些错误。在这种情况下,我们可以将错误邮件发回到开发团队中,以便他们能够及时修复这些错误。当开发团队修复完成后,就可以将代码重新提交到版本控制系统中,然后再次从头开始执行该流水线。

如果在执行测试的过程中遇到了任何错误,那么这些错误也将反馈给开发团队,等他们修复完成后,同样会再次触发该流水线,进行新一轮的持续迭代。

6、度量和验证阶段

因此,整个生命周期将会继续迭代下去,直到我们得到可以直接部署到生产环境中的代码或者产品。除此之外,在生产环境中我们还需要对代码进行度量和验证,以实时监控应用的线上运行状态。

到目前为止,我们已经了解了 CI/CD 流水线及其工作原理。

流水线的分层

由于产品本身的形态不同,负责研发的团队人员组成不同,代码的版本管理分支策略不同,使用的部署流水线形式也会各不相同,所以基于实际业务场景设计流水线是团队工程实践成熟的重要标志。

1. 提交构建流水线(个人级)

适用场景:每名研发工程师都创建了自己专属的流水线(一般对应个人的开发分支),用于个人在未推送代码到团队仓库之前的快速质量反馈。

注意:个人流水线并不会部署到 团队共同拥有的环境中,而是仅覆盖个人开发环节。如图所示,虚线步骤非必选

2. 集成验收流水线(团队级)

适用场景:每个团队都根据代码仓库(master/release/trunk)分支,创建产品专属的流水线,部署到 团队共同拥有的环境中e.g. dev)。

注意:如图所示,虚线步骤非必选,根据情况可通过 启动参数true/flase 跳过执行,自动化测试仅限于保证基本功能的用例。

3. 部署测试流水线(团队级)

适用场景:每个团队的测试工程师都需要专门针对提测版本的自动化部署/测试流水线,部署到团队共同拥有的环境中(e.g. test).

注意:如图所示,该条流水线的起点不是代码,而是提测的特定版本安装包;虚线步骤非必选,根据情况可通过 启动参数true/flase 跳过执行 或 裁剪。

4. 多组件集成流水线

适用场景:如果一个产品由多个组件构建而成,每个组件均有独自的代码仓库,并且每个组件由一个单独的团队负责开发与维护,那么,整个产品 的部署流水线的设计通常如下图所示。集成部署流水线的集成打包阶段将自动从企业软件包库中获取每个组件最近成功的软件包,对其进行产品集成打包

5. 单功能流水线

适用场景:适用于和代码变更无关的场景,不存在上面步骤复杂的编排 (也可通过上述流水线的 启动参数进行条件控制,跳过一些步骤)

  • 针对某个环境的漏洞扫描

  • 针对某个已部署环境的自动化测试

  • 定时清理任务

  • ...

6. 全功能(持续交付)流水线

适用场景:需求、代码构建、测试、部署环境内嵌自动化能力,每次提交都触发完整流水线,中间通过人工审批层次卡点,从dev环境,test环境,stage环境一直到 prod环境。常适用于快速发布的 PASS/SASS服务,对团队各项能力和流程制度要求较高,支持快速发布(策略)和快速回滚(策略)

流水线运转全景图

团队研发工程师每人每天都会提交一次。因此,流水线每天都会启动多次。当然并不是每次提交的变更都会走到最后的“上传发布” 。也不是每次提交都会走到UAT 部署,因为开发人员并不是完成一个功能需求后才提交代码,而是只要做完一个开发任务,就可以提交。每个功能可能由 多个开发任务组成,研发工程师需要确保即使提交了功能尚未开发完成的代码,也不会影响已开发完成的那些功能。

制品经过一个个质量卡点,经历各种门禁验证,最终交付给客户 可以工作的软件

二、CI/CD流水线的设计原则和策略


流水线的设计原则

每个组织都试图在建立 CI/CD 流水线时引入自己的方法,最终找到完美的平衡,我们通常将其称为“最佳实践”,下面总结了一些有效且安全的 CI/CD 流水线的基本原则。

1、流水线变量/命名的规范化

哪些是构建/部署需要变化的,比如构建参数,代码地址,分支名称,安装版本,部署机器IP等,控制变化的,保证任务的可复制性,不要写很多hardcode进去

标准化的命名,有助于快速复制;有意义的流水线命名,有助于团队新成员快速了解

2、流水线应当实现快速反馈

尽可能把不稳定的,耗时短的步骤放在流水线的最前面,如果把一个稳定的步骤放在前面,并且耗时几十分钟,后面的某个步骤挂了,反馈周期就会变长

例如,软件安装包的安装测试虽然运行速度比单元测试速度慢,但其反馈更加真实有价值,也应该放到流水线的前面阶段来执行,以免所有的单元测试都通过以后才发现软件无法部署启动。

3、一次构建,多次部署

如果该部署流水线实例触发了下游流水线,并且下游流水线也使用该制品,那么,部署流水线工具应该确保它来自上游部署流水线的同一个实例。只有这样,我们对该制品的质量信心才能随着部署流水线的前进而增加。

一次构建,多次部署(多套环境配置+多套构建版本标签);杜绝相同代码重复打包

相似技术栈/产品形态具备共性,通过以上原则可以抽取复用脚本,良好的设计有助于后续的可维护性!

4、步骤标准化/原子化

比如docker build/push, helm build/deploy, Maven构建等动作标准化,避免重复性写各种脚本逻辑根据业务场景组装,例如.:提测场景,每日构建场景,回归测试场景

构建操作:构建我们通常采用Maven进行自动化构建,构建完成输出一个或多个Jar包或War包。

打包镜像操作:实际上即基于构建完成的部署包来生成镜像。该操作一般首先基于一个基础镜像文件基础上进行,在基础镜像文件上拷贝和写入具体的部署包文件,同时在启动相应的初始化脚本。

部署操作:部署操作相当更加简单,重点就是将镜像部署到哪个资源池,哪个集群节点,初始化的节点配置等。具体部署哪个镜像不要指定,而是由上游任务节点输入。

5、与业务逻辑松耦合

部署流水线工具应该与具体的部署构建业务相分离。我们不应该为了方便实现自动化,而将软件代码的构建和部署过程与所选择的部署流水线工具紧耦合,例如将一些软件部署时所用的脚本或所需信息由部署流水线平台保存。相反,我们应该提供单独的脚本,并将其放入该产品的代码仓库中。这样就可以轻松对这些脚本的修改进行跟踪和审核。

也就是说,仅仅将部署流水线平台工具视为任务的调度者、执行者和记录者,它只需要知道部署流水线中各种任务触发与调度流程,而不必知道我们如何构建和部署软件。

6、保障环境一致性:在独立环境中构建和运行,预发布环境和生产环境等价

在独立环境中构建和运行,这可以确保我们的测试结果更加准确我们可以使用 Docker 或其他任何容器化工具来运行我们的测试套件,也可以在 Docker 容器中为我们的应用程序安装其他依赖。这样,我们可以确保测试在完全隔离的环境中运行,并且不受底层主机的任何影响。由于我们的 CI/CD 平台可以完全访问我们的代码仓库,因此大多数组织也习惯于在自己的云平台基础设施中部署 CI/CD 工具以确保安全。

建议始终保持预发布环境和生产环境等价,以避免运行测试时发生意外错误导致发布暂停这种小概率事件。我们的 CI/CD 流水线首先经过运行测试和在预发布环境中部署的阶段。测试后,该应用会自动升级(或手动部署)到生产环境。使开发和测试环境完全等价于生产环境非常困难,但我们可以在需要时做出决定保持他们尽可能相似,并且了解我们正在做出的取舍。大多数组织还使用“蓝绿部署”或“金丝雀发布”的部署策略,在该策略中,我们首先在生产环境中部署应用并处理大约 1% 的流量。然后将流量提高到 100%,或者也可以较为轻松的回滚到之前的版本。

7、把工程实践落入流水线中

流水线除了任务步骤的编排,更重要的核心是最佳工程实践的体现。过去传统的思维,自动化就是写个shell/python脚本批量执行,在DevOps/微服务时代,这一招太out了,每种工程实践的背后都有需要解决的问题,通过在流水线设计中注入最佳的工程实践,可以让流水线的价值最大化,也让流水线更高级不是嘛。

  1. 版本控制  「- 解决的问题:需求和代码的关系,版本变化的跟踪」

  2. 最优的分支策略  「- 解决的问题:版本发布和团队协作,某些情况会和环境有关系」

  3. 代码静态扫描 「- 解决的问题:开发规范和安全的问题」

  4. 80%以上的单元测试覆盖率  「- 解决的问题:代码功能质量的问题,让测试左移」

  5. 漏洞(Vulnerability)扫描   「- 解决的问题:部署环境/产品安全的问题」

  6. 开源工具扫描   「- 解决的问题:解决供应链安全问题,别忘了log4j」

  7. 制品(Artifact)版本控制  「- 解决的问题:制品的版本控制,制品的晋级,某些情况下环境的回滚」

  8. 环境自动创建    「- 解决的问题:解决的是构建/部署环境一致性的问题,开发测的好好的,测试一验证怎么不行啊,容器化/云原生让这个问题更好的解决」

  9. 不可变服务器(Immutable Server )「解决的问题:可能不好理解,打个比方如果如果你的服务器挂了,或者某次配置更改了服务就起不来了,使用不可变基础设施的主要好处是部署的简单性、可靠性和一致性,服务器可以随时替换上线」

  10. 集成测试

  11. 性能测试

  12. 每次提交都触发:构建、部署和自动化测试 「- 解决的问题:快速失败,避免下游时间的浪费」

  13. 自动化变更请求 「- 解决问题:某些场景下通过状态变更触发某些动作」

  14. 零停机发布  「- 解决的问题:滚动/蓝绿/灰度发布等,用户无感知」

  15. 功能开关   「- 解决的问题:主干开发中,如果某个功能没开放完,就通过on/off某个特性来让稳定的功能上线;还有一个场景,比如某些面对消费者的广告网站,想看看自己某个功能客户是否细化,通过功能开关看看市场反馈,一般和A/B测试配合」

流水线的设计策略

1、基于场景设计流水线

「是否需要一条完整的流水线?流水线是越多越好,还是越少越好?」建议按照场景来设计,一条流水线通吃所有流程是不现实的,搞了好多流水线(比如一个构建就一个流水线,一个复制操作就一个流水线)这些都是不可取的,维护成本巨大,得不偿失。流水线按照场景分类如下:

  • 端到端自动化流水线

  • 需求、代码构建、测试、部署环境内嵌自动化能力,每次提交都触发完整流水线

  • 提交阶段流水线(个人级)、

  • 验收阶段流水线(团队级)、

  • 部署阶段流水线(部署/发布)

  • 流水线自动化触发,递次自动化(制品)晋级;

  • 流水线任务按需串行、并行、特殊场景下跳过执行

  • 必要环节人工干预, e.g. 在手工测试、正式发布等环节导入手工确认环节,流水线牵引流动

2、建立分阶段测试策略  

通过分阶段测试,您可以尽早发现重大问题并更快地获得代码库的反馈。目标是快速构建,使用单元测试等简单测试快速测试基本功能。

在此之后,您可以将构建部署到测试环境中以执行其他测试,例如一些可访问性测试、用户测试和其他可能需要更长时间执行的测试。这意味着您正在从最关键的元素开始解决许多可能的问题。

随着分阶段测试模型越来越接近生产,您需要测试越来越多的内容。这可能包括关键项目,例如回归测试,以确保以前的错误不会再次出现在您的代码库中。在这个阶段,事情出错的可能性较小。但您需要尽早有效地发现重大问题,然后缩小测试范围,以确保您交付的是高质量的应用程序。

3、纳入更多自动化测试(安全,性能,用户体验等DFX测试)

安全,性能、设备兼容性测试通常需要手动操作,而且有些团队只做了部分工作。

手动测试这些内容可能会减慢交付周期,因此许多团队要么承担成本,要么干脆不做。    

但如果这些事情对你来说很重要(而且应该如此),那么可以将一些工具包含在你的 CI/CD 管道中,以自动测试和发现任何问题。

1)安全性应始终是软件交付流程的一部分,在当今的环境中,安全性至关重要。即便如此,我还是看到许多团队和公司没有将自动化安全测试纳入其 CI/CD 流程中,而是将安全性视为 DevOps 流程完成后才会发生的事情。

好消息是:有很多工具可以帮助您轻松完成此操作 - 包括 GitHub 原生工具,如Dependabot、代码扫描、秘密扫描,如果您是 GitHub Enterprise 用户,您可以将 GitHub 提供的所有安全功能以及更多功能与GitHub Advanced Security捆绑在一起。但即使使用免费的 GitHub 帐户,您仍然可以在任何公共或私有存储库上使用 Dependabot,并且代码扫描和秘密扫描也可用于所有公共存储库。   

2)性能和设备兼容性测试   

例如,Playwright是一款可以进行端到端测试、自动化测试以及介于两者之间的所有测试的工具。您还可以使用它进行 UI 测试,以便发现产品中的问题。

3)用户体验测试 

还有另一类工具可以帮助您自动执行用户体验测试,以确保您没有在无意的情况下更改 UI。这意味着您没有引入任何意外的 UI 更改。这对于设备兼容性测试也非常有用。如果某个设备上的某些东西看起来不好,您可以快速纠正它。     

4、虽然自动化很重要,但是质量门禁更重要

部署流水线(Deployment Pipeline)是持续交付1.0中的核心模式。

它是对软件交付过程的一种可视化呈现方式,展现了从代码提交、构建、部署、测试到发布的整个过程,为团队提供状态可视化和即时反馈。

虽然部署流水线的设计因受到软件架构、分支策略、团队结构以及产品形态的影响,每个产品的部署流水线均有所不同,

但是,其都有一个共同点,就是在每个节点的出口,都有一个质量门禁。而质量门禁正是反馈的关键。如果没有高质量的门禁,则无法形成反馈环。

5、采用基础设施即代码,实现更大的灵活性   

基础设施配置是根据需要构建 IT 基础设施的实践——一些团队会在其 CI/CD 管道中采用基础设施即代码 (IaC),以在管道中的特定点自动配置资源。IaC 的目标是,当您部署应用程序时,您也会部署基础架构。这意味着您始终知道您的基础架构在生产中是什么样子,并且您的测试环境也可以复制到生产中。    

将 IaC 构建到 CI/CD 管道中有三个好处: 

1)可以帮助您确保您的应用程序及其运行的基础设施定期接受同步测试。传统的做法是说这是一台生产机器,它看起来是这样的——这是我们的测试机器,我们希望它尽可能接近生产环境。但几乎总是,你会发现生产环境会随着时间的推移而发生变化——这使得了解你的生产环境变得更加困难。

2)它可以帮助您缓解基础设施的任何实时问题。这意味着,如果您的生产服务器出现故障,这并不是灾难 — 您可以重新部署它(甚至可以自动重新部署)。

3)最后但同样重要的一点是:将 IaC 构建到您的 CI/CD 管道中意味着您可以更有效地执行蓝绿部署等操作。您可以部署应用程序的新版本(包括代码和基础架构),并重新路由 DNS 以转到该版本。如果它不起作用,那也没关系 - 您可以快速回滚到以前的版本。

6、创建自动回滚检查点    

理想情况下,您希望避免回滚软件版本。但说实话。我们都会犯错,有时在开发或测试环境中运行的代码在生产中无法完美运行。

当您需要将发布回滚到以前的应用程序版本时,自动化可以更轻松地快速完成此操作

我认为回滚是一个通用术语,指的是通过恢复到以前的版本来缓解生产问题,无论是重新部署还是从备份中恢复。如果您拥有出色的 CI/CD 管道,那么理想情况下您可以解决问题并立即推出更新 - 这样您就可以避免不得不转到以前的应用程序版本。

三、流水线工具选择:Jenkins,CircleCI,TravisCI


选择CI解决方案并没有灵丹妙药。您的选择将取决于您的团队规模,编程语言以及诸如个人喜好之类的简单内容。这就是为什么根据上述标准比较每个工具的特性很重要的原因。但是,某些工具已在市场上赢得了领导者的地位。这些领导者包括CircleCI,Travis CI和Jenkins。

1、CircleCI简介

CircleCI是用于CI和CD的基于云的工具。使用单元测试,集成测试和功能测试,它非常专注于测试所有提交的代码更改。Facebook,Kickstarter,Spotify,Lyft,Coinbase,Expedia,Stitch Fix和Dollar Shave Club等领先公司已经在CircleCI上成功运行了其开发过程。

CircleCI成立于2011年,总部位于旧金山,在2017年被Forrester评为持续集成领域的领导者。CircleCI受全球远程团队的支持和支持,CircleCI恪守自己的座右铭,帮助企业快速交付质量代码。该工具是测试持续集成过程的一个很好的选择,特别是对于使用容器化(Docker)的项目。

功能:

  • 带有一些开放源代码私有代码库;可共享的构建配置包

  • 支持在Linux或iOS构建环境中构建的所有语言

  • 提供私有服务器和托管云选项

  • VCS:在云计划中使用GitHub的Bitbucket支持项目;服务器计划中的GitHub和GitHub Enterprise

  • 虚拟机上的工作流程和自动化测试

  • 轻量级yml配置设置的质量文档,可快速设置项目

  • 开箱即用的云解决方案,设置后相对易于维护

2、Travis CI简介

Travis CI是为开源项目创建的工具,专注于CI。它使用自动化测试和精心设计的警报系统来改善构建过程。您可以快速测试您的代码– Travis将监督所有更改,并让您知道更改是否成功。与CircleCI一样,Travis CI也非常适合在持续集成开箱即用的解决方案中迈出第一步。但是,Travis CI没有免费的私人存储库计划-计划起价为每月69美元。

与CircleCI不同,Travis CI确实支持构建矩阵-该工具提供了使用不同版本的语言和程序包运行测试的机会。您可以按照自己的方式自定义它。例如,某些环境的失败可以触发通知,但不要使整个构建失败(这对于软件包的开发版本很有帮助)。

功能:

  • 该软件的许多部分在GitHub上都是免费的,其中一些私有代码是用Ruby编写的

  • 支持使用Linux,macOS以及(最重要的是Windows)构建的所有语言

  • 私有服务器和托管云选项

  • VCS是GitHub

  • 可以针对多个运行时和数据存储库或应用程序进行测试,而无需在多个操作系统上本地安装它们

  • 详细记录的轻量级yml配置设置;预装的数据库和服务可快速设置项目

  • 开箱即用的云解决方案,设置后相对易于维护

  • 没有免费计划(仅免费试用2个并发工作和100个首次构建)

3、Jenkins简介

Jenkins是领先的开源持续集成工具。超过300个插件可支持几乎每个项目的构建和测试,从而使其可灵活应对最细微的细节。该工具可免费使用,但与其他盒装解决方案相比,其学习曲线难以设置和运行。这使Jenkins最适合大型公司的团队,在该团队中,专门的DevOps工程师可以支持和管理环境。这并非易事,因为Jenkins支持工程师必须精通Groovy编程语言。

功能:

  • 用Java编写的完全开源的代码库

  • 支持所有主要语言

  • 在您自己的私有服务器或第三方云托管选项上运行

  • 从理论上讲,与任何类型的版本控制系统兼容

  • 强大的管道语法正在生成可帮助自动化许多流程(包括测试)的脚本

  • 通过Jenkinsfile进行配置;可以自定义为最小的细节,但这可能是最复杂的过程之一,但值得庆幸的是,现在借助管道脚本可以轻松一些

  • 最可定制的

  • 所有Jenkins组件均可免费使用,但不要低估DevOps工程师自定义,配置和运行环境的时间和成本。

4.其他持续集成工具

其他的一些持续集成的工具:CruiseControl,TeamCity,Continuum等

  • AnthillPro:商业的构建管理服务器,提供C功能

  • Bamboo:商业的CI服务器,对于开源项目免费

  • Build Forge:多功能商业构建管理工具,特点:高性能、分布式构建

  • Cruise Control:基于java实现的持续集成构建工具

  • CruiseControl.NET:基于C#实现的持续集成构建工具

  • Lunt build:开源的自动化构建工具

  • Para Build:商业的自动化软件构建管理服务器

5、总结:Jenkins是开源方案中的最佳选择,使用上需要管理员能力。


CircleCITravisCI‍‍Jenkins

‍‍软件类型

部分开源

部分开源

全开源

操作系统

Linux/Mac

Linux/Mac/win

全支持

版本控制系统

GitlaHub
Bitbucket

Github

全支持

云解决方案‍‍‍

支持

支持

支持


研发效能方法论
分享内容的四大方向:研发效能和软件工程方法论,软件工程技术,平台工程设计,通用五力