跳到主要内容

渐进式交付实践

本篇以一个支付服务为例,完整演示 Argo Rollouts 的 Canary 发布。目标不是记住一份 YAML,而是理解发布过程中每一个对象和状态如何配合:新 ReplicaSet 先启动,流量按权重切分,指标和人工确认通过后再继续放量。

1. 发布前准备​

在创建 Rollout 前至少确认:

  • 镜像使用不可变 tag 或 digest,不使用 latest;
  • 稳定 Service、Canary Service 和流量路由规则已经存在或由同一批清单管理;
  • Pod 有可靠的 readinessProbe,否则 Controller 可能把“进程启动”误判为“服务可用”;
  • Prometheus、日志和业务探针能区分稳定版本与金丝雀版本;
  • 回滚不依赖数据库不可逆迁移,数据库变更遵循向前兼容策略。

2. Canary Rollout 清单​

下面的示例使用 Istio VirtualService 按比例切分流量。stableService 和 canaryService 必须与 VirtualService 的路由配合,具体字段会随流量提供者不同而变化。

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: payment-service
namespace: default
spec:
replicas: 5
strategy:
canary:
# 用于灰度流量比例划分的服务与路由定义
stableService: payment-stable-svc
canaryService: payment-canary-svc
trafficRouting:
istio:
virtualService:
name: payment-vs
routes:
- primary # 对应 virtualService 中的路由名
# 灰度发布的具体步骤
steps:
- setWeight: 10 # 1. 引入 10% 的生产流量到新版本中
- pause: {duration: 1h} # 2. 暂停 1 小时,由运维和测试观察监控/APM
- setWeight: 30 # 3. 流量提升到 30%
- pause: {} # 4. 无时间限制暂停,等待运维通过 CLI 手动点击确认继续
- setWeight: 60 # 5. 提升到 60%
- pause: {duration: 30m}
- setWeight: 100 # 6. 100% 发布,完成旧版本 Pods 的平滑回收
template:
metadata:
labels:
app: payment-service
spec:
containers:
- name: app
image: registry.company.com/apps/payment-service:v2.0.0
ports:
- containerPort: 8080

清单中的关键字段如下:

字段含义运维注意事项
replicasRollout 期望的总副本数发布期间新旧 ReplicaSet 可能同时占用容量
stableService稳定版本 Service 名称不要与 Canary Service 共用同一个 selector 逻辑
canaryService金丝雀版本 Service 名称用于流量提供者精确指向新版本
setWeight下一阶段的金丝雀流量比例没有流量路由器时不代表真实百分比
pause暂停时间或无限期暂停无限期暂停必须有明确的晋级责任人
trafficRouting调用 Istio、NGINX 等路由器先验证入口流量确实经过该路由器

3. 发布步骤如何执行​

Controller 会按以下顺序处理本示例:

  1. 创建或更新金丝雀 ReplicaSet,等待 Pod Ready;
  2. 将流量设置为 10%,进入 1 小时暂停;
  3. 暂停结束后提升到 30%,再次观察监控;
  4. 进入无限期暂停,等待负责人执行 promote;
  5. 晋级后提高到 60%,继续观察 30 分钟;
  6. 最后提升到 100%,旧版本 ReplicaSet 按策略缩容。

setWeight 是发布步骤,不是指标判断。若要让错误率或延迟自动阻止放量,需要在步骤中加入 analysis,见 Analysis 与流量治理。

4. 查看发布状态​

使用 kubectl-argo-rollouts 插件查看当前步骤、稳定/金丝雀 ReplicaSet 和暂停原因:

# 查看 Rollout 状态、当前步骤和暂停信息
kubectl argo rollouts get rollout payment-service -n default

# 持续观察变化;发布窗口中建议保留终端记录
kubectl argo rollouts get rollout payment-service -n default --watch

# 查看 Rollout 管理的 ReplicaSet 和 Pod
kubectl argo rollouts list replicasets payment-service -n default
kubectl get pods -n default -l app=payment-service -o wide

如果使用 Istio,还应同时检查路由权重是否变化:

kubectl get virtualservice payment-vs -n default -o yaml
kubectl get destinationrule payment-dr -n default -o yaml

5. 暂停、晋级、终止与重试​

# 在无限期 pause 步骤中继续发布
kubectl argo rollouts promote payment-service -n default

# 终止当前发布,让流量回到稳定版本;不要把 abort 当成删除 Rollout
kubectl argo rollouts abort payment-service -n default

# 对中止后的 Rollout 重新执行发布流程
kubectl argo rollouts retry payment-service -n default

# 发布完成后查看历史版本
kubectl argo rollouts history rollout payment-service -n default

abort 只适合已确认新版本存在问题的场景。若只是想暂时观察,应使用 pause;若发布已经失败,应先查看 AnalysisRun、Pod 事件和路由状态,再决定 retry 还是回滚。

6. 回滚策略​

优先通过 Git 回退镜像版本,让 Argo CD 重新同步,这是可审计的长期修复路径。紧急情况下可以使用 Rollouts CLI 触发回滚或终止当前版本,但事后必须把等效变更写回 Git:

# 查看历史版本和对应 ReplicaSet
kubectl argo rollouts history rollout payment-service -n default

# 紧急回退到上一版本;具体参数以客户端版本帮助为准
kubectl argo rollouts undo payment-service -n default

# 观察回退后的健康状态
kubectl argo rollouts get rollout payment-service -n default --watch
数据库迁移必须可兼容回滚

应用版本可以回滚,不代表数据库结构可以回滚。生产发布前应让旧版本和新版本在迁移窗口内都能读取数据,并把不可逆迁移拆成多个兼容步骤。

7. 常见误区​

  • 只看 kubectl get pods,不看实际入口流量和路由权重;
  • 把 setWeight: 10 理解成所有请求必然有 10% 到达金丝雀;
  • 没有设置 readinessProbe 就让 Rollout 自动晋级;
  • 使用无限期 pause 却没有发布窗口和通知责任人;
  • CLI 紧急回滚后不回写 Git,导致下一次 Argo CD 同步再次覆盖现场。