渐进式交付实践
本篇以一个支付服务为例,完整演示 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
清单中的关键字段如下:
| 字段 | 含义 | 运维注意事项 |
|---|---|---|
replicas | Rollout 期望的总副本数 | 发布期间新旧 ReplicaSet 可能同时占用容量 |
stableService | 稳定版本 Service 名称 | 不要与 Canary Service 共用同一个 selector 逻辑 |
canaryService | 金丝雀版本 Service 名称 | 用于流量提供者精确指向新版本 |
setWeight | 下一阶段的金丝雀流量比例 | 没有流量路由器时不代表真实百分比 |
pause | 暂停时间或无限期暂停 | 无限期暂停必须有明确的晋级责任人 |
trafficRouting | 调用 Istio、NGINX 等路由器 | 先验证入口流量确实经过该路由器 |
3. 发布步骤如何执行
Controller 会按以下顺序处理本示例:
- 创建或更新金丝雀 ReplicaSet,等待 Pod Ready;
- 将流量设置为 10%,进入 1 小时暂停;
- 暂停结束后提升到 30%,再次观察监控;
- 进入无限期暂停,等待负责人执行
promote; - 晋级后提高到 60%,继续观察 30 分钟;
- 最后提升到 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 同步再次覆盖现场。