K8S Pod 删除逻辑的一个易错点
K8S Pod 删除逻辑的一个易错点#
1. 问题描述#
在 Kubernetes 控制器开发中,我们遇到了一个问题:当 Pod 进入 terminating 状态时,未被检查到,导致 Running 状态的列表中仍然存在该 Pod。
2. 原因分析#
这个问题的根本原因在于 Kubernetes Pod 生命周期的特殊性,以及我们对 Pod 状态判断的不完整:
Pod 终止是一个过程,而非瞬时状态:
- 当一个 Pod 被标记为删除时,Kubernetes 首先会设置
Pod.DeletionTimestamp
字段 - 此时 Pod 的
Status.Phase
字段仍然保持为Running
,直到容器实际停止 - 这个过程可能持续数秒到数分钟
- 当一个 Pod 被标记为删除时,Kubernetes 首先会设置
代码中的逻辑缺陷:
1
2
3
4// 原代码只检查了 Phase 是否为 Running
if !isPodRelatedToKinesisConsumer(&p, kcCopy) || p.Status.Phase != corev1.PodRunning {
continue
}这段代码的问题在于:它只检查了 Pod 的 Phase 是否为 Running,但没有检查 Pod 是否已经被标记为删除(即是否设置了 DeletionTimestamp)。在以前的开发过程中,遇到都是 Pod 很快被删除的场景,故为发现该问题。
3. 解决方案#
修改 Pod 筛选逻辑,同时检查 DeletionTimestamp
:
1 | // 修改后的代码 |
这样,即使 Pod 的 Phase 仍为 Running,但只要它被标记为删除(设置了 DeletionTimestamp),就会被排除在分片分配之外。
4. Kubernetes Pod 生命周期需注意#
终止状态判断:
- 不要仅依赖
Pod.Status.Phase
判断 Pod 是否在终止 - 始终检查
Pod.DeletionTimestamp != nil
来确定 Pod 是否开始了删除流程
- 不要仅依赖
删除顺序与事件时机:
- Pod 删除是一个多阶段过程:设置 DeletionTimestamp → 执行 preStop hook → 发送 SIGTERM → 等待优雅终止时间 → 发送 SIGKILL
- 控制器可能在这个过程的任何阶段被触发,需要稳健处理各种状态
资源清理时机:
- 对于依赖 Pod 的资源(如我们的分片分配),应当在 Pod 进入终止状态就立即更新相关状态
- 不要等到 Pod 完全删除后再处理,这会导致不必要的延迟