拓冰建站拓冰建站
首页 / 资讯中心 / 正文

生产级发布三件套:Readiness Probe、PDB 与金丝雀发布实战详解

文章目录生产级发布三件套Readiness Probe、PDB 与金丝雀发布实战详解一、Readiness Probe就绪探针与滚动更新的深度配合1.1 没有 Readiness Probe 的滚动更新有多危险1.2 从就绪到接流量的完整链路1.3 生产级 Readiness Probe 最佳实践① 探测端口要真实② 探测路径要有业务含义③ 参数调优④ 与容器生命周期配合的完整示例二、PDBPodDisruptionBudget与滚动更新的关系2.1 PDB 到底保护什么2.2 PDB 与滚动更新的关系两者互补2.3 没有 PDB 的后果滚动更新风暴2.4 生产级 PDB 配置2.5 滚动更新 PDB 的完整配合2.6 PDB 与金丝雀发布的结合三、金丝雀发布Canary Release最佳实践3.1 金丝雀发布的核心思想3.2 金丝雀发布方案一多 Deployment 共享 Service最常用3.3 金丝雀发布方案二Service MeshIstio/Linkerd精细化流量控制3.4 金丝雀发布方案三Ingress 流量切分NGINX Ingress 自定义权重3.5 金丝雀发布的最佳实践清单① 金丝雀发布前必须确认的条件② 流量放量节奏建议③ 回滚触发条件满足任一即回滚④ 金丝雀发布与滚动更新的配合组合拳四、三者的完整配合生产级示例生产级发布三件套Readiness Probe、PDB 与金丝雀发布实战详解这三个机制在 Kubernetes 生产发布中缺一不可——Readiness Probe 决定新 Pod 能否接流量PDB 决定旧 Pod 能承受多大损失金丝雀发布决定变更如何小步快跑。下面从原理到实战逐一拆解。一、Readiness Probe就绪探针与滚动更新的深度配合1.1 没有 Readiness Probe 的滚动更新有多危险场景一个 Spring Boot 应用需要 10 秒完成启动加载模型、初始化连接池但容器启动只需要 1 秒。配置了 Readiness Probe 时新 Pod 创建 → 容器启动1s→ Readiness 探测初始延迟 5s 周期 5s→ 直到 /healthz 返回 200 → 标记 READY 1/1 → 加入 Service Endpoints → 滚动更新继续未配置 Readiness Probe 时新 Pod 创建 → 容器启动1s→ 立即标记 READY 1/1 → 立即加入 Service Endpoints → 此时应用还在初始化未监听端口→ 流量进来 → 连接拒绝 → 5xx 错误结论Readiness Probe 是滚动更新安全性的第一道防线。没有它滚动更新形同虚设——新 Pod 一旦启动就会被视为就绪并接收流量哪怕它还没有准备好服务。1.2 从就绪到接流量的完整链路Pod 通过 Readiness Probe │ ▼ Pod 状态变为 Readykubelet 更新 PodStatus │ ▼ EndpointSlice 控制器监听到 Pod Ready 事件 │ ▼ 更新 Service 对应的 EndpointSlice加入该 Pod 的 IP:Port │ ▼ kube-proxy 监听到 EndpointSlice 变化 │ ▼ 更新节点上的 iptables/ipvs 规则 │ ▼ 新流量开始被转发到该 Pod面试考点从 Pod Ready 到真正收到流量中间涉及EndpointSlice 控制器和kube-proxy两层传播存在秒级延迟。这就是为什么生产环境需要preStop Hook配合详见下文。1.3 生产级 Readiness Probe 最佳实践① 探测端口要真实# ❌ 错误探测 80 端口但应用实际监听 8080readinessProbe:tcpSocket:port:80# ✅ 正确探测应用真实监听端口readinessProbe:tcpSocket:port:8080② 探测路径要有业务含义# ❌ 错误探测静态资源路径应用依赖的数据库挂了也返回 200readinessProbe:httpGet:path:/index.html# ✅ 正确专门的健康检查端点会检查数据库/缓存/消息队列等依赖readinessProbe:httpGet:path:/actuator/healthport:8080关键/healthz应该返回整个应用的真实状态而不仅仅是进程存活。如果数据库连接池已耗尽此时不应该返回 200——否则 Pod 会被标记就绪但实际无法处理业务请求。③ 参数调优readinessProbe:httpGet:path:/healthzport:8080initialDelaySeconds:10# 容器启动后等 10s 才开始探测给应用初始化时间periodSeconds:5# 每 5s 探测一次timeoutSeconds:3# 单次探测超时 3sfailureThreshold:3# 连续 3 次失败 → Pod 标记为未就绪successThreshold:1# 连续 1 次成功 → 标记就绪参数影响initialDelaySeconds太短应用还没起来就开始探测白白浪费几次探测failureThreshold太小应用短暂抖动GC 暂停等就被踢出 EndpointsperiodSeconds太大Pod 状态变化反应慢流量切走/切回有延迟④ 与容器生命周期配合的完整示例containers:-name:appimage:myapp:1.21ports:-containerPort:8080readinessProbe:httpGet:path:/healthzport:8080initialDelaySeconds:10periodSeconds:5livenessProbe:# 存活探针与就绪探针区别开httpGet:path:/healthzport:8080initialDelaySeconds:30periodSeconds:10面试必问Readiness Probe 和 Liveness Probe 的区别Readiness ProbeLiveness Probe失败后果Pod 标记未就绪踢出 Service Endpoints但 Pod 不会被重启Pod 标记不健康kubelet 杀掉容器并重启适用场景应用暂时无法服务但可恢复如依赖服务短暂不可用应用死锁/内存泄漏等无法自愈的故障推荐做法检查业务依赖DB、缓存等检查进程崩溃、死锁等致命问题二、PDBPodDisruptionBudget与滚动更新的关系2.1 PDB 到底保护什么PDB 的核心目标是限制自愿中断Voluntary Disruptions时最多允许多少副本同时不可用。这里的自愿中断包括节点维护kubectl drain集群升级节点替换滚动更新Deployment 主动替换旧 Pod← 关键非自愿中断节点宕机、断电等不受 PDB 约束。PDB 只约束你主动要做的操作。2.2 PDB 与滚动更新的关系两者互补关键认知K8s 官方文档明确指出PDB 同样适用于滚动更新场景。滚动更新时Deployment 控制器会检查 PDB确保缩容旧 Pod 不会违反 PDB 限制。滚动更新时 Deployment 想缩容旧 Pod │ ▼ 检查 PDB当前可用副本数 - 1 是否 ≥ PDB 允许的最小可用数 │ ├── 是可以缩容 │ └── 否阻塞等待新 Pod 就绪后再缩容示例场景应用有 3 个副本PDB 设置 minAvailable: 2 滚动更新过程中 - 新 RS 扩容 1 个 → 当前可用 41新3旧 - Deployment 想缩容 1 个旧 Pod → 4 - 1 3 ≥ 2 → 允许 - 再缩容 1 个 → 3 - 1 2 ≥ 2 → 允许 - 再缩容 1 个 → 2 - 1 1 2 → 阻塞等待新 Pod 就绪后继续2.3 没有 PDB 的后果滚动更新风暴场景50 个节点同时维护每个节点上有 20 个 Pod。执行kubectl drain时无 PDB - 每个节点上的 20 个 Pod 同时被驱逐 - 这些 Pod 立即在其他节点重建 - 但 drain 还在继续新节点又被 drain - Pod 被驱逐 → 重建 → 又被驱逐 → 恶性循环 - 可能导致大量 Pod 长时间不可用有 PDB- 每次只允许少量 Pod 被驱逐受 PDB 限制 - 新 Pod 有足够时间在其他节点就绪 - 就绪后再驱逐下一批 - 集群状态始终保持稳定2.4 生产级 PDB 配置apiVersion:policy/v1kind:PodDisruptionBudgetmetadata:name:nginx-pdbspec:minAvailable:2# 允许最少可用副本数二选一与 maxUnavailable 互斥# maxUnavailable: 1 # 或最多允许 1 个副本不可用selector:matchLabels:app:nginx选择 minAvailable 还是 maxUnavailableminAvailable适合必须保证至少几个副本可用的场景如数据库主节点至少 1 个maxUnavailable适合最多能承受几个副本同时不可用通常配合百分比使用2.5 滚动更新 PDB 的完整配合# Deploymentspec:replicas:3strategy:rollingUpdate:maxUnavailable:1maxSurge:1# PDBminAvailable:2实际效果滚动更新流程 1. 新 RS 扩容 1 个 → 可用 43旧1新 2. 旧 RS 缩容 1 个 → 可用 3 ≥ 2 ✅ 3. 新 RS 再扩容 1 个 → 可用 4 4. 旧 RS 再缩容 1 个 → 可用 3 ≥ 2 ✅ 5. 新 RS 再扩容 1 个 → 可用 4 6. 旧 RS 再缩容 1 个 → 可用 3 ≥ 2 ✅ 7. 完成特别注意maxUnavailable: 1表示 Deployment 期望最多 1 个副本不可用但 PDB 要求至少 2 个可用。PDB 的约束优先级更高——如果 PDB 不满足Deployment 的滚动更新会被阻塞。2.6 PDB 与金丝雀发布的结合# 金丝雀发布时为金丝雀版本单独设置 PDB# 不推荐金丝雀版本通常只有 1 个副本PDB 反而会阻塞缩容# 正确做法PDB 配置在稳定版本上保护稳定版本的可用性apiVersion:policy/v1kind:PodDisruptionBudgetmetadata:name:nginx-prod-pdbspec:minAvailable:80%# 至少保留 80% 的可用副本selector:matchLabels:app:nginxtrack:stable# 只保护 stable 版本的副本三、金丝雀发布Canary Release最佳实践3.1 金丝雀发布的核心思想定义先让一小部分流量如 5%打到新版本上验证无异常后再逐步放量最终全量切换。与滚动更新的区别滚动更新金丝雀发布更新粒度按副本数逐步替换按流量比例逐步放量回滚速度回滚到上一个 RS可能涉及多轮缩扩容立即调整流量比例秒级回滚验证周期新 Pod 就绪即继续无观察期每个阶段有观察窗口如 10 分钟流量控制不区分新旧版本流量所有 Pod 在同一个 Service 下可精确控制新旧版本流量权重3.2 金丝雀发布方案一多 Deployment 共享 Service最常用核心思想同一个 Service 下有两个 Deploymentstable 和 canary通过调整副本数比例来控制流量。# Service共享同一个 SelectorapiVersion:v1kind:Servicemetadata:name:nginxspec:selector:app:nginx# 同时匹配 stable 和 canary 的 Podports:-port:80targetPort:8080# stable Deployment当前稳定版本apiVersion:apps/v1kind:Deploymentmetadata:name:nginx-stablelabels:app:nginxtrack:stablespec:replicas:9# 90% 流量selector:matchLabels:app:nginxtrack:stabletemplate:metadata:labels:app:nginxtrack:stablespec:containers:-name:nginximage:nginx:1.19# canary Deployment新版本apiVersion:apps/v1kind:Deploymentmetadata:name:nginx-canarylabels:app:nginxtrack:canaryspec:replicas:1# 10% 流量selector:matchLabels:app:nginxtrack:canarytemplate:metadata:labels:app:nginxtrack:canaryspec:containers:-name:nginximage:nginx:1.21执行流程# 1. 先部署 canary1 个副本kubectl apply-fcanary-deployment.yaml# 2. 观察 10 分钟看日志、监控、错误率# - 如果异常直接删除 canary Deployment秒级回滚kubectl delete deploy/nginx-canary# - 如果正常逐步扩容 canary、缩容 stablekubectl scale deploy/nginx-canary--replicas3kubectl scale deploy/nginx-stable--replicas7# 3. 继续观察 → 再放量kubectl scale deploy/nginx-canary--replicas5kubectl scale deploy/nginx-stable--replicas5# 4. 最终全量切换kubectl scale deploy/nginx-canary--replicas10kubectl scale deploy/nginx-stable--replicas0# 5. 清理把 canary 转正为 stable改名/改标签优点实现简单无需额外组件缺点流量比例按副本数近似不是精确的百分比1/10 是 10%但 1/100 是 1%3.3 金丝雀发布方案二Service MeshIstio/Linkerd精细化流量控制使用 Istio 的 VirtualService 精确控制流量权重apiVersion:networking.istio.io/v1beta1kind:VirtualServicemetadata:name:nginxspec:hosts:-nginxhttp:-route:-destination:host:nginxsubset:v1# 稳定版本weight:95# 95% 流量-destination:host:nginxsubset:v2# 金丝雀版本weight:5# 5% 流量apiVersion:networking.istio.io/v1beta1kind:DestinationRulemetadata:name:nginxspec:host:nginxsubsets:-name:v1labels:version:v1-name:v2labels:version:v2优点流量控制精确到 1%支持基于 HTTP Header 的定向灰度缺点需要额外部署 Service Mesh 组件3.4 金丝雀发布方案三Ingress 流量切分NGINX Ingress 自定义权重Nginx Ingress Controller 支持根据 Service 权重分配流量apiVersion:networking.k8s.io/v1kind:Ingressmetadata:name:nginxannotations:nginx.ingress.kubernetes.io/canary:truenginx.ingress.kubernetes.io/canary-weight:10# 10% 流量spec:rules:-http:paths:-path:/pathType:Prefixbackend:service:name:nginx-canaryport:number:80流程主 Ingress 指向 stable Service添加 canary Ingress带canary-weight: 10指向 canary Service逐步调高 canary-weight10 → 30 → 50 → 100100% 后切换主 Ingress 指向新版本3.5 金丝雀发布的最佳实践清单① 金丝雀发布前必须确认的条件Readiness Probe已配置且健康检查端点有效PDB已配置保护 stable 版本可用性监控告警就绪错误率、P99 延迟、业务指标日志收集覆盖新旧版本便于对比排查数据库兼容——新版本涉及 Schema 变更时必须保证向后兼容金丝雀期间新旧版本共用同一数据库② 流量放量节奏建议阶段 11%验证基础功能→ 观察 10-15 分钟 阶段 25%验证真实流量→ 观察 10-15 分钟 阶段 320%压力验证 → 观察 30 分钟 阶段 450%半量切换 → 观察 30 分钟 阶段 5100%全量切换③ 回滚触发条件满足任一即回滚错误率上升超过基线 2 倍P99 延迟增加超过 50%业务核心指标如订单成功率下降内存/CPU 使用率异常飙升日志中出现严重的异常堆栈④ 金丝雀发布与滚动更新的配合组合拳第一步金丝雀发布精确流量控制 - 5% 流量打到 canary 版本观察 30 分钟 - 确认无误 第二步切换为滚动更新全量替换 - 将 canary Deployment 修改为正式 Deployment - 用滚动更新策略替换 stable或直接扩容 canary、缩容 stable - 滚动更新保证过程中服务不中断四、三者的完整配合生产级示例# 1. Service流量入口apiVersion:v1kind:Servicemetadata:name:nginxspec:selector:app:nginxports:-port:80targetPort:8080---# 2. PDB保护可用性apiVersion:policy/v1kind:PodDisruptionBudgetmetadata:name:nginx-pdbspec:minAvailable:2selector:matchLabels:app:nginx---# 3. Deployment带 Readiness Probe preStopapiVersion:apps/v1kind:Deploymentmetadata:name:nginx-stablespec:replicas:9strategy:type:RollingUpdaterollingUpdate:maxUnavailable:1maxSurge:1selector:matchLabels:app:nginxtrack:stabletemplate:metadata:labels:app:nginxtrack:stablespec:terminationGracePeriodSeconds:30containers:-name:nginximage:nginx:1.19ports:-containerPort:8080readinessProbe:httpGet:path:/healthzport:8080initialDelaySeconds:10periodSeconds:5failureThreshold:3lifecycle:preStop:exec:command:[/bin/sh,-c,sleep 5]这套组合的效果金丝雀发布先部署 1 个 canary Pod精确控制 10% 流量滚动更新金丝雀验证通过后scale stable 到 9 个、canary 到 1 个再逐步调整Readiness Probe确保新 Pod 真正就绪才接收流量PDB即使节点维护/滚动更新也保证至少 2 个副本可用preStopPod 被终止前等待 5 秒让 kube-proxy 摘掉流量避免请求中断
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门