1. 引言

自从第一个软件开发生命周期模型 —— 瀑布模型 被提出以来,业界又陆续引入了多种开发模型。到了 2000 年左右,"敏捷革命" 推出了 敏捷宣言,由于“敏捷”不仅适用于开发人员,还涉及运维等其他角色,从而催生了一种新的方法论 —— DevOps

在本文中,我们将重点讲解 DevOps 实践中的三个核心概念:持续集成(Continuous Integration, CI)持续交付(Continuous Delivery, CD)持续部署(Continuous Deployment, CD),并分析它们之间的区别。

2. 软件开发流水线与持续集成

持续集成、持续交付和持续部署主要涉及 DevOps 周期中的代码、构建、测试、发布和部署阶段。

这些阶段体现在一个软件生产流水线中,如下图所示:

cicd pipeline

每个阶段代表对输入“产品”的一项操作,输出“产品”传递到下一个阶段,依此类推。这里的“产品”通常指的是一个 软件制品(artifact)。我们可以看到,流水线的初始输入来自规划和设计阶段产生的任务 待办列表(backlog)

开发人员基于这些任务进行开发,并将代码变更提交到源码仓库。这通常发生在开发分支上,但根据使用的 工作流(workflow),也可能发生在主分支上。当开发人员将代码合并到主分支时,系统会自动进行构建和测试。

如果自动化测试通过,则生成的制品会被发布到制品仓库;如果失败,则构建流程会被中止,并通知开发人员。这一切都是自动完成的。在这一部分的 流水线 中,每完成一次任务,就会发布一个新的 语义版本号(version) 的软件制品。

频繁地进行代码集成、构建与测试,这一整套流程被称为持续集成(Continuous Integration)。

3. 持续软件交付

软件交付与部署是软件生产流水线的最后两个阶段。

从单个开发人员的角度来看,“交付”可能意味着某项变更已经通过测试并 合并到主分支。这是开发人员交付工作的常见方式。

但问题是:这项变更是否与其他开发人员的变更兼容?是否与某个依赖项的新版本兼容?这个依赖项是否因为漏洞或被 弃用(deprecated) 而必须升级?此外,开发人员是否真正理解了新功能或 bug 修复的需求?

这时我们意识到,“交付”是指整个软件产品的交付,而不是单个变更的交付。交付是指将最终的完整软件产品交付给客户的整个过程。

一个软件产品通常由多个团队并行开发的不同组件组成。因此,流水线中第二部分(即持续交付和部署阶段)的输入,实际上是多个持续集成(CI)流水线的输出。这些 CI 流水线的最终产物通常会被发布到一个中间制品仓库中,供后续使用。

在复杂的软件产品中,可能会有多个客户或使用者。大型团队通常由不同职责的子团队组成。例如,某个团队负责开发被其他团队使用的底层库。每当这个底层库发布新版本时,它会被持续交付到内部仓库,供其他团队使用。

总结:持续交付是指将软件产品或制品交付到最终使用者可获取并使用的地方的过程。
这里的“使用”可以是指将其集成到更大的软件产品中,也可以是指将其部署到 生产环境(production environment) 中。
⚠️ 通常情况下,新版本的部署需要产品经理或客户的审批(见上图中的 Approver 角色)。

4. 持续软件部署

在实际操作中,新版本的交付通常分为两个步骤:

  1. 软件被自动部署到测试环境(或预发布环境),开发人员和客户都可以访问这个环境,进行 bug 修复和新功能的测试。这个阶段称为“用户验收测试(UAT)”或“现场验收测试(SAT)”,部分测试可以自动化完成。
  2. 如果测试通过,则部署到生产环境。该步骤通常需要人工审批。

随着云应用和移动应用的普及,软件复杂度呈指数级增长。例如,云服务可能运行在成千上万的虚拟机上,手动审批每个版本在这些机器上的部署已不再现实。因此,现在新版本的部署也实现了自动化,我们称之为 持续部署(Continuous Deployment)

当然,部署也不是一次性全部完成的。而是采用一种 受控的部署策略,例如先将新版本部署到一小部分机器上。如果运行正常,则逐步扩大部署范围;否则,就进行回滚或者销毁有问题的机器,重新创建使用旧版本的机器(更常见且成本更低)。

由于每次发布的变更较小,因此也更容易自动化测试来验证新版本是否正常。这是流水线中“持续交付/部署”阶段最后一个步骤,称为“上线后测试(Post-prod tests)”。

5. 为什么是“持续”?

为什么这些流程被称为“持续”?因为它们是持续不断地进行的

早期的软件开发周期很长:先收集需求、设计系统、开发、测试,最后发布。这种“大爆炸式”的发布方式让客户不得不等待很长时间才能拿到新版本。

在这个过程中,中间不允许变更,因为需求已经“冻结”。这导致客户和开发人员都感到沮丧:客户没有拿到想要的产品,开发人员也没有得到足够的反馈。产品功能逐渐偏离客户需求。

此外,软件更新成本高且耗时。不仅新功能开发和测试需要大量时间,现有软件和生产数据迁移到新版本也非常复杂且容易出错。双方都对下一次发布感到恐惧。开发人员常调侃说:“大改动伤身”,这也是引入敏捷和后来 DevOps 的主要原因。

如果软件以小步快跑的方式演进,那么每次变更都较小,实现、测试和部署都更容易,出错率更低,也更容易回滚。
随着开发周期变短,发布频率自然提高,新的变更可以持续集成到软件中。

客户能更快地获得新功能和修复,而开发人员也不再惧怕周五下午的发布。通过自动化构建、测试、交付和部署流程,减少了人为干预和错误,提高了对软件的信任度。

6. 总结对比

总结一下,以下表格展示了持续集成、持续交付和持续部署这三个流程的对比:

过程 输入 主要活动 输出
持续集成 (CI) 待办任务(Backlog) 规划、设计、编码、合并、构建和测试 软件制品(Artifacts)
持续交付 (CD) 软件制品 组装、打包、验收测试、发布最终产品 最终产品
持续部署 (CD) 最终产品 应用自动化部署策略、上线后测试、自动回滚 已部署并运行的生产环境软件

虽然它们是三个独立的流程,但它们共同构成了软件生产的完整流水线。

7. 结论

在本文中,我们介绍了构成软件生产流水线的三大核心流程:持续集成、持续交付和持续部署,并分析了它们之间的区别。

我们还强调了:如果流水线中处理的变更足够小,整个软件开发流程就会更加顺畅和高效。换句话说,就是实现了“持续”。

此外,自动化在这一过程中扮演了至关重要的角色。它减少了人为干预,提高了任务的可靠性和可重复性,使整个软件生产流程具备良好的扩展能力。

一句话总结:持续 = 小步快跑 + 自动化支撑。


原始标题:Continuous Integration vs. Continuous Deployment vs. Continuous Delivery