← 中文资源

简体中文版本

在 Pod 终止前完成连接排空

通过 preStop 等待、足够的优雅终止时间和就绪探针,让滚动发布期间的存量请求完成,避免 502 突发。

阅读英文原文

概述

Pod 被删除时,API Server 标记 Terminating 与 kubelet 发送 SIGTERM 几乎同时发生,但 Endpoints 的摘除是异步的。Ingress 控制器、kube-proxy 和云负载均衡器各自监听 EndpointSlice,可能延迟数秒才停止转发,这段时间正好落在进程关闭监听器之后,于是出现连接拒绝和 502。

步骤

  1. 增加 preStop 钩子,在收到 SIGTERM 之前保持进程存活,为 Endpoints 传播争取时间:
lifecycle:
  preStop:
    exec:
      command: ["/bin/sh", "-c", "sleep 10"]
terminationGracePeriodSeconds: 40
  1. 应用在 SIGTERM 后停止接受新连接,并等待存量请求完成。Go 服务可调用 srv.Shutdown(ctx),超时设为 25 秒,小于“宽限期减去 preStop 时间”。
  2. 执行 kubectl rollout restart deployment/payments-api,同时用 kubectl get endpointslices -l kubernetes.io/service-name=payments-api -w 观察地址摘除顺序。
  3. 用 hey -z 60s -c 20 https://api.example.com/health 在发布期间持续压测。

验证

预期滚动发布全程无非 2xx 响应,且日志顺序为:preStop 等待、Endpoints 摘除、SIGTERM、处理存量请求、进程退出。若仍有短暂 502,说明 preStop 时间小于边缘层同步间隔,应逐步上调并复测。

注意事项

  • terminationGracePeriodSeconds 必须覆盖 preStop 等待时间加应用排空超时,再留出余量,否则会被 SIGKILL 打断。
  • 就绪探针应在开始关闭时立即失败,让重新检查就绪状态的控制器也停止转发。
  • 长时间连接(如 WebSocket)可能超过宽限期,需要客户端重连策略。
  • 存在 sidecar 时注意关闭顺序,优先使用原生 sidecar 或统一终止信号。