2.1 CI/CD介绍
CI是指持续集成(Continuous Integration, CI),狭义的CD指持续交付(Continuous Delivery, CD),广义的CD指持续部署(Continuous Deployment)。所谓的持续,就是说每完成一个完整的部分,就向下个环节交付,发现问题可以马上调整,使问题不会放大到其他部分和后面的环节。集成是指个人研发的软件部分向整体部分交付,以便尽早发现个人开发部分的问题;交付是指研发尽快向质量团队或者用户交付,以便尽早发现生产环境中存在的问题;部署是代码通过测试后自动部署到生产环境。
2.1.1 持续集成
随着软件项目复杂度的增加,对软件组件之间的集成和协同工作提出了更多的要求。如果开发人员在后期才进行集成,发现和解决问题的代价会很大,很有可能导致项目延期甚至失败。因此要“尽早集成、经常集成”,在项目早期发现的风险和质量问题更容易得到解决,并保证了开发进度,持续集成就诞生在这样的背景下。
持续集成指的是频繁地将代码合入到主干分支,只有通过自动化测试和验证的代码才能被集成,目的是让产品在可以快速迭代的同时还能保证质量。简单来说就是,针对软件系统的每次变更,能持续且自动地进行验证:构建、测试。根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起,并确保核心功能正常执行,不受影响。Martin Fowler说过:“持续集成并不能消除Bug,而是让它们非常容易被发现和改正。”
持续集成的流程如图2-1所示。
图2-1 持续集成的流程
开发人员首先获取当前工作代码库的副本。随着其他开发人员将更改后的代码提交到源代码库,此副本逐渐与远端代码库不同步。代码库可能不仅仅被更改,还可能添加新库,或者增加其他引起依赖或者冲突的模块。
代码分支检出的时间越长,当开发者分支重新集成到主线时,集成冲突和失败的风险就越大。当开发人员将代码提交到代码库时,必须先更新代码,使本地副本和代码库中的主线分支同步。代码库包含的更改越多,开发人员在提交自己的变更前必须执行的工作越多。
开发人员的代码提交到源代码库,即触发CI服务器开始构建和测试,并把测试结果反馈给开发人员。测试通过,代码即合并到代码库中继续下一轮的测试;测试失败,开发人员根据反馈结果修改后重新提交。
以上过程循环重复即持续集成。
持续集成一般由代码变更触发,遵循先进先出的原则,否则容易引起混乱,很难定位是谁的代码破坏了集成;而且构建时间不能太长,否则构建次数太少,大部分变更一直处于等待状态。
需要补充一点,在代码提交之前,开发人员必须在本地完成单元测试,集成测试通常在检测到新提交时在CI服务器上自动运行。
持续集成的好处就在于:
快速发现错误,变更容易追踪,节省了项目生命周期间的时间和金钱。
避免版本发布最后时期才集成的混乱。
测试失败或出现bug时更容易恢复。
保证主干分支的可用。
频繁地集成推动开发人员设计模块化、不太复杂的代码。
可以说,持续集成是DevOps的重要基础环节。
2.1.2 持续交付
持续交付指在持续集成的基础上,频繁地将集成后的代码交付给质量团队(QA)或者用户,部署到更贴近真实运行环境的类生产环境中以供测试评审,通过就进入发布,生产阶段。它旨在更快更频繁地构建、测试和发布软件,有助于降低交付的成本、时间和风险。直接和可重复的部署过程对于持续交付非常重要。持续交付并不意味着每个变更都会尽快部署到生产环境中,它意味着每次更改都被证明可以随时部署。持续交付的目标不是要消灭缺陷,而是要规范开发和测试的流程,从根源上提高产品的质量。开发人员需要了解任何代码提交都可能会随时发布给客户,这一点很重要。
持续交付的流程如图2-2所示。
图2-2 持续交付的流程
由图2-2可以看到,持续交付在持续集成的基础上多了手工部署和系统测试等流程。
持续交付的产品一般有:
源代码交付:比如Python/Shell脚本,但这些文件不是标准的软件包,不利于集中管理和运行。
软件包交付:比如通过RPMBuilder工具制作Linux标准包。
镜像交付:可以是虚拟机镜像也可以是Docker镜像。
持续交付的优点:
提高了产品质量,加快了产品上市时间。
产品更符合用户需求,提高了客户满意度:频繁地发布使开发团队可以更快地获得用户反馈,专注于开发对客户有用的功能,有助于构建正确的产品。
提高了生产力和效率。
在实施持续交付的过程中,必须考虑将基础设施的维护纳入进来,作为支持产品运行的一部分。传统的基础设施运维管理存在以下几个问题:
自动化缺乏串联:虽然有一定的自动化,但不能做到无人值守,需要执行一些临时命令。由于环境释放和重建的成本高,因而倾向于不释放,导致资源利用率低。
与产品团队脱节:很难根据需求随时动态增加环境。需要额外的文档来描述环境,可能更新不及时。
通过基础设施代码化(Infrastructure as Code, IaC)可以解决上述问题,大大有助于实现持续交付,促使持续交付和DevOps的成熟,是DevOps的一项关键实践。
IaC有四项关键原则:
再生性:环境中的任何元素可以轻松复制。
一致性:无论何时,创建的环境中各个元素的配置是完全相同的。
快速反馈:能够频繁、容易地进行变更,并快速验证变更是否正确。
可见性:所有对环境的变更应该容易理解、可审计、可回退、受版本控制。
2.1.3 持续部署
持续部署是持续交付的下一阶段,指的是软件通过测试后自动部署到生产环境。持续部署的前提是能自动化完成测试、构建、交付等步骤;目标是代码在任何时刻都是可部署的,可以进入生产阶段。
持续部署的流程如图2-3所示。
图2-3 持续部署的流程
持续部署意味着每次更改都会自动部署到生产环境中,强调的是自动化。为了进行持续部署,必须持续交付。虽然持续部署可能不适合每个团队或项目,但持续交付是DevOps实践的绝对要求。
2.1.4 CI/CD工作流
以上简单介绍了CI/CD的概念及每个阶段的工作流程,整合起来即一套完成的CI/CD流水线。在实际应用中,一般通过代码评审系统实现代码审查和集成反馈。整个CI/CD系统配置了代码仓库系统、代码评审系统和构建工具系统。
(1)代码提交
开发者向代码评审系统(比如Gerrit)提交代码。
(2)测试
系统监听到代码评审系统的事件后即触发相关的测试。这里的测试有如下几种:
单元测试:针对函数或者模块的测试。
代码风格检查:针对代码编写的风格进行检查,比如Python的pep8等。
集成测试:功能测试。
(3)构建
测试通过后代码就可以合入主干分支,同步到代码仓库,进行下一阶段的构建了。所谓构建,就是将源代码转换为可以运行的软件包或者镜像等。
(4)测试
构建完成后进行下一轮测试,此阶段的测试比第一轮测试全面,包括功能测试、系统测试、性能测试等。
(5)交付
第二轮测试通过,代码就进入发布、生产阶段。
(6)部署
经过多轮测试后的版本就是一个可直接部署到生产环境的稳定版本,此版本发布到制品库上,用户就可以在获取版本后通过自动化工具部署到生产环境。
工作流有了,接下来就是选择每个阶段的工具搭建整个自动化的生态系统,在没有制定出CI/CD的工作流时考虑工具的选择只是纸上谈兵,只有在设计好工作流程和业务流程之后再选择相匹配的工具集才有意义。