这篇文章已经一年多了,较旧的文章可能包含过时的内容。请检查从发表以来,页面中的信息是否变得不正确。
Kubernetes 1.31:防止无序删除时 PersistentVolume 泄漏
PersistentVolume(简称 PV)具有与之关联的回收策略。回收策略用于确定在删除绑定到 PV 的 PVC 时存储后端需要采取的操作。当回收策略为 Delete 时,期望存储后端释放为 PV 所分配的存储资源。实际上,在 PV 被删除时就需要执行此回收策略。
在最近发布的 Kubernetes v1.31 版本中,一个 Beta 特性允许你配置集群以这种方式运行并执行你配置的回收策略。
在以前的 Kubernetes 版本中回收是如何工作的?
PersistentVolumeClaim (简称 PVC)是用户对存储的请求。如果新创建了 PV 或找到了匹配的 PV,那么此 PV 和此 PVC被视为已绑定。PV 本身是由存储后端所分配的卷支持的。
通常,如果卷要被删除,对应的预期是为一个已绑定的 PV-PVC 对删除其中的 PVC。不过,对于在删除 PVC 之前可否删除 PV 并没有限制。
首先,我将演示运行旧版本 Kubernetes 的集群的行为。
检索绑定到 PV 的 PVC
检索现有的 PVC example-vanilla-block-pvc:
kubectl get pvc example-vanilla-block-pvc
以下输出显示了 PVC 及其绑定的 PV;此 PV 显示在 VOLUME 列下:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
example-vanilla-block-pvc Bound pvc-6791fdd4-5fad-438e-a7fb-16410363e3da 5Gi RWO example-vanilla-block-sc 19s
删除 PV
当我尝试删除已绑定的 PV 时,kubectl 会话被阻塞,且 kubectl 工具不会将控制权返回给 Shell;例如:
kubectl delete pv pvc-6791fdd4-5fad-438e-a7fb-16410363e3da
persistentvolume "pvc-6791fdd4-5fad-438e-a7fb-16410363e3da" deleted
^C
检索 PV
kubectl get pv pvc-6791fdd4-5fad-438e-a7fb-16410363e3da
你可以观察到 PV 处于 Terminating 状态:
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-6791fdd4-5fad-438e-a7fb-16410363e3da 5Gi RWO Delete Terminating default/example-vanilla-block-pvc example-vanilla-block-sc 2m23s
删除 PVC
kubectl delete pvc example-vanilla-block-pvc
如果 PVC 被成功删除,则会看到以下输出:
persistentvolumeclaim "example-vanilla-block-pvc" deleted
集群中的 PV 对象也被删除。当尝试检索 PV 时,你会观察到该 PV 已不再存在:
kubectl get pv pvc-6791fdd4-5fad-438e-a7fb-16410363e3da
Error from server (NotFound): persistentvolumes "pvc-6791fdd4-5fad-438e-a7fb-16410363e3da" not found
尽管 PV 被删除,但下层存储资源并未被删除,需要手动移除。
总结一下,与 PersistentVolume 关联的回收策略在某些情况下会被忽略。对于 Bound 的 PV-PVC 对,PV-PVC 删除的顺序决定了回收策略是否被执行。如果 PVC 先被删除,则回收策略被执行;但如果在删除 PVC 之前 PV 被删除,则回收策略不会被执行。因此,外部基础设施中关联的存储资产未被移除。
Kubernetes v1.31 的 PV 回收策略
新的行为确保当用户尝试手动删除 PV 时,下层存储对象会从后端被删除。
如何启用新的行为?
要利用新的行为,你必须将集群升级到 Kubernetes v1.31 版本,并运行CSI external-provisioner
v5.0.1 或更高版本。
工作方式
对于 CSI 卷,新的行为是通过在新创建和现有的 PV 上添加Finalizer
external-provisioner.volume.kubernetes.io/finalizer 来实现的。只有在后端存储被删除后,Finalizer 才会被移除。
下面是一个带 Finalizer 的 PV 示例,请注意 Finalizer 列表中的新 Finalizer:
kubectl get pv pvc-a7b7e3ba-f837-45ba-b243-dec7d8aaed53 -o yaml
apiVersion: v1
kind: PersistentVolume
metadata:
annotations:
pv.kubernetes.io/provisioned-by: csi.vsphere.vmware.com
creationTimestamp: "2021-11-17T19:28:56Z"
finalizers:
- kubernetes.io/pv-protection
- external-provisioner.volume.kubernetes.io/finalizer
name: pvc-a7b7e3ba-f837-45ba-b243-dec7d8aaed53
resourceVersion: "194711"
uid: 087f14f2-4157-4e95-8a70-8294b039d30e
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 1Gi
claimRef:
apiVersion: v1
kind: PersistentVolumeClaim
name: example-vanilla-block-pvc
namespace: default
resourceVersion: "194677"
uid: a7b7e3ba-f837-45ba-b243-dec7d8aaed53
csi:
driver: csi.vsphere.vmware.com
fsType: ext4
volumeAttributes:
storage.kubernetes.io/csiProvisionerIdentity: 1637110610497-8081-csi.vsphere.vmware.com
type: vSphere CNS Block Volume
volumeHandle: 2dacf297-803f-4ccc-afc7-3d3c3f02051e
persistentVolumeReclaimPolicy: Delete
storageClassName: example-vanilla-block-sc
volumeMode: Filesystem
status:
phase: Bound
Finalizer 防止此 PersistentVolume 从集群中被移除。如前文所述,Finalizer 仅在从存储后端被成功删除后才会从PV 对象中被移除。进一步了解 Finalizer,请参阅使用 Finalizer 控制删除。
同样,Finalizer kubernetes.io/pv-controller 也被添加到动态制备的树内插件卷中。
有关 CSI 迁移的卷
本次修复同样适用于 CSI 迁移的卷。
一些注意事项
本次修复不适用于静态制备的树内插件卷。
参考
我该如何参与?
Kubernetes SlackSIG Storage 交流频道是与SIG Storage 和迁移工作组团队联系的良好媒介。
特别感谢以下人员的用心评审、周全考虑和宝贵贡献:
- Fan Baofa (carlory)
- Jan Šafránek (jsafrane)
- Xing Yang (xing-yang)
- Matthew Wong (wongma7)
如果你有兴趣参与 CSI 或 Kubernetes Storage 系统任何部分的设计和开发,请加入Kubernetes Storage SIG。我们正在快速成长,始终欢迎新的贡献者。