阶段二 · GitOps 持续交付

渐进式交付

一句话总结

就算 GitOps 让部署变得自动又可回滚,一次"全量替换"仍会把坏版本瞬间送到 100% 用户面前;
渐进式交付让新版本先接一小撮流量,看监控指标,确认健康再逐步放量,把发布风险关进一个可控的小笼子里.

前置回顾

第 05 篇我们让 ArgoCD 自动把新镜像同步上集群--但默认用的是 Deployment 的滚动更新:新 Pod 起,旧 Pod 撤,几分钟内全部换成新版本.问题是:如果新版本有个只在生产真实流量下才暴露的 bug,它会立刻影响所有用户,等你 git revert 回滚,损失已经造成.本篇是阶段二的收尾,补上"发布"这一步本身的安全网.

回滚很快,但"已经炸了"才回滚就晚了

先把第 05 篇的能力和它的盲区说清楚.GitOps 给了我们出色的事后 能力:

10:00  新版本 v2 全量上线(滚动更新,几分钟内 100% 切换)
10:03 错误率从 0.1% 飙到 8%,用户开始投诉
10:06 有人发现告警 → git revert → ArgoCD 同步回 v1
10:09 恢复

这 6 分钟里,8% 的请求全挂了 -- 全量用户都被波及

问题不在"回滚慢"(GitOps 已经够快),而在**"全量"**:新版本一上来就面向所有人,爆炸半径(Blast Radius)是 100%.渐进式交付换一个思路--别让坏版本有机会面向所有人.

全量发布像让全城同时喝一口新配方的水,有问题就是全城中招.渐进式交付像先给一个小区试饮,监测健康指标,没问题再逐步推广到全城--出问题最多影响那一个小区,且在扩大前就被拦住.

两种核心策略:蓝绿与金丝雀

渐进式交付有两条主线策略,先建立直觉,再看工具.

蓝绿发布(Blue-Green)

同时存在两套完整环境:蓝(旧版本,正在服务)和绿(新版本,已部署但不接流量).验证绿没问题后,把流量一次性从蓝切到绿.

蓝绿:两套并存,流量整体切换

切换前:  用户 ──100%──▶ [蓝 v1]      [绿 v2] 已就绪,0 流量,内部验证中
切换后: 用户 ──100%──▶ [绿 v2] [蓝 v1] 保留待命(出事秒切回)
  • 优点:切换瞬间完成;旧环境(蓝)还留着,回滚就是把流量切回去,秒级;新版本上线前可以在绿环境充分内测.
  • 代价:发布期间要两倍资源(两套完整环境同时存在);流量仍是"一刀切",切过去那一下,所有用户同时进入新版本--只是回退更快.

金丝雀发布(Canary)

名字来自矿工带金丝雀下井--金丝雀对毒气敏感,先它出事,矿工就知道该撤了.金丝雀发布让新版本先接一小撮流量(比如 5%),其余仍走旧版本;观察新版本的指标,健康就逐步加大比例(5%→20%→50%→100%),任一步异常就停下回退.

金丝雀:新版本按比例逐步放量

第1步:  旧 v1 ◀─95%─ 用户 ─5%─▶ 新 v2   观察指标...健康✓
第2步: 旧 v1 ◀─80%─ 用户 ─20%─▶ 新 v2 观察指标...健康✓
第3步: 旧 v1 ◀─50%─ 用户 ─50%─▶ 新 v2 观察指标...健康✓
完成: 用户 ─100%─▶ 新 v2,撤掉旧版本
(任一步指标恶化 → 立即停止放量并回退,只有少数用户被波及)
蓝绿 金丝雀
流量切换 一次性整体切 按比例逐步放
爆炸半径 切换后即 100% 始终只有当前放量比例
资源开销 高(两套并存) 低(只多出金丝雀那几个 Pod)
回滚速度 秒级(切回蓝) 快(停止放量)
适合 要快速整体切换/充分预发验证 要最小化爆炸半径,用真实流量灰度

点睛之笔:用监控指标自动决策

到这里你可能发现一个关键问题:金丝雀"观察指标,健康才放量"--谁来观察?靠人盯着监控大盘点鼠标吗? 那就又回到了"依赖人"的老路(第 01 篇的核心矛盾).

渐进式交付真正的威力,在于把"看指标做决策"也自动化.发布工具在每一步放量后,自动查询监控系统(Prometheus 等)的关键指标,和预设阈值比对:

每放量一步,自动分析(analysis):
查询新版本的: 错误率 < 1% ?
P99 延迟 < 300ms ?
...
├── 全部达标 → 自动进入下一步,加大流量
└── 任一不达标 → 自动停止 + 回退,无需人介入半夜爬起来

这一步把渐进式交付和前面所有内容连成了闭环:第 04 篇的"质量门禁"管的是上线前(代码,镜像够不够格),而这里的"指标门禁"管的是上线中(真实流量下表现好不好).两者是同一种哲学--设好客观标准,让机器自动判断放行还是拦截--只是战场从流水线挪到了生产环境.

手动调流量比例,人肉看大盘,顶多算"灰度发布".渐进式交付(Progressive Delivery)的精髓是自动化的指标驱动决策:放量,分析,晋级或回退,全程由工具按客观指标执行.人只需要事先定义好"什么叫健康",剩下的交给机器--这正是 DORA 指标里"变更失败率"和"恢复时间"能同时压低的原因.

工具:Argo Rollouts 与 Flagger

原生的 K8s Deployment 只会"滚动更新",不会做按比例放量 + 指标分析.这需要专门的控制器,两个主流选择:

Argo Rollouts Flagger
出身 Argo 生态(和第 05 篇 ArgoCD 同门) Flux 生态
做法 提供新资源 Rollout 替代 Deployment 在现有 Deployment 旁加 Canary 资源驱动
策略 金丝雀,蓝绿都支持 金丝雀,蓝绿,A/B 都支持

以 Argo Rollouts 为例,它用一个 Rollout 资源(用法几乎和 Deployment 一样)声明放量步骤和指标分析:

apiVersion: argoproj.io/v1alpha1
kind: Rollout # ← 替代 Deployment
metadata:
name: myapp
spec:
replicas: 6
strategy:
canary: # 金丝雀策略
steps:
- setWeight: 5 # 1. 先给新版本 5% 流量
- pause: {duration: 5m} # 停 5 分钟观察
- analysis: # 2. 自动查指标(见下),不达标则中止回退
templates:
- templateName: success-rate
- setWeight: 20 # 3. 健康 → 放到 20%
- pause: {duration: 5m}
- setWeight: 50 # 4. 再到 50% ... 直至 100%
# template/selector 部分和 Deployment 写法一致
# AnalysisTemplate:定义"什么叫健康"--查 Prometheus 的成功率
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
metrics:
- name: success-rate
interval: 1m
successCondition: result[0] >= 0.99 # 成功率 ≥ 99% 才算通过
failureLimit: 2 # 累计 2 次不达标 → 判定失败,自动回退
provider:
prometheus:
address: http://prometheus.monitoring:9090
query: |
sum(rate(http_requests_total{job="myapp",status!~"5.."}[2m]))
/ sum(rate(http_requests_total{job="myapp"}[2m]))

提交后,Argo Rollouts 就自动执行"放 5% → 等 5 分钟 → 查成功率 → 达标则放 20%..."的全过程,任一步成功率掉到 99% 以下且累计两次,立即自动回退.你定义标准,它替你值夜班.

流量怎么精确切成 5% / 20%?

按比例切流量靠的是流量管理层:服务网格(Istio/Linkerd)或 Ingress(Nginx,Gateway API).Rollouts/Flagger 不自己转发流量,而是去动态调整这些组件的权重配置--比如改 Istio VirtualService 的 weight.这正好衔接 Kubernetes 笔记里的 Service / Ingress / Gateway API:渐进式交付是建立在那套七层流量管理之上的上层能力.

把阶段二三篇连起来

阶段二完整地回答了"可信镜像怎么安全地变成生产流量"这件事,三篇各管一层:

┌─────────────────┐
│ 阶段一产出:可信镜像 :sha │
└─────────────────┘


┌─────────────────────────────────────────┐
│ 第06篇 Helm/Kustomize<br/>把镜像 tag 写进各环境配置 │
└─────────────────────────────────────────┘


┌─────────────────────────────────────────┐
│ 第05篇 GitOps/ArgoCD<br/>Git 改动 → 自动同步到集群 │
└─────────────────────────────────────────┘


┌──────────────────────────────────┐
│ 第07篇 渐进式交付<br/>金丝雀/蓝绿 + 指标分析逐步放量 │
└──────────────────────────────────┘


┌───────────┐
│ 健康 → 全量上线 │
└───────────┘
  • 第 06 篇解决"配置怎么按环境组织"--决定部署什么
  • 第 05 篇解决"配置怎么自动同步上集群"--决定怎么送上去
  • 第 07 篇解决"上线这一下怎么不炸"--决定怎么安全地放出去

三者叠加,你就拥有了一条从提交代码到安全上线,全程自动,出事自动止损的现代交付流水线.阶段三会再往下一层:连承载这一切的基础设施本身,也用同样的声明式思想管起来.

快速回顾

  • GitOps 回滚快,但救不了"全量瞬间炸":全量发布的爆炸半径是 100%,坏版本一上来就波及所有用户
  • 蓝绿:两套环境并存,流量一次性切换,回滚秒级,但费两倍资源,切换仍是一刀切
  • 金丝雀:新版本按比例逐步放量(5%→20%→...),爆炸半径始终等于当前放量比例,资源开销小
  • 点睛:指标驱动自动决策--每步放量后自动查 Prometheus 指标,达标晋级,不达标自动回退,无需人盯盘;这是"渐进式交付"区别于手动灰度的本质
  • 工具:Argo Rollouts(同 ArgoCD 生态,用 Rollout 替代 Deployment)/ Flagger;靠服务网格或 Ingress 精确切流量
  • 与门禁同源:第 04 篇管上线前,本篇管上线中,都是"设客观标准,让机器自动放行或拦截"

金丝雀放量期间,新旧版本同时在线,数据库 schema 不兼容怎么办?

这是渐进式交付(以及蓝绿)绕不开的硬约束:既然新旧版本会同时读写同一个数据库,数据库变更就必须向后兼容.常用做法是"扩展-收缩(expand-contract)":先只字段/表(旧版本无视它,照常工作),等新版本全量,旧版本下线后,再在后续版本里旧字段.绝不能在一次发布里做"重命名/删列"这种破坏性变更--否则放量期间旧版本会直接崩.

小团队,流量不大,有必要上渐进式交付吗?

看风险承受度,不必一步到位.可以分层采用:流量小但怕停服 → 用蓝绿(实现简单,留个旧环境能秒切回)就够了;只有当"全量出事的代价高,且有 Prometheus 监控能定义健康指标"时,自动金丝雀才物有所值.别为了用而用--它的复杂度(服务网格,指标体系)是实实在在的成本,要和它防住的风险匹配.

动手练习

  1. 本地金丝雀部署 在 k3d 集群装 Argo Rollouts(含它的 kubectl 插件),把一个普通 Deployment 改写成 Rollout,配置 setWeight: 25 → pause → 50 → 100 的金丝雀步骤.
  2. 观察放量过程kubectl argo rollouts get rollout myapp --watch 观察一次发布:看流量比例如何一步步爬升,每步如何暂停.
  3. 手动回退测试 在某个 pause 步骤,故意把镜像换成一个会崩的版本,手动 abort,确认它停止放量并回退,体会"爆炸半径只在金丝雀那一小撮".
  4. 自动指标分析(进阶) 接上 Prometheus,写一个基于成功率的 AnalysisTemplate,制造一段高错误率,验证 Rollouts 自动 判定失败回退--全程不用你点.
  5. 蓝绿策略对比 把同一个应用改成蓝绿策略再发一次,对比两种策略在资源占用和切换体验上的差异.