Kubernetes 疑难杂症:Pod 始终处于 Terminating 状态的真实原因与安全修复方案

摘要 :在 Kubernetes 集群运维中,Pod 卡在 Terminating 状态是一个常见的问题。通常情况下,这极有可能是因为容器运行时(如历史版本中的 Docker 或 containerd)在宿主机或其他命名空间中发生了挂载泄漏(mount leak)。这会导致 kubelet 在清理资源时触发 "device or resource busy" 错误,进而使得该 Pod 的 API 对象永远滞留。本文将带你从底层逻辑拆解该问题,并提供安全、彻底的修复步骤。


现象描述

当删除一个包含多个 Pod 的资源对象(如 ReplicationController 或 Deployment)时,大部分 Pod 会被删除,但总有几个顽固的 Pod 停留在 Terminating 状态:

bash 复制代码
NAME        READY   STATUS        RESTARTS   AGE
pod-186o2   1/1     Terminating   0          2h
pod-4b6qc   1/1     Terminating   0          2h
pod-8xl86   1/1     Terminating   0          1h

此时,无论是反复执行 kubectl delete 还是等待,都无济于事。要彻底解决这个问题,我们需要先理解其背后的工作机制。

为什么 Pod 会卡在 "Terminating"?

当 Kubernetes 删除一个 Pod 时,kubelet 会执行一个严谨的关闭流程:发送 SIGTERM 信号 -> 等待 terminationGracePeriodSeconds -> 停止容器 -> 卸载(unmount)卷和网络命名空间 -> 最后从节点和 API Server 中移除该 Pod。

如果卸载(unmounting)过程失败 (通常是因为挂载点处于 "busy" 状态),清理流程就会中断,导致 API 对象陷入 Terminating 的边缘状态。

这种 "device or resource busy" 的错误在 Kubernetes 和 Docker/Moby 的 issue 跟踪器中由来已久。核心原因通常分为两类:

  1. 挂载泄漏 / 运行时占用(Host-level) :容器运行时泄露了挂载点,或者有进程在这些挂载点内持有了文件描述符。常见症状包括 kubelet 无法移除 Pod 的 volume 路径;umount 报告 "not mounted" 但 /proc/mounts 中依然存在记录。
  2. Finalizers 阻塞(API-level):例如 PVC/CSI finalizers 为了确保资源被正确清理,会有意拦截删除操作。如果负责清理的控制器发生故障,对象就会卡住。(警告:在未完全评估后果前,切勿暴力移除 finalizers)。

快速排查决策树

遇到该问题时,按照以下逻辑进行排查,切勿盲目使用 --force

第一步:检查是否被 Finalizer 阻塞

bash 复制代码
kubectl get pod <POD_NAME> -o jsonpath='{.metadata.finalizers}'
  • 如果输出包含 finalizers:问题出在存储/CSI 的清理流程上。请修复底层的存储依赖,而不是强行删除 Pod。仅在底层资源已手动确认处理完毕后,作为最后手段移除 finalizer。
  • 如果没有 finalizers:高度怀疑是挂载泄漏或运行时持有。进入宿主机级别的深度排查。

节点级深度排查与修复(针对 Docker & containerd)

通过 kubectl describe pod <POD_NAME> 找到 Pod 所在的节点,并通过 SSH 登录到该节点。

1. 定位 Pod 的 UID 和挂载路径

首先获取目标 Pod 的 UID:

bash 复制代码
POD=pod-186o2
NS=default
UID=$(kubectl get pod $POD -n $NS -o jsonpath='{.metadata.uid}')
echo $UID

在节点上检查 kubelet 下的挂载情况:

bash 复制代码
# 查找属于该 UID 的挂载记录
grep -F "$UID" /proc/mounts || true
findmnt | grep "$UID" || true

如果看到类似 /var/lib/kubelet/pods/<UID>/volumes/... 的路径拒绝被卸载,这就是罪魁祸首。

2. 识别占用挂载点的进程

bash 复制代码
# 查找哪个进程打开了挂载点下的文件或目录
lsof +D /var/lib/kubelet/pods/$UID 2>/dev/null | head

如果某个容器运行时或 sidecar 进程仍持有打开的文件,这里会暴露其行踪。

3. 容器运行时清理

根据你集群使用的运行时,执行相应的清理操作。

对于 Docker(传统集群):

bash 复制代码
docker ps --no-trunc | grep $POD
# 如果找到容器,尝试优雅停止:
docker stop <containerID>

# 逃生舱操作(高危:会重启节点上所有容器):
# systemctl restart docker

注:docker rm 时的 "device or resource busy" 是个历史悠久的已知问题(涉及 aufs/overlay2)。重启 Docker daemon 通常能释放泄漏的引用,但在生产节点需极其谨慎。

对于 containerd(现代 Kubernetes 默认):

bash 复制代码
crictl ps | grep $POD
crictl stopp <containerID>
crictl rmp <containerID>

# 逃生舱操作(高危):
# systemctl restart containerd

4. 强制卸载残留路径 (Lazy Umount)

如果运行时已不再持有该路径,但挂载依然存在:

bash 复制代码
umount -l /var/lib/kubelet/pods/$UID/volumes/<driver>/<vol> || true

(注意:仅当确认使用该路径的进程已彻底退出后,才能使用 -l 参数。Lazy umount 会立即断开连接,并在 busy 引用消失后清理系统资源。)


安全删除 Pod(仅在解除占用后)

一旦 kubelet 能够完成节点的清理工作,普通的删除命令即可生效:

bash 复制代码
kubectl delete pod $POD -n $NS

如果普通的 delete 依然无效,且你已经 100% 确认节点上的真实工作负载和挂载均已清理干净,方可使用强制删除来清理 API 对象:

bash 复制代码
kubectl delete pod $POD -n $NS --grace-period=0 --force

根本预防与最佳实践

为了减少此类事件的发生,建议采取以下加固措施:

  1. 保持运行时更新:及时升级 containerd/Docker,包含的 bug 修复能大幅减少挂载泄漏的边缘场景。
  2. 合理设置优雅退出时间 :准确配置 terminationGracePeriodSeconds,确保应用在 kubelet 强行介入前有充足时间完成退出。
  3. 监控 OOM 事件 :节点的高负载或内核 OOM 行为容易遗留异常的挂载状态,甚至产生不可杀死的 D-state 进程。
  4. 存储组件健康度:确保 CSI 驱动和 PVC finalizers 能够正常完成工作,并对卡住的 finalizers 建立告警机制。

运维速查手册

bash 复制代码
# === 1. Docker 环境清理 ===
docker ps --no-trunc | grep <pod-name-or-uid> || true
docker stop <containerID> || true
# sudo systemctl restart docker # 终极手段

# === 2. containerd 环境清理 ===
crictl ps | grep <pod-name-or-uid> || true
crictl stopp <containerID> && crictl rmp <containerID> || true
# sudo systemctl restart containerd # 终极手段

# === 3. Kubernetes API 清理 ===
kubectl delete pod <POD> -n <NS>                # 正常删除
kubectl delete pod <POD> -n <NS> --grace-period=0 --force  # 清理完底层后的强制删除

结语 :下次当你看到 Pod 永远处于 Terminating 时,不要直接敲击 --force 的手。

相关推荐
MaximusCoder2 小时前
等保测评命令——Centos Linux
linux·运维·经验分享·python·安全·centos
鹓于3 小时前
手机SSH直连电脑运行iflow终极安全配置
windows·安全·ssh
北京软秦科技有限公司5 小时前
IACheck+AI审核如何赋能刑事证据检测?全面提升报告法律效力,构建高标准司法鉴定审核体系
人工智能·安全
艾莉丝努力练剑6 小时前
【脉脉】AI创作者崛起:掌握核心工具,在AMA互动中共同成长
运维·服务器·c++·人工智能·安全·企业·脉脉
MonkeyKing_sunyuhua7 小时前
K8S执行MAC打出的本地镜像错误:exec /usr/local/bin/uvicorn: exec format error
macos·容器·kubernetes
4t4run8 小时前
3、k8s安装
云原生·容器·kubernetes
洛菡夕8 小时前
nginx安全防护与HTTPS部署实战
nginx·安全·https
未佩妥剑,已入江湖9 小时前
docker Windows下安装
运维·windows·docker·容器
星辰_mya9 小时前
ZooKeeper 分布式锁:强一致性下的“排队”哲学
分布式·zookeeper·云原生·面试·分布式锁