概述
Pod 被删除时,API Server 标记 Terminating 与 kubelet 发送 SIGTERM 几乎同时发生,但 Endpoints 的摘除是异步的。Ingress 控制器、kube-proxy 和云负载均衡器各自监听 EndpointSlice,可能延迟数秒才停止转发,这段时间正好落在进程关闭监听器之后,于是出现连接拒绝和 502。
步骤
- 增加 preStop 钩子,在收到 SIGTERM 之前保持进程存活,为 Endpoints 传播争取时间:
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 10"]
terminationGracePeriodSeconds: 40
- 应用在 SIGTERM 后停止接受新连接,并等待存量请求完成。Go 服务可调用
srv.Shutdown(ctx),超时设为 25 秒,小于“宽限期减去 preStop 时间”。 - 执行
kubectl rollout restart deployment/payments-api,同时用kubectl get endpointslices -l kubernetes.io/service-name=payments-api -w观察地址摘除顺序。 - 用
hey -z 60s -c 20 https://api.example.com/health在发布期间持续压测。
验证
预期滚动发布全程无非 2xx 响应,且日志顺序为:preStop 等待、Endpoints 摘除、SIGTERM、处理存量请求、进程退出。若仍有短暂 502,说明 preStop 时间小于边缘层同步间隔,应逐步上调并复测。
注意事项
terminationGracePeriodSeconds必须覆盖 preStop 等待时间加应用排空超时,再留出余量,否则会被 SIGKILL 打断。- 就绪探针应在开始关闭时立即失败,让重新检查就绪状态的控制器也停止转发。
- 长时间连接(如 WebSocket)可能超过宽限期,需要客户端重连策略。
- 存在 sidecar 时注意关闭顺序,优先使用原生 sidecar 或统一终止信号。