1. 概述

在 Kubernetes 中,PersistentVolumeClaim(PVC)用于管理持久化存储,允许用户动态申请存储资源,从而确保数据在 Pod 生命周期之外仍能持久保留。

但在实际使用中,我们有时会遇到 PVC 无法删除的情况,这可能导致资源堆积、清理困难等问题。本文将从几个常见原因出发,详细讲解 PVC 删除失败的原因及对应的解决方案。

2. Pod 依赖导致无法删除 PVC

如果某个 PVC 正在被 Pod 使用,Kubernetes 会阻止该 PVC 的删除操作以防止数据丢失。因此,删除 PVC 前必须先删除所有使用它的 Pod。

我们可以通过以下命令查看当前 default 命名空间下哪些 Pod 正在使用名为 my-pvc 的 PVC:

$ kubectl get pods -o json | jq -r '.items[] | select(.spec.volumes[]?.persistentVolumeClaim.claimName=="my-pvc") | .metadata.name'

"my-pod"

该命令通过 kubectl 获取所有 Pod 的 JSON 输出,并使用 jq 过滤出使用 my-pvc 的 Pod 名称。

假设我们直接尝试删除 PVC:

$ kubectl delete pvc my-pvc

persistentvolumeclaim "my-pvc" deleted

此时 PVC 会进入 Terminating 状态而无法真正删除。

解决方法是先删除使用该 PVC 的 Pod:

$ kubectl delete pod my-pod

pod "my-pod" deleted

Pod 删除后,再执行 PVC 删除命令即可成功。

关键点

  • 删除 PVC 前务必确认没有 Pod 正在使用它。
  • 若 PVC 卡在 Terminating 状态,先排查是否有 Pod 依赖。

3. Finalizer 保护机制

Finalizer 是 Kubernetes 中用于防止误删资源的一种机制。当 PVC 上存在 finalizer 时,删除操作会等待某些条件满足后才真正删除资源。

我们可以通过以下命令查看 PVC 是否设置了 finalizer:

$ kubectl describe pvc my-pvc | grep Finalizers

Finalizers:    [kubernetes.io/pvc-protection]

如果看到类似输出,说明该 PVC 被保护,不能直接删除。

3.1 使用 kubectl patch 移除 finalizer

可以直接通过命令将 finalizer 设置为 null:

$ kubectl patch pvc my-pvc -p '{"metadata":{"finalizers":null}}'

persistentvolumeclaim/my-pvc patched

3.2 手动编辑 PVC 删除 finalizer

也可以通过编辑 PVC 的方式手动删除 finalizer:

$ kubectl edit pvc my-pvc

找到 metadata 字段中的 finalizers 部分并删除:

"metadata": {
  "finalizers": [
    "kubernetes.io/pvc-protection"
  ]
}

保存退出后,PVC 的 finalizer 就会被移除,之后即可正常删除 PVC。

关键点

  • PVC 被卡在 Terminating 状态时,检查 finalizer 是关键。
  • 可通过 kubectl patch 或手动编辑方式移除 finalizer。

4. 命名空间删除导致 PVC 卡住

如果一个命名空间被标记为删除状态,但其中的 PVC 没有先被删除,这些 PVC 也会卡在 Terminating 状态。

例如,我们查看所有命名空间下的 PVC:

$ kubectl get pvc --all-namespaces  

NAMESPACE     NAME    STATUS       VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
my-namespace  my-pvc  Terminating  pvc-20d640c3-9440-43f3-80bc-499648de0c95   100Mi      RWO            standard       <unset>                 2m46s

我们尝试删除该命名空间:

$ kubectl delete namespace my-namespace

namespace "my-namespace" deleted

然后尝试删除该命名空间下的 PVC:

$ kubectl delete pvc my-pvc -n my-namespace

persistentvolumeclaim "my-pvc" deleted

此时 PVC 仍然卡在 Terminating 状态。尝试移除 finalizer 也会失败:

$ kubectl patch pvc my-pvc -n my-namespace -p '{"metadata":{"finalizers":null}}' 

Error from server (NotFound): namespaces "my-namespace" not found

因为命名空间已被删除,所以无法操作其资源。

解决方法

解决办法是重新创建同名命名空间,然后移除 finalizer 并删除 PVC:

$ kubectl create namespace my-namespace

namespace/my-namespace created

$ kubectl patch pvc my-pvc -n my-namespace -p '{"metadata":{"finalizers":null}}'

persistentvolumeclaim/my-pvc patched

$ kubectl delete pvc my-pvc -n my-namespace

persistentvolumeclaim "my-pvc" deleted

关键点

  • 删除命名空间前务必先清理其下的 PVC。
  • 若 PVC 已卡住,需重建命名空间再处理。

5. 总结

在 Kubernetes 中删除 PVC 时,可能因以下原因导致失败:

  • 存在使用 PVC 的 Pod
  • PVC 被 finalizer 保护
  • PVC 所属命名空间已删除但 PVC 未清理

解决这些问题的关键步骤包括:

  1. 删除使用 PVC 的 Pod
  2. 移除 PVC 上的 finalizer(通过 kubectl patch 或手动编辑)
  3. 若 PVC 所在命名空间已删除,需重建命名空间后再操作 PVC

掌握这些排查技巧,可以有效避免资源堆积,保持 Kubernetes 集群的整洁与稳定。


原始标题:Unable to Delete PersistentVolumeClaims