专业书籍精读 · 持续交付 · 第 1 章
Continuous Delivery · Ch 1 · Jez Humble & David Farley · 2010
你手机里的 App 每周都在悄悄更新。可「把写好的新版本真正送到用户手上」这件事,在很多公司恰恰是一年里最让人害怕的那几天:全组半夜开工,照着几十页操作文档一步步敲命令,出了错就现场救火,天亮前搞不定就整个退回去重来。《持续交付》第 1 章讲的就是:这种痛苦不是命,是可以被工程手段消灭的。
同一个年代,有的公司一年只敢上线四次、每次如临大敌;而 Amazon 在 2011 年公开说,自己平均每 11.6 秒就往线上更新一次,最忙的那一小时更新了一千多次。上线一千次的那家,反而更稳当。这听着反直觉,却正是这本书的出发点:发布之所以危险,往往不是因为这次改动大,而是因为你做得太少。
三件事凑在了一起。一是上线靠人手——照着文档敲命令,人会看错行、会漏掉一台机器。二是排练太少——真正像线上的环境往往要等功能全开发完才第一次碰,于是装不上、连不通、配置错的问题全堆在最没时间处理的那一刻爆发。三是每台服务器都成了手工艺品——今天有人手动改个参数、明天打个补丁,久了谁也说不清它现在是什么样,更别提照原样再造一台。
这本书的核心比喻很像自动洗车房:与其每次叫几个人拎着水桶手洗、洗得好不好全看今天谁上手,不如修一条固定通道——车从一头开进去,每道工序按同样的顺序自动走完,哪道过不了就当场拦下。软件也一样:每一次代码改动都从同一个入口进这条「流水线」,自动编译、快速检查、装到一个和线上一模一样的环境里测,一关不过就淘汰,一路全过的版本才有资格上线。
关键在于:测试环境和正式环境跑的是完全同一套动作。等到真要给用户上线那天,这套动作团队已经练过几百遍——它自然就不再是大事。书里最出名的那句话说的就是这个理:如果一件事很痛,那就更频繁地做它。
发布从「事件」变回「日常」:每次带上线的改动少了,出问题时要排查的嫌疑范围也跟着小;谁都能一键部署,不用排队等某个大神。诚实的代价是:这条流水线本身要花不小的力气去建、还得天天维护,短期内它一定比「找个人手动传个包」更慢、更贵——它赚的是长期的钱。
把发布做成一条自动、可重复的流水线,让每一次改动都走同一条路、受同样的检验;然后尽量频繁地发布。发布得越少才越危险,越常做才越无聊、也才越安全。
想进到具体机制、反模式清单和示意图? → 切到精读版
你以为发布危险是因为「这次改动太大」,其实因果常常反过来——正因为发布得少,每次改动才那么大。《持续交付》第 1 章立下全书命题:交付之所以痛苦、高风险、耗时,根源在于发布过程手工、罕见、不可重复;解法是把构建、部署、测试、发布整个过程自动化成一条部署流水线(deployment pipeline),让每一次提交都成为候选发布版,把「上线」从一场需要熬夜与祈祷的事件,变成无聊到没人紧张的日常操作。
作者 Jez Humble 与 David Farley,成书时同在 ThoughtWorks。本章是全书 Part I「基础」的开篇,也是整本书的总纲:不讲任何具体工具,只把「交付为什么这么痛」摊开,再给出中心模式(部署流水线)与八条原则。下承第 2 章配置管理(把代码、配置、环境统统纳入版本控制,让系统可重现)、第 3 章持续集成,第 5 章把这里草描的流水线展开成全书骨架。今天的 Jenkins、GoCD、GitHub Actions、Argo CD,都是这条流水线的具体化身。
先还原 2010 年前后典型企业软件的样子:一年发布 2–4 次,窗口定在周五深夜或整个周末,一份几十页的部署手册,一屋子人待命,「回滚」意味着从数据库备份里恢复。痛在三处:反馈慢——周期时间以月计,缺陷在修复成本最高的时候才浮现;批量大——一次上线塞进成百个改动,出事时嫌疑范围大得没法查;不可重复——每次发布都是一场手艺表演,换个人、换台机器结果就不一样。
不解决会怎样?Knight Capital,2012 年 8 月 1 日。美国证券交易委员会(SEC)2013 年的行政处罚令记载:一次手工部署把新代码装上了 8 台生产服务器中的 7 台,漏掉一台;偏偏那台机器上,一个被复用的旧开关唤醒了多年未用的老算法,45 分钟内向市场发出数百万笔订单,公司损失超过 4.6 亿美元。一次「漏了一台机器」的手工部署——这就是本章要消灭的东西。
反模式 1 · 手工部署软件。症状像张体检表:一份逐步描述「该敲什么命令」的长文档;靠人工测试确认「它到底起来了没有」;上线中频繁打电话问开发「这步为什么报错」;现场临时改配置;一次发布耗几个钟头而不是几分钟;结果不可预测,常常得回滚。作者的判据很锋利:换一批人、换一台机器就跑不出同样结果的,不是流程,是手艺。对策是把部署做成完全脚本化、所有环境跑同一套的自动过程。
反模式 2 · 只在开发完成后才部署到类生产环境。症状:开发期只在本机跑;测试人员拿不到像样的环境;运维临发布才第一次见到这个应用。于是装配、依赖、配置、数据迁移这些问题全被推迟到最没时间处理的那一刻。对策是从第一天起就往类生产环境部署,把「部署」反复演练。
反模式 3 · 手工管理生产环境的配置。症状:同一个包在预发装得好好的、一到生产就挂;集群里总有那么几台特别爱出问题;没办法把系统(操作系统、补丁、中间件、数据库、配置)退回到过去某个已知状态。对策:环境的每个方面都纳入版本控制、由脚本自动建立(第 11 章——「基础设施即代码」的雏形)。
作者把目标说得很直白:找到一种高效、快速、可靠地交付有价值软件的方式。落成可操作的指标就是周期时间——从「决定做一个改动」到「它在生产上跑起来」有多久。围绕它,本章给出全书的中心模式:部署流水线,即「应用的构建、部署、测试、发布过程的自动化实现」。
一次提交进入流水线后逐关推进:提交阶段(编译、单测、静态分析)→ 自动化验收测试 → 手工 / 用户验收 / 容量测试 → 发布。关键不在关卡本身,而在三件事:每一关都由同一套脚本、同一份制品驱动;任何一关失败,这个版本立刻出局;结果要在几分钟到几十分钟内回到提交者面前。书里给的经验值是提交阶段控制在十分钟以内(第 7 章展开)——超过这个数,人就不再等它、转头开新工作,反馈也就失去了意义。
一条流水线值不值钱,全看反馈闭环。本章提了三条:① 每一次改动都必须触发反馈过程——不能挑着跑、不能「这次改得小就先不测」;② 反馈必须尽快到达——越快,「出错」到「发现」之间夹的改动越少,定位越便宜;③ 团队必须接收反馈并据此行动。第三条最常被忽视:主干红了两周没人修,CI 服务器就只是个装饰品。
传统做法是等测试都跑完,从若干构建里提名一个作为发布候选版,再走一遍完整回归。作者把它反了过来:每一次签入(check-in)都产生一个潜在的发布版本——每个构建默认都是候选,流水线的每一关都在证伪它,只有一路走到底没被淘汰的版本才有资格上生产。这个转变很关键:「什么时候能发」从一个由人拍板的里程碑,变成流水线随时回答的状态。
本章末尾给出八条原则,是全书的价值观压缩包:
收益条条对着前面的痛:赋能团队(一键自助部署)、减少错误(尤其是交接处的错误,配置不再靠口头传递)、降低压力、部署灵活,以及熟能生巧——同一套流程在每个环境都跑,真上生产时它已被执行过成百上千次。
这一章真正的争论点不在「要不要自动化」,而在先自动化什么、哪里该停手、以及为此付出什么。
表 1 · 大爆炸式发布 vs 持续交付(代价也照实写)
| 大爆炸式发布 | 持续交付 | |
|---|---|---|
| 发布频率 | 一年 2–4 次,挑周五深夜 / 周末 | 随时可发;实践中每天数次到每小时数十次 |
| 单次批量 | 成百个改动一起上 | 一次提交即一个候选版,批量极小 |
| 周期时间 | 以月计 | 以分钟到小时计 |
| 出事定位 | 嫌疑范围是整批改动,靠猜 | 范围就是这一次提交 |
| 回滚 | 常需从数据库备份恢复,高风险 | 退回上一个已知良好制品,脚本化 |
| 前期投入 | 低——手动传个包当天就能干 | 高——脚本、测试套件、环境管理都要建并长期维护 |
| 组织要求 | 可按职能分墙而治 | 要求开发 / 测试 / 运维协作;组织不改,工具白搭 |
表 2 · 三个常被混为一谈的「持续」
| 做什么 | 产出的承诺 | 上生产由谁决定 | |
|---|---|---|---|
| 持续集成 CI | 每天多次把改动合回主干,自动构建 + 测试 | 主干随时可构建、可测 | 不涉及 |
| 持续交付 CD | 再加上自动化部署与逐关验证的流水线 | 每个通过流水线的构建都具备上线资格 | 业务按按钮 |
| 持续部署 | 再去掉那个按钮 | 每个通过的构建自动进生产 | 流水线自己 |
本书主张的是中间那一档。持续部署更激进,也不是人人适用——客户端软件、嵌入式设备、强监管系统里,「什么时候让用户拿到」本就是业务与合规决定,不该交给流水线。
至于「几乎一切都要自动化」里的那个「几乎」:该自动化的是编译打包、测试、环境搭建、部署、数据库迁移、制品晋级;该留给人的是探索性测试(靠好奇心撞未知问题)、可用性判断(好不好用无法断言成 true/false)、给客户演示,以及「现在要不要发给用户」这个决定。
这一章之所以成为整个 DevOps 运动的地基,是因为它把「发布」这件长期被当成组织问题、甚至运气问题的事,重新定义成一个可以工程化的技术问题。今天的工具都是它的化身:Jenkins / GitHub Actions 是流水线的执行器;Docker 镜像、Terraform、Ansible 是「把环境纳入版本控制」的答案;Argo CD、Spinnaker 把部署做成可观测、可回滚的自动过程;特性开关(feature flag)让「Done means released」在不向用户暴露半成品的前提下成立。面试里那句「说说你们的发布流程」考的就是这一章——能不能报出周期时间、单次批量、回滚手段,以及哪一关拦住了什么。
11.6 秒完成一次生产部署,最忙的一小时部署 1,079 次——把「发布频率高到某个程度,发布就不再是事件」这件事量化了。Jon Jenkins「Velocity Culture」, Velocity 2011 ↗517 次;自建一键部署工具 Deployinator 把一次网站发布从「3 名开发 + 1 名运维、其他人待命、顺利也要一个多小时」压到「1 个人、2 分钟以内」——本章「手工部署」反模式的对照实验。Etsy Code as Craft, 2011 ↗208 倍、前置时间快 106 倍、故障恢复快 2,604 倍,而变更失败率低 7 倍——「快」与「稳」不是取舍,是同一批实践的产物。Accelerate State of DevOps Report 2019 ↗4.6 亿美元——三个反模式同时踩中的账单。SEC 行政处罚令 34-70694, 2013 ↗① 命题:交付之痛的根源是发布过程手工、罕见、不可重复;反直觉的因果是——不是改动大所以危险,而是发布少所以改动大。
② 三个发布反模式:手工部署 / 只在开发完成后才碰类生产环境 / 手工管理生产环境配置;病根都是不可重复。
③ 目标可量化为周期时间——从决定做一个改动,到它跑在生产上。
④ 中心模式:部署流水线——构建、部署、测试、发布全过程的自动化实现;同一份制品、同一套脚本沿关卡推进,一关不过即出局。
⑤ 反馈三条:每次改动都触发;尽快返回(提交阶段十分钟量级);团队必须据此行动——第三条最常烂尾。
⑥ 视角转变:每一次签入都产生一个候选发布版,「能不能发」从人拍板的里程碑,变成流水线随时回答的状态。
⑦ 八原则里最该记的:可重复的发布流程、几乎一切自动化(但不是一切)、一切纳入版本控制、痛就更频繁地做、质量内建、Done 意味着已发布。
⑧ 实证:Flickr 每天 10+ 次(2009)、Amazon 平均 11.6 秒一次(2011)、Etsy 一个月 517 次(2011);DORA 2019 显示精英组部署频率高 208 倍、变更失败率却低 7 倍——快与稳同源。
⑨ 别混淆:持续交付 ≠ 持续部署,CI 服务器 ≠ 持续交付。诚实的代价是——流水线要持续投入维护,短期一定比手工上线更贵。