K8s中Pod卡在Terminating本质是容器运行时存储驱动死锁,需节点级干预:先定位(kubectl describe+findmnt+dmesg),再停服务、lazy卸载overlay2、清理目录,最后加固配置(统一overlay2、启用xino、确保d_type支持)。

在 K8s 集群中,当底层 Docker(或更准确地说,容器运行时如 containerd)因存储驱动死锁导致 Pod 删除卡在 Terminating 状态,本质是宿主机文件系统层的挂载或元数据锁未释放——K8s 的 kubectl delete 只能触发容器运行时的清理请求,无法穿透到 overlay2 或 devicemapper 的内核级阻塞。必须从节点层面干预。
先确认是不是存储驱动死锁
别急着删,先定位根源:
- 执行
kubectl get pods -A | grep Terminating,再对卡住的 Pod 运行kubectl describe pod <name> -n <ns>,重点看 Events 中是否有Failed to unmount、device or resource busy或overlay2: failed to mount - 登录对应工作节点,检查 Docker/containerd 状态:
sudo systemctl status docker(或containerd),若服务本身响应迟缓或日志卡在 mount/unmount 操作,大概率是存储层问题 - 查挂载点:
findmnt -D | grep overlay2,观察是否有残留的/var/lib/docker/overlay2/<id>/merged仍被挂载,且对应容器已不存在 - 看内核日志:
dmesg -T | tail -30 | grep -i "overlay\|busy\|deadlock",出现overlayfs: failed to get dentry或反复unmount blocked就是典型信号
绕过死锁的手动清理三步法(节点级)
这是最直接有效的解法,适用于 overlay2 卡死场景(当前主流):
-
停运行时服务:在卡住 Pod 所在节点执行
sudo systemctl stop docker(若用 containerd,则停containerd)。这能阻止守护进程持续尝试访问已卡住的路径 -
lazy 卸载 overlay2 目录:找到该 Pod 对应容器的 overlay2 ID(可通过
docker ps -a或crictl ps -a查容器 ID,再docker inspect <id> | grep -i graph;或直接查/var/lib/docker/containers/<cid>/config.v2.json中的GraphDriver.Data.MergedDir)。然后对它的merged、upper、work子目录逐个执行:sudo umount -l /path/to/xxx -
安全清空并重启:确认无进程占用:
sudo lsof +D /var/lib/docker/overlay2/<id>返回空;再执行sudo rm -rf /var/lib/docker/overlay2/<id>;最后sudo systemctl start docker。此时kubectl get pods中该 Pod 会立即消失
永久规避:集群节点的存储驱动加固
靠手动清理是救火,长期要改配置:
-
统一使用 overlay2,禁用 aufs/devicemapper:在所有节点的
/etc/docker/daemon.json中只保留"storage-driver": "overlay2",删除其他驱动配置;重启 Docker 后用docker info | grep "Storage Driver"验证 -
启用 xino 模式(Linux ≥ 5.15):在
daemon.json加入"storage-opts": ["overlay2.xino=auto"],可大幅降低 stat 竞争引发的挂起 -
确保 d_type 支持:若
/var/lib/docker在 ext4 分区,格式化时需带-O dir_index,large_file,ext_attr,has_journal, filetype,或检查dumpe2fs -h /dev/xxx | grep -i d_type输出为 1 -
避免高风险文件系统:不要把
/var/lib/docker放在 eCryptfs、ZFS 用户空间层、或启用了配额(quota)的分区上,它们破坏 overlay 的原子性语义
K8s 层面的兜底与加速
即使底层修复了,K8s 控制平面有时仍残留 finalizer 或缓存状态:
- 若 Namespace 卡在
Terminating,导出后清空 finalizers:kubectl get ns <ns> -o json > ns.json,编辑finalizers: [],再kubectl replace --raw "/api/v1/namespaces/<ns>/finalize" -f ns.json - 对单个 Pod 强制跳过优雅终止:
kubectl delete pod <name> -n <ns> --grace-period=0 --force,但注意这只是“告诉 API Server 别等”,不解决底层卡死,仅适用于已确认运行时已清理完毕的情况 - 升级集群节点内核至 ≥ 5.11、Docker 至 ≥ 24.0 或 containerd ≥ 1.7,这些版本对 overlay2 锁机制有实质性优化



















