部署策略图:滚动、蓝绿与金丝雀

用图对比滚动更新、蓝绿部署和金丝雀发布:流量如何切换、回滚如何进行、各自的成本,以及自动化金丝雀分析如何做决定。

· 创始人兼开发者

发布于

部署策略图:滚动、蓝绿与金丝雀

大多数故障都始于一次部署。代码通过了评审和测试,然后遇上了真实的流量、真实的数据和真实的依赖。部署策略决定了有多少流量会同时遇上新版本、你多快能发现问题,以及多快能撤销它。

本文对比大多数团队会在其中做选择的三种策略:滚动更新、蓝绿部署和金丝雀发布。文中展示每种策略下流量如何移动、回滚是什么样子,最后给出一张金丝雀发布的架构图,其中继续还是回滚的决定是自动做出的。

滚动更新

每次替换几个实例,逐步把旧版本换成新版本。Kubernetes Deployment 默认就是这样做的:在 RollingUpdate 策略 中,maxSurge 和 maxUnavailable 控制发布过程中允许多出和缺少多少个 Pod,两者默认都是 25%。

  • 流量: 发布期间,两个版本同时处理请求,比例取决于各自的 Pod 数量。
  • 回滚: 再做一次滚动更新,回到旧版本。需要几分钟,而不是几秒。
  • 成本: 几乎没有额外成本,最多是 surge 的那部分容量。
  • 风险: 任何用户都可能很早就碰到新版本,而唯一的自动关卡是就绪探针。一个启动正常、却在负载下失败的版本会被完整地发布出去。

对于低风险的变更,以及测试和探针都完善的内部服务,滚动更新是合适的默认选择。让就绪探针检查服务正常工作所需的一切,而不只是进程是否在运行;否则发布过程会若无其事地用坏掉的 Pod 替换健康的 Pod。

蓝绿部署

运行两套完整的环境。蓝环境服务生产流量;绿环境部署新版本,并在原地测试。然后由负载均衡器或 DNS 一次性把全部流量从蓝切到绿。Martin Fowler 对 蓝绿部署的描述 是经典参考。

  • 流量: 先全部在蓝,再全部在绿。不会同时在两边,至少不会持续很久。
  • 回滚: 切回仍在运行的蓝环境。只需几秒。
  • 成本: 两套环境同时运行期间需要双倍容量。
  • 风险: 切换会一次性移动 100% 的用户,所以只在真实流量下才出现的问题会影响所有人。数据库是共享的,因此模式变更必须同时兼容两个版本。

金丝雀发布

把一小部分真实流量(比如 5%)发往新版本,与稳定版本对比;如果表现良好,再逐步扩大比例。这个名字来自煤矿里的金丝雀;参见 Fowler 网站上的 金丝雀发布文章。

  • 流量: 按权重、请求头或用户分组来划分。
  • 回滚: 把金丝雀的权重设为零。几秒即可完成,而且只有百分之几的用户受到影响。
  • 成本: 几个额外的 Pod,加上流量划分和分析的工具。
  • 风险: 只要盯住正确的指标,就是三者中最低的。没人盯着的金丝雀,只是一次缓慢的滚动更新。

横向对比

滚动 蓝绿 金丝雀
接触到坏版本的用户 逐步增加,最多全部 全部,一次性 一小部分
回滚时间 几分钟 几秒 几秒
额外容量 仅 surge 切换期间 100% 几个 Pod
是否需要流量划分 不需要 一个切换开关 加权路由
数据库变更 向后兼容 向后兼容 向后兼容

最后一行在三种策略中都一样,这是有原因的:无论哪种策略,两个版本的代码总会在某个时刻面对同一个数据库。使用“先扩展、后收缩”(expand-and-contract)的迁移方式:先添加新的列和表,部署同时兼容两种结构的代码,再在之后的版本中移除旧结构。

金丝雀之前的影子流量

有些团队会在金丝雀之前加一步:把一部分生产请求复制给新版本,并丢弃它的响应。Envoy 和 Istio 都可以这样镜像流量。这能在完全不影响用户的情况下发现崩溃和延迟退化,但只适用于读请求和幂等请求。被镜像的写请求会重复产生副作用,比如邮件、支付和库存变动,所以要把它们排除在镜像之外,或者让影子版本连接沙箱中的依赖。

自动化金丝雀决策

金丝雀的价值来自对比,而人并不擅长盯着仪表盘看一个小时。Argo Rollouts 和 Flagger 等工具在 Kubernetes 上把这件事自动化:它们分步调整流量,在每一步之间查询你的指标提供方,并根据你定义的阈值决定提升还是中止。

好的分析指标数量少,而且贴近用户:

  • 金丝雀的错误率(5xx 响应),与稳定版本对比。
  • 高百分位的延迟,比如 p99。
  • 如果可能,再加一个业务信号,比如每分钟完成的结账数。

拿金丝雀和稳定版本对比,而不是和一个固定数值对比,这样某个依赖状态不佳的夜晚就不会让每次发布都失败。

架构图

CI 把 v2 镜像交给发布控制器。Ingress 把 95% 的流量发往稳定版 v1,5% 发往金丝雀 v2;两者都向指标系统上报数据,指标再输入控制器。一个判断节点检查金丝雀:是则依次提升到 25%、50% 和 100%;否则中止,并把全部流量切回 v1。

11 个组件 · 11 个连接

在 Archboard 中打开
图表内容
  • CI pipeline
  • Rollout controller
  • Users
  • Ingress
  • Stable v1
  • Canary v2
  • Metrics
  • Canary within thresholds?
  • Next step: 25, 50, 100 percent
  • Abort: all traffic to v1
  • image v2
  • 95%
  • 5%
  • error rate, p99 latency
  • yes
  • no
  • set weights
Kubernetes 上的金丝雀发布。Ingress 把 5% 的流量发往新版本,发布控制器把它的错误率和延迟与稳定版本对比,然后要么逐步提升流量,要么把全部流量切回 v1。

这张图的读法如下:

  • 上方,流量路径: 用户到达 Ingress,Ingress 把 95% 的请求发往稳定的 ReplicaSet,5% 发往金丝雀。两者都向指标系统上报数据。
  • 下方,控制回路: CI 把新镜像交给发布控制器。控制器设置 Ingress 的权重(虚线连线),读取两个版本的错误率和 p99 延迟,然后做出决定。
  • 决策: 在阈值之内就进入下一步;超出阈值就中止,并把全部流量切回 v1。
  • Markdown 块 列出了各个步骤和中止规则,这些内容应当纳入每个服务发布配置的评审。

功能开关是第四种策略

部署策略控制的是哪些服务器运行新代码。功能开关(feature flag)控制的是哪些用户看到新行为,与部署无关。频繁发布的团队会把两者结合起来:用滚动更新或金丝雀部署,把有风险的功能放在开关后面,再逐步打开开关。开关是更快的回滚方式,因为不需要重新部署任何东西。

部署图上应该画什么

  • 连线上的流量百分比。 它们在发布过程中会变化;画出第一步即可。
  • 谁来修改权重。 控制器、流水线还是某个人。
  • 中止条件。 写数字,而不是“看起来不对就停”。
  • 数据库, 并注明模式变更采用先扩展、后收缩的方式。

CI/CD 流水线图 展示了在此之前的构建和测试阶段,Kubernetes 架构图 介绍了集群本身,可观测性架构图 则展示了指标从何而来。

在 Archboard 中构建

  1. 使用 Google 或 GitHub 登录,并新建一张图。
  2. 添加一个 人员 表示用户,再添加 Kubernetes 节点包中的一个 Ingress 和两个 ReplicaSet 节点,分别表示稳定版和金丝雀。
  3. 添加 DevOps 节点包中的 指标 和一个 流水线,再添加 C4 模型节点包中的一个 容器 表示发布控制器。
  4. 添加流程图节点包中的一个 判断、一个 处理 和一个 开始 / 结束,表示提升和中止。
  5. 在 Ingress 的连线上标注流量权重,用虚线画出权重的调整,再添加一个基础节点包中的 Markdown 块,写明各个步骤。

这个示例共用 11 个图表节点,在 Free 套餐的限制之内。

常见问题

哪种部署策略最好? 取决于风险和工具。滚动更新适合大多数低风险变更;金丝雀适合坏版本代价高昂的面向用户的服务;蓝绿适合需要瞬间完整切换、并且负担得起双倍容量的系统。

蓝绿部署和金丝雀发布有什么区别? 蓝绿部署一次性切换全部流量,并保留旧环境以便即时回滚。金丝雀先移动一小部分流量,只有在新版本证明自己之后才扩大比例。

部署期间如何处理数据库迁移? 让每次模式变更都向后兼容:先扩展,部署同时兼容两种结构的代码,再在之后的版本中收缩。

金丝雀分析应该使用哪些指标? 与稳定版本对比的错误率和高百分位延迟,如果能快速测量,再加一个业务指标。

功能开关算一种部署策略吗? 它是一种发布策略。它把开启功能和部署代码解耦,并且能与三种部署策略中的任何一种很好地配合。

免费开始 — 1 个席位,无需信用卡。

相关文章

← 返回博客

一分钟打开画布

使用 Google 或 GitHub 登录。单席位免费,团队加入后再升级。