本文将深入剖析其背后的实现机制。Kubernetes 设计的优雅退出机制,旨在保证服务实例上下线时,尽可能避免服务中断。
这一目标的核心实现,依赖于 Kubernetes 的调度策略与 Pod 容器内部关闭逻辑的紧密配合:
- 调度策略:当 Pod 被删除或缩容时,Kubernetes 会向容器进程发送
SIGTERM 信号,通知容器开始优雅退出,同时将该 Pod 状态标记为 Terminating。同步地,Kubernetes 会根据副本控制器(如 ReplicaSet/Deployment)的配置创建新的 Pod,并且 Service 会立即将新流量路由到新 Pod,而非处于 Terminating 状态的旧 Pod。
- Pod 容器的内部关闭逻辑:对于处于
Terminating 状态的 Pod,Kubernetes 会提供一个宽限期(默认为 30 秒)让其完成清理工作,例如关闭文件描述符、释放资源等。如果容器进程在宽限期内未能自行退出,Kubernetes 将发送 SIGKILL 信号强制终止进程。因此,业务服务在开发时,需要监听 SIGTERM 信号,在收到信号后,先处理完当前正在执行的请求,再正常退出,从而实现最大程度的优雅下线。
详解
Kubernetes 的优雅退出是由 kubelet、Endpoints 控制器、ReplicaSet/Deployment、探针(Probe)与生命周期钩子(Lifecycle)等多个组件协同实现的。
通常有两种触发路径:
kubectl delete pod(用户强制删除):旧 Pod 会立即进入 Terminating 状态,随后副本控制器检测到副本数不足,会启动新的 Pod 进行补充。
- Deployment 滚动更新(RollingUpdate):通常的策略是“先启动新 Pod”(
maxSurge),待新 Pod 进入 Ready 状态后,再终止旧 Pod(maxUnavailable)。
核心逻辑
- 当 Pod 进入
Terminating 状态后,它会被从 Service 的 Endpoints 后端列表中移除,新的流量请求不会再被路由到该 Pod。
kubelet 会首先向 Pod 内的容器发送 SIGTERM 信号。如果容器在 terminationGracePeriodSeconds 设定的宽限期内没有退出,kubelet 最终会发送 SIGKILL 信号强制终止进程。
kubectl delete pod 命令不会“先拉新后删旧”;只有滚动更新(RollingUpdate)才有“先启动新实例,再终止旧实例”的保障流程。
- 应用程序自身需要实现“停止接收新连接、等待现有请求处理完成、超时后强制关闭”等逻辑。为了更可靠,建议配合使用
preStop 生命周期钩子与 readinessProbe 就绪探针。
触发路径对比(时序图)
A. 用户执行 kubectl delete pod
B. Deployment 滚动更新(RollingUpdate)
默认策略:maxUnavailable=1,maxSurge=1。
流程拆解
- 终止信号分发
kubelet 在 Pod 被删除或缩容时,会向容器内的主进程发送 SIGTERM 信号。
- 收到信号的 Pod 随即进入
Terminating 状态,优雅退出的宽限期开始计时。
- 与流量切断协同
Endpoints 控制器会实时监听 Pod 状态,一旦 Pod 进入 Terminating,便将其从关联的 Service 后端池中移除。
- 新的服务请求将不会再被路由到该 Pod;对于该 Pod 上仍在处理的连接和请求,则由应用程序自身的逻辑决定何时释放。
- 宽限期与强制终止
- 宽限期的时长由 Pod 规约中的
spec.terminationGracePeriodSeconds 字段控制,默认值为 30 秒。
- 如果容器进程在宽限期结束后仍未退出,
kubelet 将发送 SIGKILL 信号强制终止该进程。
- 新 Pod 的补充与创建
kubectl delete pod场景:旧 Pod 直接变为 Terminating;随后,ReplicaSet 控制器观察到期望的副本数减少,便会触发创建新 Pod 的流程。
- 滚动更新场景:通常策略是先创建新 Pod(将总副本数临时提升至
replicas + maxSurge),待新 Pod 状态变为 Ready 后,再按顺序终止旧 Pod(将总副本数最终降至 replicas - maxUnavailable)。
关键参数与配置
Pod 级别
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 允许超出期望副本数的最大Pod数
maxUnavailable: 1 # 更新过程中不可用Pod的最大数量
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
terminationGracePeriodSeconds: 60 # 优雅退出宽限期,单位秒
containers:
- name: server
image: ghcr.io/example/web:1.2.3
ports:
- containerPort: 8080
readinessProbe: # 就绪探针
httpGet:
path: /healthz
port: 8080
periodSeconds: 2
failureThreshold: 2
lifecycle: # 生命周期钩子
preStop: # 终止前钩子
httpGet:
path: /drain # 应用实现的“停止接收新连接”端点
port: 8080
配置说明:
terminationGracePeriodSeconds:设置合理的宽限期,既能保证在途请求处理完毕,又能避免因超时被 SIGKILL 强制杀死。
readinessProbe:确保只有通过健康检查的 Pod 才会被加入 Service 的流量后端。应用在准备退出时,可以主动使就绪探针失败,促使自身更快地从后端移除。
preStop:用于在 SIGTERM 信号发送之前或同时,执行自定义的清理逻辑(例如调用应用内预先实现的“排水”(Drain)接口,通知服务停止接收新请求)。
Service 与 Endpoints
- Service 与
Endpoints 无需特殊配置即可配合优雅退出。Endpoints 控制器会自动在 Pod 变为 Terminating 时将其从后端列表中剔除。
- 如果使用了外部负载均衡器(如 Ingress 或云厂商的 LoadBalancer 类型 Service),需要确保负载均衡器的健康检查机制与 Kubernetes 内部的
readinessProbe 状态保持一致,避免流量切换延迟或双写。
验证与排查
- 观察 Pod 事件:执行
kubectl describe pod <pod-name>,查看事件中关于 Terminating、preStop 钩子执行以及探针检查的记录。
- 观察 Endpoints 变化:执行
kubectl get endpoints <service-name> -w 进行实时观察,确认 Pod 进入 Terminating 状态后是否被及时移除。
- 滚动更新演练:执行
kubectl rollout restart deployment/<deployment-name> 触发滚动更新,观察新旧 Pod 的 Ready 和 Terminating 状态变化的先后顺序是否符合预期。
- 压测验证:在 Pod 删除或滚动更新过程中持续发送业务流量,监控服务是否出现明显的 5xx 错误率突增或连接拒绝现象。
最佳实践
- 避免宽限期过短:如果应用关闭逻辑较复杂,需要适当调大
terminationGracePeriodSeconds,并优化应用自身的关闭路径,确保能在宽限期内完成。
- 处理长连接:应用在收到
SIGTERM 后,应立即停止接受新的连接,并为现有连接设置合理的超时时间,必要时主动关闭空闲或超时的长连接。
- 合理使用
preStop:preStop 钩子执行时间计入宽限期,应确保其逻辑快速且幂等。复杂的关闭逻辑建议在应用内部处理。
- 主动标记非就绪状态:应用可以在收到
SIGTERM 信号或进入 preStop 阶段时,主动将自身的健康检查状态置为失败,促使负载均衡器更快地切断流量。
- 与外部组件对齐:确保外部负载均衡器(LB)或 API 网关的健康检查端点、超时时间与 Kubernetes 内的
readinessProbe 配置保持一致,避免因状态不一致导致流量错误路由。
常见误解澄清
- 删除 Pod 会等待新 Pod Ready 后才让旧 Pod Terminating 吗?
答:不会。
kubectl delete pod 命令会立刻让目标 Pod 进入 Terminating 状态;新 Pod 是由副本控制器(如 ReplicaSet)在检测到副本数不足后随后创建补足的,两者没有等待关系。
- Pod 处于 Terminating 状态下还会接收流量吗?
答:不会。
Endpoints 控制器会将其从关联的 Service 后端列表中移除,新的服务请求不会再被路由到它。
- 优雅退出只靠配置 Kubernetes 资源就足够了吗?
答:不够。Kubernetes 提供了机制和框架,但应用必须自行实现优雅关闭的业务逻辑(停止接单、等待在途请求完成、超时强制关闭等)。
总结
Kubernetes 的优雅退出是一套由“信号分发、后端移除、宽限期控制、副本管理”等多个环节协同工作的机制。它不仅是Docker等容器运行时技术的上层抽象,更是构建稳定微服务架构的关键保障。
要实现真正的无损发布或下线,除了正确配置 terminationGracePeriodSeconds、readinessProbe、preStop 等参数外,更关键的是在应用程序内部实现完善的优雅关闭流程。
无论是滚动更新还是手动删除,Kubernetes 都会确保进入 Terminating 状态的 Pod 不再承接新流量,从而为业务平滑过渡提供了基础保障。
|