pod终止|优雅关闭
两个操作是异步的
要在摘除掉ip后,在开始处理服务管理
所谓T4≤T2 保证服务质量(T4关闭时长取决于集群大小)
在关闭开始的时候,留足够的sleep时间
Kubernetes (k8s) 中的 Pod 可能因多种原因被删除。以下是一些常见原因:
- 手动删除:用户使用 kubectl delete pod 命令手动删除 Pod。
- 控制器策略:Deployment、ReplicaSet 或 DaemonSet 等控制器根据其策略调整副本数,例如缩减副本数时会删除多余的 Pod;Job 和 CronJob 完成后删除其创建的 Pod。
- 节点故障:如果节点失效,节点上的 Pod 会被 Kubernetes 控制平面标记为失效并在其他节点上重新调度。
- 资源限制:当节点资源不足时,Kubernetes 可能会根据优先级和资源限制(如资源配额和调度策略)来删除一些 Pod。
- 健康检查失败:Pod 的 liveness 或 readiness 探针连续失败,Kubernetes 会认为 Pod 不健康并删除或重启它。
- 优先级抢占:如果有更高优先级的 Pod 需要资源,Kubernetes 可能会删除较低优先级的 Pod 以释放资源。
- 调度器策略:Kubernetes 调度器可能会根据调度策略(如 NodeAffinity、PodAffinity 等)重新分配 Pod,从而删除旧的 Pod。
- 更新策略:Deployment 或 StatefulSet 进行滚动更新时,旧的 Pod 会被删除并替换为新的 Pod。
- 节点自动缩放:当使用集群自动缩放器时,如果集群缩小(移除节点),部分 Pod 会被删除。
但是不管是何种原因删除Pod(用户手动删除或控制器自动删除),在Pod的删除过程中,都会同时会存在两条并行的时间线,如下图所示:
- 一条时间线是网络规则的更新过程。
- 另一条时间线是 Pod 的删除过程。
由上面流程图可知,在 Pod 删除过程中,存在两条并行的时间线,这两条时间线谁先执行完毕是不确定的。如果 Pod 内的容器已经删除,但网络层面的 Endpoint 资源仍包含该 Pod 的 IP,客户端请求可能会被路由到已删除的 Pod,导致请求处理失败;或者请求未处理完时,Pod 内的容器已经被删除,这样也会导致请求处理失败。
注意从集群中删除的 Pod,因为它们的 IP 地址可能仍然用于路由流量。与立即关闭 Pod 相比,你应该考虑在应用程序中等待更长的时间,或者设置一个
preStop
钩子。只有在集群中的所有端点都被传播并从 kube-proxy、Ingress 控制器、CoreDNS 等中删除后,才应该删除 Pod。通过合理的优雅退出配置 T4 <= T2,即在确保网络层面已经删除了Pod IP的前提下,容器再进行优雅退出,在优雅退出过程中继续处理尚未完成的请求,并完成必要的清理工作,如数据保存、连接关闭等。确保Pod在退出时对用户客户端请求是无感知的,同时保证服务的一致性和可靠性。
时间轴
隐含的时间轴
- TerminationGracePeriodSeconds(T1): 总体 Pod 关闭容忍时间。这个值并不是一个固定参考值,每一个应用对着值的要求也不一样,它跟着 Deployment 走,所以这个值有明确的业务属性。
- Lifecycle PreStop Hook 执行时间(T2): 等待应用进程关闭前需要执行动作的执行时间,这个主要是影响 “新建请求” 到业务 Pod,因为在执行 preStop 的时候 k8s 网络层的变更也在执行。
- Container Graceful Stop 执行时间(T3): 等待应用自主关闭已有请求的连接,同时结束到数据库之类后端数据写入工作,保证数据都落库或者落盘。
- Kubernetes 网络层变更时间(T4)
原则公式:T1 = T2 + T3
复杂的逻辑:
这里总结下 Kubernetes 网络层变更时间与 TerminationGracePeriodSeconds 之间在不同情况下,有可能对 http 业务的影响。
场景 | Http_Code | 描述 |
T4<=T2 | 200 | 正常 |
T2<T4<=T1 | 200/404 | 少量 404,主要看应用的 webservice 如何关闭,如果关闭的优雅,只有 200 |
T1<T4 | 502 | Bad Gateway,后面的 Pod 已经消失了,但是网络层还没有完成变更,导致流量还在往不存在的 Pod 转发 |
处理方法
心思新密的小伙伴可能逐渐发现,要解决问题,实际就是做一个巧妙的动作调整时间差,满足业务 pod 能够真正的正确的关闭。
知道了原因,知道了逻辑,那顺理成章的就有了解决方案:
- 容器应用进程中要有优雅退出代码,能够执行优雅退出;
- 增加 preStopHook,能够执行一定时间的 sleep;
- 修改 TerminationGracePeriodSeconds,每一个业务根据实际需要修改;
当然还有关键的时间点需要考虑:
- 尽量满足 T3 >= T4,这样能够保证新建请求能转移到新 Pod 上。
- 合理配置 T1 和 T2 的值,留下合理的时间 T3 给 Pod 内的应用做优雅关闭。
Loading...