GKE v1.20抢占节点驱逐后Pod卡住为Failed/Shutdown僵尸状态问题咨询
根因分析
该问题是GKE 1.20.x版本的官方已知缺陷,和业务代码的信号处理逻辑无关:
- Kubernetes 1.20版本默认开启了kubelet优雅节点关闭特性,但是GKE的抢占节点(preemptible node)生命周期管理逻辑和该特性存在适配冲突:抢占事件触发后,kubelet会先启动Pod驱逐流程,标记对应Pod为
Failed状态、原因为Shutdown,但GCP的抢占节点会在触发事件后30秒内被强制销毁,kubelet来不及完成和apiserver的状态同步全流程 - 你观测到的
Cancelling deletion of Pod preempt-pod日志,是因为节点被销毁后失联超过K8s默认的节点监测宽限期(40秒),节点生命周期控制器会直接取消节点上未完成的Pod删除任务,最终遗留状态为Shutdown的Failed Pod,也就是你所说的僵尸Pod,这类Pod不会实际占用计算资源,仅会残留etcd记录。
可行解决方案
1. 版本升级(永久修复)
升级GKE集群到1.21.3-gke.900及以上版本即可,谷歌已经在该版本修复了preemptible节点的Pod清理逻辑,适配了kubelet的优雅关闭特性;也可以选择升级到1.22及以上正式版本,相关缺陷已完全合入上游K8s发布分支。
2. 临时规避方案(无法升级时使用)
- 关闭kubelet的优雅节点关闭特性:在节点池的kubelet配置中添加参数
shutdownGracePeriod=0s和shutdownGracePeriodCriticalPods=0s,关闭该特性后抢占节点的Pod驱逐逻辑会回到1.19版本的行为,不会产生僵尸Pod - 配置自动清理脚本:定期执行以下命令清理所有状态为Shutdown的Failed Pod:
kubectl delete pods -A --field-selector=status.reason=Shutdown
你可以把这个命令配置为集群内的CronJob定时运行,建议频率为每小时一次即可,不会对集群性能产生影响。
补充说明
你观察到的"集群会在其他节点启动新副本"是Deployment/StatefulSet等工作负载的正常行为,和僵尸Pod无关,这些僵尸Pod只会占用etcd存储和kubectl get pods的展示空间,不会影响业务可用性。
内容的提问来源于stack exchange,提问作者jbphelps
相关产品推荐
相关产品推荐

