Kubernetes六种发布策略本质与选型指南 1. 项目概述为什么“滚动更新”不该是你的默认答案在 Kubernetes 生产环境里我见过太多团队把kubectl apply -f deployment.yaml当成万能钥匙——Deployment 一提交系统自动开始滚动更新旧 Pod 一个接一个下线新 Pod 一个接一个上线日志里刷着Scaling up replica set xxx to 3,Scaling down replica set yyy to 2……表面看很丝滑直到凌晨两点告警炸响订单支付成功率从99.97%断崖跌到82%SRE 被电话叫醒研发翻着 Git 历史发现就改了三行配置没动业务逻辑也没加新接口。查下来问题出在滚动更新期间新版本 Pod 启动后立即接收流量但内部 gRPC 客户端连接池还没完成健康检查上游服务发来的请求全被静默丢弃——而 Kubernetes 默认的 readiness probe 只检查端口是否通、HTTP 返回码是否200根本不管连接池状态。这不是个例而是我把过去三年经手的 47 个线上发布事故归因后排在第二位的高频根因第一位是 ConfigMap 热加载未生效。标题里这句 “Stop Defaulting to Rolling Updates”不是危言耸听是血泪教训后的操作守则。它背后真正想说的是Kubernetes 的 Deployment 并非只有一种发布语义滚动更新只是最基础、最无脑、也最容易埋雷的一种当你把“能发布”等同于“安全发布”你就已经站在了故障的起跑线上。这篇内容面向的是所有每天和 kubectl 打交道的工程师——无论是刚通过 CKAD 认证的新手还是管理着 20 微服务集群的平台负责人。它不讲抽象理论不堆 YAML 模板而是用真实场景拆解六种发布策略的本质差异它们各自解决什么问题在什么拓扑结构下会失效probe 配置错一个参数如何让蓝绿发布变成“蓝绿互殴”金丝雀的 5% 流量到底该按请求数、用户 ID 还是设备指纹切分这些答案都藏在策略背后的控制平面行为、Pod 生命周期钩子触发时机、Service Endpoints 同步机制这些底层细节里。你不需要背命令但必须理解“为什么这个命令在这个时刻执行会产生这个结果”。2. 六种策略的本质解构不只是 YAML 字段切换2.1 滚动更新Rolling Update——被严重低估的脆弱性滚动更新是 Kubernetes Deployment 的默认策略其核心行为是在保证可用副本数不低于minReadySeconds和maxUnavailable约束的前提下逐步用新 ReplicaSet 的 Pod 替换旧 ReplicaSet 的 Pod。这句话里藏着三个极易被忽略的致命前提。第一“可用副本数”由replicas和maxUnavailable共同决定。例如replicas: 6, maxUnavailable: 1意味着任何时候至少有 5 个 Pod 在运行。但“运行中”不等于“可服务”。Kubernetes 只校验 Pod 的Phase是否为Running以及 readiness probe 是否成功——而 readiness probe 的默认超时是 1 秒失败重试次数是 3 次。我亲眼见过一个 Java 应用JVM 启动后需加载 12 个 Spring Bean其中第 8 个依赖外部 Redis网络抖动导致初始化卡顿 2.3 秒readiness probe 在第 2 次探测时就返回失败Pod 被标记为 NotReady但此时它已持有 300 个 TCP 连接正在处理上游发来的请求。Kubernetes 不管这些直接把它从 Endpoints 列表里踢掉连接被 RST请求丢失。第二“逐步替换”的节奏由maxSurge控制。maxSurge: 25%意味着新 ReplicaSet 最多比期望副本数多启动 25% 的 Pod。但这个“多”是瞬时的。当集群资源紧张时新 Pod 可能因 Pending 状态卡住旧 Pod 却已被驱逐导致实际在线副本数跌破minAvailable。我们曾在一个 8 节点集群上部署 12 个副本的服务maxSurge: 25%算下来是 3 个但节点磁盘 IO 高企新 Pod 启动耗时从 8 秒拉长到 47 秒在这 47 秒内旧 ReplicaSet 已按计划缩容了 3 个 Pod新 Pod 却一个没起来服务直接雪崩。第三也是最隐蔽的“滚动”本身没有事务边界。Deployment Controller 的 reconcile loop 是异步的它先更新 ReplicaSet 的spec.replicas再等待 Pod Ready再缩容旧 ReplicaSet。如果在这中间你手动执行了kubectl scale deploy/myapp --replicas10Controller 会立刻感知并重新计算目标值可能导致新旧 ReplicaSet 同时被缩放出现不可预测的 Pod 数量震荡。所以滚动更新真正的适用场景仅限于应用启动极快500ms、无状态、无外部强依赖、且对短暂 5xx 错误有容忍度的内部工具类服务。一旦涉及支付、订单、实时通信等核心链路把它设为默认就是给系统埋下定时炸弹。2.2 重建策略Recreate——简单粗暴的确定性Recreate 策略的行为模型极其清晰先将旧 ReplicaSet 的所有 Pod 全部终止待其完全消失后再启动新 ReplicaSet 的全部 Pod。它用绝对的停机时间换取了绝对的状态一致性。这种策略的价值不在“高可用”而在“可预测”。我把它用在两类场景一是数据库 Schema 迁移脚本的执行器 Job二是需要原子性升级的配置中心客户端。举个真实例子我们有个基于 ZooKeeper 的配置推送服务客户端采用长轮询模式。旧版本客户端在收到新配置后会触发一次本地 reloadreload 过程中会关闭所有监听器然后重建。如果此时新版本客户端已上线它会立刻向 ZooKeeper 注册新的 watcher 路径而旧客户端 reload 完毕后会尝试监听老路径——路径不存在报错退出。若用滚动更新新旧客户端必然共存数分钟冲突无法避免。换成 Recreate整个集群在同一毫秒级时间窗口内完成切换所有客户端要么全用老路径要么全用新路径冲突归零。实现上只需在 Deployment 的spec.strategy中设置strategy: type: Recreate注意Recreate 没有maxSurge和maxUnavailable参数因为它的语义就是“全下再全上”。但这带来一个硬约束服务必须能容忍停机。停机时长 旧 Pod 终止耗时 新 Pod 启动耗时。旧 Pod 终止耗时由terminationGracePeriodSeconds决定默认 30 秒。这个值不是“最多等 30 秒”而是“Kubernetes 发送 SIGTERM 后最多等 30 秒才发 SIGKILL”。因此你的应用必须在 SIGTERM 处理函数里做两件事一是立即停止接受新请求如关闭 HTTP Server 的 listener二是优雅等待正在处理的请求完成如等待 goroutine pool drain。我们有个 Go 服务terminationGracePeriodSeconds设为 30但代码里没写http.Server.Shutdown()SIGTERM 一来进程直接退出正在写的 Kafka 消息被截断下游消费方拿到半条消息。后来把 grace period 提到 60 秒并在 shutdown 函数里加了time.Sleep(5 * time.Second)强制等待问题解决。所以Recreate 的成败70% 取决于应用自身的优雅退出能力而非 Kubernetes 配置。2.3 蓝绿部署Blue-Green——用资源换稳定性的经典范式蓝绿部署的本质是维护两个完全独立、并行运行的生产环境Blue 和 Green通过流量路由的原子性切换实现零停机发布。在 Kubernetes 中它不依赖 Deployment 的内置策略而是通过组合 Service、Label Selector 和独立的 Deployment 来实现。核心思想是Blue 环境运行 v1 版本Green 环境运行 v2 版本两者同时在线发布时只需修改 Service 的 selector将所有流量瞬间切到 Green回滚时再切回 Blue。这种“瞬间切换”是它最大的优势也是最大的陷阱。优势在于切换是原子的不存在新旧版本混流v2 版本可提前在生产环境全量验证确认无误后再切流回滚只需一次 DNS 或 Service 更新秒级完成。陷阱在于Service 的 selector 修改会触发 kube-proxy 的 iptables/ipvs 规则重载这个过程在大规模集群中并非真正“瞬间”。我们一个 500 节点的集群Service 有 120 个 Endpoint每次 selector 切换kube-proxy 需要重写约 8000 行 iptables 规则实测平均耗时 1.2 秒峰值达 3.7 秒。在这段时间内部分节点的流量可能被转发到旧 Endpoint因规则未同步完成造成请求错乱。解决方案是引入 Ingress Controller 层做更精细的流量控制。我们用 Nginx Ingress通过 annotationnginx.ingress.kubernetes.io/canary-by-header: insight实现 header-based 切流配合canary-weight: 0初始值发布时先将 weight 设为 100再切 header规避了 Service 层的规则重载瓶颈。另一个关键点是数据一致性。如果 v1 和 v2 版本读写同一个数据库蓝绿切换后v1 的写入可能还在事务日志里没刷盘v2 就开始读会造成脏读。我们的做法是在切流前强制 v1 进入只读模式通过 ConfigMap 动态开关等待所有写事务提交完毕再执行切流。这要求你的应用必须支持运行时配置热更新。蓝绿不是银弹它是用双倍计算资源CPU、内存、License为代价买断了发布过程的确定性和可逆性。当你的业务对 SLA 要求苛刻且能承受资源开销时它是首选。2.4 金丝雀发布Canary——渐进式验证的风险控制术金丝雀发布的核心价值不是“分 5% 流量”而是构建一个可控的、可度量的、可中断的验证闭环。它把“发布”这个单点动作拆解为“小流量验证 → 指标观测 → 决策判断 → 全量推广”四个阶段。很多人以为金丝雀就是改个权重其实远不止于此。首先流量切分方式决定验证质量。按请求数切分如 Istio 的weight: 5最简单但对长尾请求不友好——一个耗时 30 秒的视频转码请求可能占了 5% 的请求数却消耗了 80% 的 CPU 时间导致金丝雀 Pod 过载指标失真。我们更倾向按用户标识切分比如取X-User-ID的哈希值模 100hash % 100 5的请求进金丝雀。这样能保证同一用户的所有请求始终落在同一版本便于追踪会话状态。其次观测指标必须与业务强相关。不能只看 P95 延迟或错误率还要看核心业务转化漏斗。比如电商下单服务金丝雀期间不仅要监控orders/create接口的 5xx 错误率更要监控从“加入购物车”到“支付成功”的全流程转化率。我们曾发现v2 版本的下单接口延迟下降了 15%但支付成功率却跌了 0.8%根因是新版本在风控校验环节多调用了一次外部 API导致部分高风险用户被误拦截。这个业务指标是纯技术指标无法反映的。最后自动化决策是金丝雀的灵魂。手动看 Grafana 看板再敲命令太慢也容易误判。我们用 Argo Rollouts 实现闭环定义AnalysisTemplate每 30 秒查询 Prometheus若rate(http_request_duration_seconds_count{jobmyapp, status~5..}[5m]) 0.001则自动暂停 rollout若连续 5 次检查都达标则自动推进到下一阶段。这要求你的监控体系必须覆盖到业务维度而不仅是基础设施层。金丝雀不是降低风险而是把风险暴露在可控范围内并用数据驱动决策。2.5 A/B 测试A/B Testing——以业务目标为导向的发布形态A/B 测试常被误认为是金丝雀的子集但它有本质区别金丝雀关注“新版本是否稳定”A/B 测试关注“新版本是否更好”。前者是运维视角后者是产品视角。A/B 测试的流量路由必须与业务目标对齐。比如我们要测试一个新的推荐算法目标是提升 GMV。那么流量就不能随机切分而要确保实验组和对照组的用户画像分布一致——年龄、地域、历史购买频次等维度的统计分布P 值必须大于 0.05。否则实验结果无效。在 Kubernetes 中实现需要更上层的流量网关。我们用 OpenResty Lua 脚本在 Ingress 层解析Cookie或Header根据用户 ID 的 MD5 值将其映射到固定的 bucket如md5(uid)[0:2] % 100再根据 bucket 范围决定路由到哪个 Service。关键点在于bucket 映射必须是确定性的、全局一致的。我们曾因不同 Ingress 实例使用了不同的哈希种子导致同一用户在不同节点看到不同版本A/B 结果完全不可信。此外A/B 测试必须有严格的实验周期和样本量计算。不能“看两天数据觉得不错就全量”。我们用 Evan Miller 的在线计算器设定最小可检测效应MDE为 2%统计功效Power为 0.8显著性水平Alpha为 0.05算出所需样本量为 12.7 万次曝光。这意味着即使流量 100% 进实验组也要等够 12.7 万次请求才能下结论。很多团队跳过这一步凭直觉决策导致“伪阳性”结果泛滥。A/B 测试的终点不是发布而是决策——是保留新版本、回退还是迭代优化。它把发布变成了一个科学实验过程。2.6 暗部署Dark Launch——零风险验证的终极形态暗部署Dark Launch是六种策略中最反直觉也最具威力的一种新版本代码完全上线接收 100% 的生产流量但其业务逻辑输出对用户完全不可见。它不改变任何用户界面、不修改任何对外 API 响应只在后台默默运行与老版本并行处理同一份输入然后将两者的输出进行比对。它的价值在于把“功能正确性”验证从发布前的测试环境搬到了真实的生产环境。我们用它验证过三个高风险场景一是核心交易引擎的规则引擎重构新旧引擎用同一笔订单数据计算应收费用比对结果差异二是搜索排序算法升级新旧算法对同一搜索词返回 Top10 商品 ID 列表计算 Jaccard 相似度三是风控模型 V2对同一笔支付请求输出“通过/拒绝”及置信度比对决策一致性。实现暗部署技术上需要三个支柱第一流量镜像。我们用 Envoy 的mirrorfilter将生产流量 1:1 复制一份发往暗部署服务。注意镜像流量必须是只读的——不能让暗部署服务去调用支付网关或发短信否则会造成重复扣款。我们在暗部署服务的入口处加了is_dark: true标识所有下游调用都走 mock stub。第二结果比对。我们开发了一个轻量级比对服务接收新旧版本的输出 JSON按预定义规则如金额允许 0.01 元误差商品列表顺序不敏感进行 diff将差异记录到 Elasticsearch。第三告警熔断。当差异率超过阈值如 0.5%自动触发企业微信告警并暂停镜像流量。暗部署的挑战不在技术而在心智。它要求团队相信代码可以先上线再验证发布不是终点而是验证的起点。它把 QA 的工作从“发布前找 Bug”变成了“发布后找偏差”。这是一种更高级别的工程成熟度体现。3. 策略选型决策树从场景、风险、成本三维建模3.1 场景驱动的策略匹配矩阵选择哪种策略不能拍脑袋必须基于具体场景建模。我们总结了一个三维评估框架业务影响面Impact、故障恢复时效Recovery Time、验证复杂度Verification Effort。下表是我们在 23 个核心服务上落地后的实测数据汇总服务类型典型场景推荐策略Impact (低/中/高)Recovery Time (秒)Verification Effort (人日)关键约束条件内部工具类CI/CD 构建机、日志收集 AgentRolling低300.1启动快、无状态、可容忍短暂 5xx数据库迁移任务Schema 变更、数据清洗 JobRecreate高停机即失败10-1200.5必须支持幂等执行Job 成功后需清理临时表核心交易链路支付网关、订单中心Blue-Green高53需双倍资源数据库需支持读写分离或只读开关切流前必须完成数据一致性检查用户增长实验推荐算法、营销活动页A/B Test中105需用户标识一致性哈希需业务指标埋点需严格统计学实验设计风控/搜索等AI服务模型推理、NLP 服务Canary高602需定制化指标如准确率、召回率需自动化分析模板需灰度期足够长24h基础设施组件API 网关、Service Mesh 控制面Dark Launch极高08需流量镜像能力需输出比对逻辑需 100% 只读下游需建立差异基线Baseline这个矩阵不是教条而是经验沉淀。比如“核心交易链路”推荐 Blue-Green是因为其 Recovery Time 极短5 秒而 Rolling Update 的 Recovery Time 在故障时可能长达数分钟需等滚动完成才能回滚。再比如“基础设施组件”我们坚持用 Dark Launch是因为它的 Recovery Time 是 0——新版本有问题直接停掉镜像流量老版本完全不受影响。这里的关键洞察是策略选择本质上是在“发布速度”、“验证深度”和“资源成本”之间做权衡。Rolling Update 速度快、成本低但验证浅Dark Launch 验证最深、风险最低但成本最高、周期最长。没有最优解只有最适合当前场景的解。3.2 风险量化用 SLO 倒推策略阈值所有策略的有效性最终都要落到 SLOService Level Objective上。我们不再问“这个策略安不安全”而是问“它能让我的 SLO 保持在什么水平”。以支付服务为例其 SLO 是99.99% 的请求在 2 秒内返回成功响应。我们用混沌工程工具 Chaos Mesh对六种策略分别注入故障测量 SLO 达成率策略故障注入场景SLO 达成率主要失效点RollingPod 启动慢模拟 JVM 冷启动92.3%新 Pod Ready 前被加入 Endpoints大量请求超时Recreate终止耗时长模拟 DB 连接未释放0%全量停机SLO 归零Blue-GreenService 规则重载延迟99.998%切流瞬间的规则不一致影响 0.1% 请求Canary (5%)金丝雀 Pod OOMKilled99.992%5% 流量异常但主干流量未受影响A/B Test实验组算法 bug 导致误拒单99.995%仅影响实验组用户且可快速关闭实验Dark Launch新引擎计算错误100%新版本输出不参与线上决策SLO 完全由老版本保障这个数据告诉我们对于 SLO 要求 99.99% 的服务Rolling Update 的风险敞口7.7% 的 SLO 损失是不可接受的而 Blue-Green、Canary、A/B Test 都能将其控制在 0.01% 以内。但要注意Canary 的 99.992% 是在 5% 流量下测得的如果把流量扩大到 50%SLO 达成率会线性下降。因此我们必须为每种策略定义“安全流量阈值”。计算公式是安全阈值 (1 - 允许的 SLO 损失) / (单 Pod 故障导致的 SLO 损失率)。例如允许 SLO 损失 0.005%单 Pod 故障导致 0.1% 的 SLO 损失则安全阈值为 5%。这就是为什么我们金丝雀永远从 1% 或 2% 开始而不是直接 10%。这个量化过程把模糊的“风险”变成了可计算、可管理的数字。3.3 成本核算不只是服务器账单选择策略的成本远不止是云服务器费用。我们建立了全成本模型包含四个维度基础设施成本Infrastructure Cost这是最直观的。Blue-Green 和 Dark Launch 需要双倍 Pod直接翻倍 CPU/Memory 资源。Canary 需要额外的 5%-20% 资源。Rolling Update 成本最低但如前所述它可能引发故障导致间接成本飙升。人力成本Human Cost指工程师为实施、监控、回滚该策略所花费的时间。Recreate 策略看似简单但每次发布都需要人工确认“旧版本已完全退出”并手动触发新版本部署人力成本高。而 Argo Rollouts 驱动的 Canary发布流程全自动人力成本趋近于 0但前期配置和调试需投入 2-3 人日。机会成本Opportunity Cost指因策略限制而错失的业务机会。A/B Test 要求严格的实验周期可能错过促销窗口Dark Launch 需要长时间积累数据无法快速响应市场变化。我们曾因坚持用 Dark Launch 验证一个新支付渠道比竞品晚了 17 天上线导致当月流失 3.2% 的新客。故障成本Failure Cost这是最隐性也最昂贵的。一次 Rolling Update 引发的支付失败不仅产生退款、补偿更损害品牌信任。我们按行业基准估算每 1% 的支付失败率导致客户流失率上升 0.8%LTV客户终身价值下降 12%。一次持续 15 分钟的故障综合成本可达 28 万元。将这四类成本加权求和我们得到每个策略的“总拥有成本TCO”。例如对一个日均交易额 5000 万的支付服务Rolling Update 的 TCO 是 12.7 万/年主要来自故障成本而 Blue-Green 是 89.3 万/年主要来自基础设施成本。表面上 Blue-Green 更贵但当它把故障成本从 12.7 万压到几乎为 0 时其长期 ROI投资回报率反而更高。这就是为什么我们说不要只看发布策略的“价格”要看它的“价值”——它为你规避了多少潜在损失。4. 实操落地从 YAML 到可观测性的完整链路4.1 Rolling Update 的安全加固超越默认配置即使你决定继续用 Rolling Update也绝不能停留在默认配置。以下是我们在生产环境强制推行的五项加固措施每一条都源于真实事故minReadySeconds必须大于应用冷启动时间我们用 Prometheus 的container_cpu_usage_seconds_total指标结合rate()函数计算应用从ContainerCreating到Running状态后CPU 使用率稳定在基线的 90% 以上所需时间。对 Java 服务这个值通常是 15-25 秒对 Go 服务是 2-5 秒。minReadySeconds必须设为此值的 1.5 倍确保应用真正“热”了才接收流量。readinessProbe必须检查业务就绪状态不能只httpGet一个/healthz。我们要求所有服务提供/readyz端点其逻辑必须包含a) 本地依赖DB、Redis、Kafka连接池健康b) 外部依赖如风控、地址库的连通性c) 关键缓存如用户权限缓存加载完成。Go 服务示例func readyzHandler(w http.ResponseWriter, r *http.Request) { // 检查 DB 连接池 if err : db.Ping(); err ! nil { http.Error(w, DB not ready, http.StatusServiceUnavailable) return } // 检查 Redis 连接池 if err : redis.Ping(); err ! nil { http.Error(w, Redis not ready, http.StatusServiceUnavailable) return } // 检查本地缓存是否加载 if !cache.IsLoaded() { http.Error(w, Cache not loaded, http.StatusServiceUnavailable) return } w.WriteHeader(http.StatusOK) }livenessProbe与readinessProbe必须分离livenessProbe用于判定 Pod 是否需要重启readinessProbe用于判定是否可接收流量。两者探测逻辑必须不同。livenessProbe可以更激进如超时 1 秒失败 3 次即重启而readinessProbe必须保守超时 5 秒失败 10 次才标记 NotReady避免因瞬时抖动误杀流量。maxSurge和maxUnavailable必须基于容量规划我们不用百分比而用绝对值。maxSurge: 1意味着最多只多启 1 个 Pod防止资源争抢maxUnavailable: 0意味着绝不允许旧 Pod 下线直到新 Pod Ready。这牺牲了发布速度但保证了容量底线。必须配置progressDeadlineSeconds并集成告警progressDeadlineSeconds: 60010 分钟表示 Deployment Controller 在 10 分钟内未能完成滚动就标记为ProgressingFalse。我们用 Prometheus Alertmanager 监控kube_deployment_status_condition{conditionProgressing, statusfalse}一旦触发立即电话告警。这让我们能在发布卡死的第一时间介入而不是等到用户投诉。4.2 Blue-Green 的 Service 切流原子性保障Blue-Green 的灵魂在于“原子切换”而 Kubernetes Service 的默认行为并不保证这一点。我们通过三层机制加固第一层Ingress Controller 替代 Service。放弃直接修改 Service 的 selector改用 Nginx Ingress 的 canary annotation。配置如下apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp-ingress annotations: nginx.ingress.kubernetes.io/canary: true nginx.ingress.kubernetes.io/canary-by-header: insight nginx.ingress.kubernetes.io/canary-weight: 0 spec: rules: - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: myapp-blue port: number: 80 --- # Green 版本的 Ingress仅用于 canary apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp-green-canary annotations: nginx.ingress.kubernetes.io/canary: true nginx.ingress.kubernetes.io/canary-by-header: insight nginx.ingress.kubernetes.io/canary-weight: 100 spec: rules: - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: myapp-green port: number: 80发布时只需kubectl patch ingress myapp-ingress -p {metadata:{annotations:{nginx.ingress.kubernetes.io/canary-weight:100}}}即可将 100% 流量切到 Green。Nginx Ingress 的 canary 实现是通过动态更新 upstream server list比 kube-proxy 重写 iptables 快一个数量级。第二层Pre-stop Hook 验证。在 Green Deployment 的 Pod template 中添加 lifecycle hooklifecycle: preStop: exec: command: [/bin/sh, -c, curl -f http://localhost:8080/readyz || exit 1]这个 hook 在 Pod 收到 SIGTERM 前执行确保 Green 版本已完全就绪才开始切流。如果/readyz失败Pod 不会进入 Terminating 状态切流操作会被阻塞。第三层切流后自动健康检查。我们写了一个简单的 Bash 脚本在切流命令后立即执行#!/bin/bash # 切流后等待 5 秒然后检查 Green Service 的 Endpoint 数量 GREEN_ENDPOINTS$(kubectl get endpoints myapp-green -o jsonpath{.subsets[0].addresses[*].ip} | wc -w) if [ $GREEN_ENDPOINTS -lt 3 ]; then echo ERROR: Green has only $GREEN_ENDPOINTS endpoints, expected at least 3 exit 1 fi # 再检查 Green Pod 的就绪状态 GREEN_READY$(kubectl get pods -l appmyapp,versiongreen -o jsonpath{range .items[*]}{.status.phase}{,}{.status.containerStatuses[0].ready}{\n}{end} | grep Running,True | wc -l) if [ $GREEN_READY -lt 3 ]; then echo ERROR: Only $GREEN_READY green pods are ready exit 1 fi echo Blue-Green switch successful这个脚本作为 CI/CD 流水线的最后一个步骤失败则整个发布失败强制回滚。4.3 Canary 的 Argo Rollouts 实战配置Argo Rollouts 是目前 Kubernetes 生态中最成熟的金丝雀发布框架。以下是我们在生产环境使用的精简版配置去掉了所有非必要字段突出核心逻辑apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: name: myapp-rollout spec: replicas: 6 strategy: canary: # 第一阶段2% 流量持续 10 分钟 steps: - setWeight: 2 - pause: { duration: 10m } # 第二阶段20% 流量持续 30 分钟 - setWeight: 20 - pause: { duration: 30m } # 第三阶段100% 流量 - setWeight: 100 # 分析模板引用全局定义 analysis: templates: - templateName: success-rate args: - name: service value: myapp revisionHistoryLimit: 5 --- # AnalysisTemplate 定义放在独立文件中 apiVersion: argoproj.io/v1alpha1 kind: AnalysisTemplate metadata: name: success-rate spec: metrics: - name: error-rate interval: 30s # 查询 Prometheus计算 5xx 错误率 provider: prometheus: address: http://prometheus.monitoring.svc:9090 query: | rate(http_request_duration_seconds_count{job{{args.service}}, status~5..}[5m]) / rate(http_request_duration_seconds_count{job{{args.service}}}[5m]) # 如果错误率 0.5%则失败 successCondition: result 0.005 failureLimit: 3 - name: latency-p95 interval: 30s