kubernetes滚动更新期间出现502错误,根本原因是网关无法将请求转发至健康后端pod,常见于旧pod终止而新pod未就绪、或交接断连且网关未及时感知状态变化;需通过正确配置readinessprobe、prestop hook和滚动策略实现优雅退出与就绪前置。

HTTP 502(Bad Gateway)在 Kubernetes 滚动更新期间出现,通常不是因为“旧工作进程残留”本身直接返回 502,而是上游网关(如 Ingress Controller、Service Proxy 或云负载均衡器)无法将请求成功转发到健康的后端 Pod。根本原因往往是:旧 Pod 已被终止或停止响应,但新 Pod 尚未就绪;或新旧 Pod 交接期间存在短暂断连,而网关未及时感知健康状态变化。
要真正解决问题,关键在于让滚动更新过程具备优雅退出(graceful shutdown) 和 就绪前置(readiness-first) 能力,而非简单等待或强制杀掉旧进程。
? 先确认是不是真由“旧进程残留”引起
502 的源头一定在反向代理层(如 nginx-ingress、traefik、ALB/NLB),它尝试把请求发给一个后端地址,却收到连接拒绝、超时或空响应。此时需排查:
-
kubectl get endpoints <your-service></your-service>—— 确认 endpoints 是否只包含 Ready 状态的 Pod IP -
kubectl get pod -o wide+kubectl describe pod <pod-name></pod-name>—— 查看是否卡在Terminating,或容器未响应 SIGTERM -
kubectl logs <ingress-pod> | grep "upstream.*failed"</ingress-pod>—— 直接看网关日志里报错的具体后端地址和原因
若 endpoints 里仍有已终止的 IP,或 ingress 日志显示“no live upstreams”,说明就绪/存活探针或终止流程没配好。
✅ 确保滚动更新不中断服务的三要素
1. 正确配置 readinessProbe(就绪探针)
必须确保:新 Pod 只有真正能处理请求时,才被加入 endpoints。否则流量会打到还没启动完的应用上,导致 502。
readinessProbe:
httpGet:
path: /readyz
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 3 # 连续3次失败才从 endpoints 移除(对新Pod是“暂不加入”)
⚠️ 常见错误:
- 用
/healthz(liveness 探针路径)代替/readyz,而 healthz 可能在启动中就返回 200,造成误判; -
initialDelaySeconds太小,应用还没加载完配置或 DB 连接就暴露了。
2. 配置 preStop hook + 合理 terminationGracePeriodSeconds
让旧 Pod 在被删除前,有足够时间:
- 拒绝新连接(如关闭监听 socket)
- 处理完正在执行的请求(尤其长连接、异步任务)
- 主动通知上游(如调用 ingress 的 drain 接口,非必需但可选)
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 15"] # 给应用缓冲期,例如等 HTTP server graceful shutdown 完成
terminationGracePeriodSeconds: 30
✅ 建议:
-
preStop休眠时间 ≥ 应用 graceful shutdown 最大耗时(如 Spring Boot 的server.shutdown=graceful默认 30s); -
terminationGracePeriodSeconds必须 ≥preStop时间,否则会被强制 kill。
3. 调整 Deployment 的滚动更新策略
避免“先删后建”,启用 maxSurge 和 maxUnavailable 的合理组合,保证始终有可用实例:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 允许临时多起 1 个 Pod(保障容量)
maxUnavailable: 0 # 更新中不允许任何 Pod 不可用(强一致性要求)
若设
maxUnavailable: 1,在 3 副本场景下,更新时可能只剩 2 个 Pod 在线——若这 2 个里有 1 个刚好因探针失败被踢出 endpoints,就只剩 1 个承载全部流量,压力大易超时 → 触发 502。
? 补充检查项(常被忽略)
-
Ingress Controller 自身健康:
kubectl get pod -n ingress-nginx确保 controller Pod 全部 Running; -
Service 的 targetPort 与容器实际监听端口一致:比如容器 expose 8080,但 service 写成
targetPort: 80→ 请求发错端口 → connection refused → 502; -
应用未监听 0.0.0.0:只监听
127.0.0.1导致 Service 流量进不来,probe 也失败; -
资源不足触发 OOMKilled:旧 Pod 被杀前未完成 graceful shutdown,新 Pod 因内存不足启动失败 → endpoints 空 → 502;查
kubectl describe pod中的 Events 和Reason: OOMKilled。
? 快速验证方法
部署后立即执行:
# 实时观察 endpoints 变化(更新过程中应平滑增减,不为空)
watch 'kubectl get endpoints <svc-name> -o jsonpath="{.subsets[*].addresses[*].ip}"'
# 模拟请求,看是否出现 502(配合 curl -I 或 hey 工具压测)
while true; do curl -s -o /dev/null -w "%{http_code}\n" http://your-domain/healthz; sleep 0.1; done</svc-name>
如果 endpoints 瞬间清空或长时间不变,说明 probe 或 lifecycle 配置有问题。
问题本质不在“旧进程残留”,而在新旧流量切换缺乏协调机制。把 readiness 探活做准、把 preStop 做稳、把更新策略设保守,502 就会大幅减少。











