site logo

Marico's space

生产部署期间会发生什么?幕后指南

AI技术与应用 2026-07-30 14:49:32 5

最近折腾了公司那条祖传部署流水线,踩了几个坑才搞明白这玩意到底在干嘛,这篇把问题说清楚。

你把代码 push 上去,几分钟后它就在线上跑着了,供真实用户访问。

但这两步之间其实跑着一长串基础设施:构建、打包产物、数据库迁移、健康检查、流量切换。搞生产的技术人天天依赖这条链路,很多团队到现在还是自己维护这套东西。

部署基础设施早就成了运营负担。最开始这是没办法的事,每个团队都得自己搭,因为市面上根本没有现成方案。

但现在情况变了——它变成了一套你工程师要额外维护的"第二个产品",占着 on-call 轮值、占着 sprint 容量、占着凌晨两点的注意力,这些资源本来可以用在更有价值的地方。

这篇文章走一遍真实生产部署的每个阶段:构建、产物、数据库迁移、健康检查、滚动更新、回滚。顺便聊聊为什么 PaaS(平台即服务)能帮你把这些步骤都兜底了,以及一个团队自己扛这些要付出多少代价。

构建阶段:把代码变成能跑的东西

部署不会把你的源代码原封不动发上去,而是发构建的结果。构建阶段把你的代码变成服务器能运行的形式。

具体什么样取决于你的技术栈。Java 或 Go 项目编译成二进制文件;JavaScript 前端打包压缩;Python 应用解析并锁定依赖版本。在大多数现代方案里,这些都会被装进一个容器镜像里——也就是你的应用加上运行环境的一个冻结快照。

构建阶段还会跑测试。单元测试、代码检查、安全扫描都在这里做。任何一步挂了,部署就停在这里,不会碰到生产环境。这是抓 bug 成本最低的地方——构建失败损失几分钟,部署失败损失的是用户。

自己维护流水线的团队在这里要花不少精力:维护构建服务器、缓存依赖、排错不稳定的测试 runner。

这些活儿跟产品功能一点关系没有,纯属维护,而且永远干不完。PaaS 把整个构建阶段直接做进平台里了。你 push 代码,平台识别语言、一致性地构建、出问题快速失败。构建还是那个构建,只不过工程师不用再用自己的时间买单了。

产物:一版代码,冻结在某个时刻

构建的输出物叫产物(artefact)。可能是容器镜像、编译好的二进制,或者一个压缩包。不管什么格式,产物的唯一使命就是:精确。代表的是你的应用在某个特定时刻的某个精确版本。

这比听起来重要得多。通过测试的那个产物,必须和发到生产的是同一个。如果你在测试和发布之间重新构建了一次,就有可能发出不一样的东西。某个依赖可能更新了,某个构建参数可能变了。"测试环境没问题"往往意味着"我们构建了两次,得到了两个不同的结果"。

好的流水线构建一次,然后让同一个产物在各阶段晋升。产物会被版本化并存储在镜像仓库里,任何版本都可以随时拉出来再跑。这份存储历史也是回滚能实现的原因,这个后面会讲到。

在 PaaS 上,产物管理是默认标配。每次部署产生一个编号 release,平台存储它、追踪它、能恢复它。你不需要设计 registry 策略、不需要写晋升脚本、不需要指派专人维护。这套规范是内置的。

数据库迁移:最危险的一步

新代码上线之前,数据库往往也得跟着改。可能是新版本需要新增一列或者新表。这些改动叫迁移,是大多数部署中最危险的部分。

为什么?代码好替换,数据不好。如果部署了一个坏代码版本,可以直接换掉。但如果迁移损坏了数据或者弄丢了数据,可能没有干净的回退方案。迁移还制造了一个棘手的窗口期——有那么几分钟,老代码和新代码可能同时连着同一个数据库跑。这段时间里,两个版本都得能适配这个 schema。

安全的做法是让迁移向后兼容。先加新列,部署能同时处理新旧两种结构的代码,然后在后面的版本再清理旧列。步骤更多,但每一步本身都是安全的。

PaaS 不能替你写迁移。没有任何工具知道你数据的业务含义。但一个靠谱的平台会给迁移在 release 流程中一个明确的位置,按顺序执行,详细记录什么时间跑了什么。这套结构能防止那种经典失败场景——有人手动跑了个迁移,结果忘了告诉团队。

健康检查:证明新版本活过来了

新版本启动之后,平台不会盲目信任它,而是会检查。健康检查是应用里的一个小接口,通常就是一个返回"OK"的路由。平台反复调用它——应用有响应,就算健康;没响应,平台就认为出问题了。

通常有两类检查。readiness check(就绪检查)问的是"你准备好接收流量了吗";liveness check(存活检查)问的是"你还在工作吗,需不需要我重启你"。这两者有区别。一个应用可能还活着但还没就绪,比如还在预热缓存。

健康检查是部署的守门人。新版本在证明自己能处理请求之前,不会接收任何流量。没有健康检查,你就只能把真实用户导到一个可能还在启动崩溃中的应用上。

每个正经 PaaS 都会自动跑健康检查。你定义端点,平台负责轮询、超时处理、决策判断。自己搭这套东西的团队要手工调所有这些参数,通常是通过痛苦的试错才找到正确的值。这笔学费是以工程时间为代价的,而这个问题的解法行业早就做出来了。

滚动更新:空中换引擎

这是最难的部分。你的老版本正在服务线上流量,你得在不掉一个请求的情况下替换掉它。最常见的方案是滚动更新。

原理是这样的。假设你现在有四个应用副本在跑。平台先启动一个新版本的一个副本,等它的健康检查通过,然后把一部分流量切过去,同时关掉一个老副本。然后重复这个过程——一次一个副本——直到全部换成新版本。用户完全感知不到,因为每时每刻都有足够多的健康副本在服务所有人。

有些团队用这个思路的变体。蓝绿部署是在老版本旁边完整跑一个新版本,然后一次性切走所有流量。金丝雀发布是先让一小部分用户体验新版本,观察错误率没问题再扩大范围。

自己搞的话,意味着要写编排逻辑、管理负载均衡器规则、处理每个中间步骤失败的边界情况。光是构建就要几个月工程量,之后还要持续维护——这些全是为了 PaaS 默认就带的功能。在平台上,零宕机发布是开箱即用的,不需要你专门安排人去做的项目。

回滚:紧急逃生舱

有时候新版本通过了所有检查,但还是在线上搞坏了什么东西。错误率开始爬升,某个页面加载不出来。现在速度比什么都重要,最快的修复很少是发一个新补丁——而是回滚:重新部署那个你已经验证过能用的旧产物。

这就是为什么冻结的、带版本的产物这么重要。回滚要快,唯一的条件就是旧版本已经存储好、测试过、随时能跑。那些在压力下从旧 commit 重新构建的团队,是在最糟糕的时机赌一把。

在大多数 PaaS 上,回滚就是一个命令或者一次点击。平台保留你的 release 历史,能在几秒内恢复到任何一个之前的版本。这个功能可能比其他任何功能都拯救了更多 on-call 工程师的夜晚。

你还在自己维护这套东西吗?

PaaS 没有让任何一个步骤消失。构建还是在跑,产物还是在存,迁移还是在执行,健康检查还是在轮询,流量还是在逐个副本地切换。抽象掉这些机制并没有消除它们,只是标准化了,并把维护工作交给了一个产品就是做部署的平台。

这是每个产品团队现在应该直接问的问题:我们为什么还要自己搭、自己维护这套流水线?十年前,自定义 pipeline 是不得已。今天这是个选择,而对大多数团队来说,这是个错误的选择。每花一小时调试一个不稳定的构建 agent、调一个健康检查超时、或者打补丁给编排脚本,都是从用户真正买单的产品上抽走的时间。部署流水线不会让你差异化——它做不到。你竞争对手的部署跟你用的是同一套逻辑。

了解这条链路是怎么工作的,因为凌晨两点 on-call 的时候你需要懂这些。但知道怎么工作不是自己维护的理由。"我们自研了部署系统"已经不是荣誉徽章了。它只是说明你的团队在维护一个没有用户的产品。除非部署基础设施本身就是你的业务,否则把这套机械交给平台,把工程师放回到只有他们能做的事情上。