Deployment 蓝绿部署与灰度发布:高级策略与排坑实战(下)

📅 2026/6/26 20:46:51
Deployment 蓝绿部署与灰度发布:高级策略与排坑实战(下)
上集我们搞懂了 Deployment 的三级结构、滚动更新策略调优、pause/resume 灰度验证和回滚全流程。但生产环境有时候滚动更新还不够——比如重大版本升级你想先全量验证再切流量或者高风险变更你想只让一小部分用户先踩坑。这时候蓝绿部署和灰度发布就派上用场了。下集聚焦三种发布策略的进阶对比、蓝绿/灰度手操全流程以及扩缩容和常见排坑。文章末尾会给出贯穿上下集的 10 条落地清单。一、蓝绿部署Blue/Green Deployment1.原理滚动更新是渐进替换蓝绿部署是全量切换——同时跑两套完整环境蓝旧版绿新版新版验证通过后一把切流量。┌─────────────┐ 用户 ──→ │ Service │ ──→ app: blue ──→ 蓝环境3个旧Pod └─────────────┘ │ ↓ 切换 selector ┌─────────────┐ 用户 ──→ │ Service │ ──→ app: green ──→ 绿环境3个新Pod └─────────────┘优点零停机风险可控——出问题切回蓝环境就行。缺点需要双倍资源切换是全量的新版本有问题影响全部用户。2.实战操作Step 1部署蓝环境当前版本 v1# 01-blue.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:app-bluespec:replicas:3selector:matchLabels:app:bluetemplate:metadata:labels:app:bluespec:containers:-name:appimage:nginx:1.22.1---apiVersion:v1kind:Servicemetadata:name:app-svcspec:type:NodePortselector:app:blue# ← 指向蓝环境ports:-port:80targetPort:80nodePort:30000kubectl apply-f01-blue.yamlStep 2部署绿环境新版本 v2——不接入流量# 02-green.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:app-greenspec:replicas:3selector:matchLabels:app:greentemplate:metadata:labels:app:greenspec:containers:-name:appimage:nginx:1.30.1kubectl apply-f02-green.yaml# 此时绿环境 Pod 在跑但没有 Service 指过来——不接收流量Step 3切换流量到绿环境# 改 Service selectorblue → greenkubectl patchserviceapp-svc-p{spec:{selector:{app:green}}}# 流量瞬间切到 v2whiletrue;docurl-sIhttp://192.168.91.21:30000|head-2;sleep1;done验证思路切之前while true; do curl nodeIP:30000; sleep 0.5; done切的一瞬间返回内容从 v1 变成 v2。出问题马上patch回app: blue即可。二、灰度发布金丝雀发布/Canary1.原理蓝绿是全量切换灰度是逐步导流——旧版本和新版本同时在线先让一小部分流量打到新版本确认没问题后逐步放大。核心思路两个 Deployment 用同一个 labelService 同时选中它们靠副本数比例控制流量分配。┌─────────────┐ 用户 ───→ │ Service │ ──→ app: web └─────────────┘ │ ┌────────┴────────┐ ↓ ↓ 旧 Deployment 新 Deployment replicas: 3 → 0 replicas: 1 → 3 (v1, 旧版) (v2, 新版)2.实战操作Step 1部署旧版本3副本100% 流量# 01-old.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:app-oldspec:replicas:3selector:matchLabels:app:webtemplate:metadata:labels:app:web# ← 同一个 labelspec:containers:-name:appimage:nginx:1.22.1---apiVersion:v1kind:Servicemetadata:name:app-svcspec:type:NodePortselector:app:web# ← 匹配两个 Deployment 的 Podports:-port:80targetPort:80nodePort:30000kubectl apply-f01-old.yamlStep 2部署新版本1副本~25% 流量# 02-new.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:app-newspec:replicas:1selector:matchLabels:app:webtemplate:metadata:labels:app:web# ← 同一个 labelspec:containers:-name:appimage:nginx:1.30.1kubectl apply-f02-new.yaml# 现在 4个 Pod3个old 1个newService 轮询负载约 75%/25% 分流Step 3观察 → 逐步切流# 观察新版本无异常后逐步调副本数kubectl scale deployment app-old--replicas2# 旧3→2流量比约 67%/33%kubectl scale deployment app-old--replicas1# 旧2→1流量比约 50%/50%kubectl scale deployment app-new--replicas3# 新1→3kubectl scale deployment app-old--replicas0# 旧1→0100% 流量到新版灰度 vs 蓝绿 vs 滚动更新对比方式切换方式资源占用回滚难度适用场景滚动更新渐进替换正常秒级rollout undo日常发布首选蓝绿部署全量切换双倍秒级切 selector重要版本升级灰度发布逐步导流递增秒级scale 回旧高风险变更三、扩缩容Deployment 的副本数可以随时调整两种方式1. 手动扩缩容# 扩容到 5 个副本kubectl scale deployment nginx--replicas5# 缩容到 2 个kubectl scale deployment nginx--replicas2底层就是改 RS 的replicas字段K8s 自动调度或回收 Pod。2. 自动扩缩容HPAHorizontal Pod Autoscaler 根据 CPU/内存指标自动调整副本数# 前置条件集群已安装 metrics-serverkubectl autoscale deployment nginx--min2--max10--cpu-percent80当 Pod 平均 CPU 使用率 80% → 自动增加副本当 Pod 平均 CPU 使用率 80% → 自动减少副本副本数始终在--min和--max之间# 查看 HPA 状态kubectl get hpa注意HPA 和手动 scale 会冲突。如果手动改了 replicasHPA 可能立刻改回来——统一用一个方式管理副本数。四、故障排查1.常见问题速查表现象可能原因排查方法Pod 始终 Pending资源不足 / 节点选择器不匹配kubectl describe pod看 Events更新卡在 Progressing镜像拉不下来 / 探针失败 / 资源不足kubectl describe pod 新Pod看 Events回滚报 revision not foundrevisionHistoryLimit清理了旧 RSkubectl rollout history确认保留范围滚动更新太慢maxSurge 和 maxUnavailable 都是 0一次只能更新 1 个 Pod适当调大 maxSurgeRecreate 导致服务中断Recreate先杀所有旧 Pod只有不兼容版本才用 Recreate2.详细排查2.1 回滚失败revision 已被清理kubectl rollout undo deployment/nginx --to-revision1# error: revision 1 not found in deployment nginx原因revisionHistoryLimit清理了旧 RS。预防重要 Deployment 适当调大。spec:revisionHistoryLimit:20# 保留20个历史版本2.2 更新卡住progressDeadlineSeconds 超时kubectl get deployment nginx# NAME READY UP-TO-DATE AVAILABLE AGE# nginx 2/3 2 2 5mkubectl describe deployment nginx# Conditions:# Type Status Reason# Progressing False ProgressDeadlineExceeded原因新 Pod 一直不 Ready镜像拉不下来、探针失败、资源不足。排查# 看 Pod 日志kubectl logs-f新Pod名称# 看 Pod Eventskubectl describe pod新Pod名称2.3 滚动更新太慢maxSurge: 0, maxUnavailable: 0→ 一次只更新1个Pod3副本要3轮。适当增大maxSurge或maxUnavailable。2.4 Recreate 策略导致服务中断Recreate会先杀所有旧Pod再建新Pod中间所有Pod不可用。只有在新旧版本真的不兼容时才用 Recreate否则永远用 RollingUpdate。五、总结一句话总结Deployment 滚动更新的本质是新 RS 扩容 旧 RS 缩容maxSurge/maxUnavailable 控制节奏旧 RS 保留是为了秒级回滚。日常发布首选滚动更新重要版本可用蓝绿或灰度兜底。落地清单核心业务 Deployment 设置maxSurge: 1, maxUnavailable: 0设置minReadySeconds: 30防止 Pod 刚 Ready 就被计入可用重要 Deployment 调大revisionHistoryLimit: 20用kubectl annotate记录每次变更原因不要依赖已弃用的--record灰度场景用rollout pauserollout resume手动控制节奏回滚前先rollout history确认目标 revision 还在重大版本升级考虑蓝绿部署先部署新版 → 验证 → 切 Service selector高风险变更用灰度发布两个 Deployment 同 label靠副本数比例控流Recreate 策略只在新旧版本不兼容时使用HPA 和手动 scale 二选一不要混用