引言前几天删 Kafka 的 PVC 时,又踩了个大坑:输入kubectl delete pvc -n kafka kafka-data-kafka-0,终端卡了 5 分钟,最后提示 “请求超时”;用kubectl get pvc -n kafka看,状态是 “Terminating”,一直变不了。

我试了网上说的 “清空 finalizer”:kubectl patch pvc xxx -p '{"metadata":{"finalizers":[]}}',结果提示 “patched (no change)”;又试了--force --grace-period=0,还是卡着不动;甚至重启了 kubelet,依然没用。

折腾了 2 小时才搞懂:这是 **“Pod 占用 + NFS 挂载” 的双重死锁 **—— 今天把我亲测有效的 5 步解决方案教给你,从此告别 Terminating 状态!

一、卡 Terminating 的核心死锁:2 层锁把资源焊死了

PVC/PV 删不掉,本质是被 2 层锁牢牢焊死了:

锁 1:Pod 占用的 “pvc-protection” 锁

K8S 有个安全机制:只要 PVC 还被 Pod 使用,就会自动给 PVC 加一个kubernetes.io/pvc-protection的 finalizer(终结器)。这个 finalizer 的作用是 “防止删除正在被使用的存储”—— 只要 Pod 还在运行,就算你手动清空 finalizer,K8S 也会立刻重新加上,所以patch命令会提示 “no change”。

锁 2:节点上的 NFS 挂载锁

Kafka Pod 运行时,会把 NFS 挂载到节点的/var/lib/kubelet/pods/xxx/volumes/...目录下。如果 Pod 没正常终止,kubelet 进程会持续占用这个挂载点,导致 K8S 认为 “PVC 还在被使用”,就算删了 Pod,挂载点没释放也删不掉 PVC。

二、5 步终极解锁:先卸挂载→删 Pod→清锁→删资源

这 5 步必须按顺序来,颠倒任何一步都会失败:

步骤 1:找到 PVC 对应的 Pod 和节点

先搞清楚哪个 Pod 在占用这个 PVC,以及 Pod 运行在哪个节点上:

bash

运行

# 1. 查PVC绑定的Pod(Used By字段)
kubectl describe pvc -n kafka kafka-data-kafka-0 | grep "Used By"
# 输出示例:Used By:       kafka-0

# 2. 查Pod所在节点
kubectl get pod -n kafka kafka-0 -o wide | grep kafka-0
# 输出示例:kafka-0   Running   0     5h   10.244.1.10   node-1   <none>
步骤 2:登录节点,强制卸载 NFS 挂载点

Pod 所在节点上的 NFS 挂载没释放,是卡 Terminating 的 “隐形凶手”—— 必须先强制卸载:

bash

运行

# 1. 登录Pod所在节点(比如node-1)
ssh node-1

# 2. 查该节点上的NFS挂载点(找和kafka相关的路径)
mount | grep kafka
# 输出示例:192.168.142.141:/data/kafka/kafka-0 on /var/lib/kubelet/pods/029b664b-e666-47e0-aea3-0cd46f2ed76a/volumes/kubernetes.io~nfs/kafka-pv-0 type nfs (...)

# 3. 强制卸载(-l=懒卸,-f=强制,解决“设备忙”的问题)
sudo umount -lf /var/lib/kubelet/pods/029b664b-e666-47e0-aea3-0cd46f2ed76a/volumes/kubernetes.io~nfs/kafka-pv-0

# 4. 验证卸载成功(再查mount,该路径消失)
mount | grep kafka
步骤 3:删除占用 PVC 的 Kafka Pod

Pod 不删,pvc-protection锁永远解不开 —— 必须强制删除 Pod:

bash

运行

# 回到K8S master节点,删除占用PVC的Pod
kubectl delete pod -n kafka kafka-0 --force --grace-period=0
# 对所有占用PVC的Pod执行同样操作(比如kafka-1、kafka-2)
kubectl delete pod -n kafka kafka-1 kafka-2 --force --grace-period=0

验证 Pod 已删除:

bash

运行

kubectl get pod -n kafka | grep kafka
# 无输出即成功
步骤 4:清空 PVC 和 PV 的 finalizer 保护锁

Pod 删了、挂载点卸了,现在 finalizer 终于能清空了:

bash

运行

# 清空PVC的finalizer
kubectl patch pvc -n kafka kafka-data-kafka-0 -p '{"metadata":{"finalizers":[]}}'
# 对其他PVC执行同样操作
kubectl patch pvc -n kafka kafka-data-kafka-1 -p '{"metadata":{"finalizers":[]}}'
kubectl patch pvc -n kafka kafka-data-kafka-2 -p '{"metadata":{"finalizers":[]}}'

# 清空PV的finalizer(PV也可能有pv-protection锁)
kubectl patch pv kafka-pv-0 -p '{"metadata":{"finalizers":[]}}'
kubectl patch pv kafka-pv-1 -p '{"metadata":{"finalizers":[]}}'
kubectl patch pv kafka-pv-2 -p '{"metadata":{"finalizers":[]}}'

验证 finalizer 已清空:

bash

运行

# 查PVC的finalizers字段(应为空数组)
kubectl get pvc -n kafka kafka-data-kafka-0 -o jsonpath='{.metadata.finalizers}'
# 输出:[]
步骤 5:强制删除 PVC 和 PV

现在死锁已解,删除操作能秒成功:

bash

运行

# 删除所有PVC
kubectl delete pvc -n kafka --all --force --grace-period=0
# 删除所有PV
kubectl delete pv kafka-pv-0 kafka-pv-1 kafka-pv-2 --force --grace-period=0
三、验证:终于把资源删干净了!

执行以下命令,无输出即说明清理完成:

bash

运行

kubectl get pvc -n kafka
kubectl get pv | grep kafka

总结PVC/PV 卡 Terminating,根本不是 “finalizer 没清” 这么简单,而是 “Pod 占用 + NFS 挂载” 的双重死锁。必须按 “卸挂载→删 Pod→清锁→删除” 的顺序操作,才能彻底解锁 —— 记住这 5 步,下次遇到 Terminating 状态再也不用慌!

更多推荐