永久卷
本文档描述了 Kubernetes 中的 持久卷。建议熟悉 卷、StorageClass 和 VolumeAttributesClass。
简介
管理存储与管理计算实例是不同的问题。PersistentVolume 子系统为用户和管理员提供了一个 API,它抽象了存储提供方式和消费方式的细节。为此,我们引入了两个新的 API 资源:PersistentVolume 和 PersistentVolumeClaim。
PersistentVolume (PV) 是集群中的一块存储,它由管理员配置或者使用 Storage Class 动态配置。就像节点是集群资源一样,它也是集群中的一个资源。PV 是与 Volume 类似的卷插件,但其生命周期独立于使用该 PV 的任何独立 Pod。此 API 对象捕获了存储实现的细节,可以是 NFS、iSCSI 或云厂商特定的存储系统。
PersistentVolumeClaim (PVC) 是用户对存储的请求。它类似于 Pod。Pod 消耗节点资源,而 PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存)。PVC 可以请求特定大小和访问模式(例如,可以挂载为 ReadWriteOnce、ReadOnlyMany、ReadWriteMany 或 ReadWriteOncePod,参阅 访问模式)。
尽管 PersistentVolumeClaims 允许用户使用抽象的存储资源,但用户通常需要具有不同属性(例如性能)的 PersistentVolumes 来解决不同的问题。集群管理员需要能够提供各种不同于大小和访问模式的 PersistentVolumes,同时不向用户暴露这些卷的实现细节。为此,存在 StorageClass 资源。
参阅包含工作示例的详细演练。
卷和 PVC 的生命周期
PV 是集群中的资源。PVC 是对这些资源的请求,也起到对资源的认领作用。PV 和 PVC 之间的交互遵循此生命周期:
供应
PV 的供应方式有两种:静态或动态。
静态
集群管理员创建一些 PV。它们带有实际存储的细节,可供集群用户使用。它们存在于 Kubernetes API 中,可供使用。
动态
当管理员创建的静态 PV 无法满足用户的 PersistentVolumeClaim 时,集群可能会尝试为该 PVC 动态供应一个卷。此供应基于 StorageClasses:PVC 必须请求一个存储类,且管理员必须已创建并配置了该 StorageClass 才能进行动态供应。请求 StorageClass 为 ""
的 PVC 会实际禁用自身的动态供应。
要启用基于 StorageClass 的动态存储供应,集群管理员需要在 API 服务器上启用 DefaultStorageClass
准入控制器。例如,可以通过确保在 API 服务器组件的 --enable-admission-plugins
参数的逗号分隔有序值列表中包含 DefaultStorageClass
来实现这一点。有关 API 服务器命令行参数的更多信息,请查阅 kube-apiserver 文档。
Binding
用户创建,或在动态供应的情况下,已经创建了一个 PersistentVolumeClaim,其中指定了请求的存储量和某些访问模式。控制平面中的一个控制循环监控新的 PVC,查找匹配的 PV(如果可能),并将它们绑定在一起。如果为新的 PVC 动态供应了 PV,该循环将始终把该 PV 绑定到 PVC。否则,用户将始终获得至少他们请求的资源,但卷可能超出请求的大小。一旦绑定,PersistentVolumeClaim 绑定是排他的,无论它们如何绑定。PVC 到 PV 的绑定是一对一的映射,使用 ClaimRef,它是一个 PersistentVolume 和 PersistentVolumeClaim 之间的双向绑定。
如果不存在匹配的卷,PVC 将无限期保持未绑定状态。随着匹配的卷可用,PVC 将被绑定。例如,如果集群供应了许多 50Gi 的 PV,将无法匹配请求 100Gi 的 PVC。当一个 100Gi 的 PV 被添加到集群时,该 PVC 就可以被绑定。
使用
Pod 将 PVC 用作卷。集群会检查 PVC,找到绑定的卷,并将其挂载到 Pod 中。对于支持多种访问模式的卷,用户在使用其 PVC 作为 Pod 中的卷时指定所需的模式。
一旦用户拥有一个 PVC 并且该 PVC 已绑定,绑定的 PV 就属于该用户,直到他们不再需要为止。用户通过在 Pod 的 volumes
块中包含 persistentVolumeClaim
部分来调度 Pod 并访问其声明的 PV。有关这方面的更多详细信息,请参阅将 PVC 作为卷。
使用中存储对象保护
“使用中存储对象保护”功能的目的是确保 Pod 正在使用的 PersistentVolumeClaims (PVC) 以及绑定到 PVC 的 PersistentVolume (PV) 不会被从系统中移除,因为这可能导致数据丢失。
说明
当存在一个正在使用该 PVC 的 Pod 对象时,该 PVC 被 Pod 正在使用中。如果用户删除 Pod 正在使用的 PVC,PVC 不会立即被移除。PVC 的移除将被推迟,直到没有任何 Pod 再使用该 PVC。同样,如果管理员删除绑定到 PVC 的 PV,PV 不会立即被移除。PV 的移除将被推迟,直到 PV 不再绑定到任何 PVC。
当 PVC 的状态为 Terminating
且 Finalizers
列表中包含 kubernetes.io/pvc-protection
时,你可以看到该 PVC 受到保护。
kubectl describe pvc hostpath
Name: hostpath
Namespace: default
StorageClass: example-hostpath
Status: Terminating
Volume:
Labels: <none>
Annotations: volume.beta.kubernetes.io/storage-class=example-hostpath
volume.beta.kubernetes.io/storage-provisioner=example.com/hostpath
Finalizers: [kubernetes.io/pvc-protection]
...
当 PV 的状态为 Terminating
且 Finalizers
列表中也包含 kubernetes.io/pv-protection
时,你可以看到该 PV 受到保护。
kubectl describe pv task-pv-volume
Name: task-pv-volume
Labels: type=local
Annotations: <none>
Finalizers: [kubernetes.io/pv-protection]
StorageClass: standard
Status: Terminating
Claim:
Reclaim Policy: Delete
Access Modes: RWO
Capacity: 1Gi
Message:
Source:
Type: HostPath (bare host directory volume)
Path: /tmp/data
HostPathType:
Events: <none>
回收
用户不再需要卷时,可以从 API 中删除 PVC 对象,从而允许回收资源。PersistentVolume 的回收策略指示集群在卷解除绑定后如何处理该卷。目前,卷可以被 Retained(保留)、Recycled(回收)或 Deleted(删除)。
Retain(保留)
Retain
回收策略允许手动回收资源。当 PersistentVolumeClaim 被删除时,PersistentVolume 仍然存在,卷被认为是“已释放”。但它尚未可用于新的 PVC,因为前一个 PVC 的数据仍然留在卷中。管理员可以按照以下步骤手动回收卷。
- 删除 PersistentVolume。关联的外部基础设施中的存储资产在 PV 被删除后仍然存在。
- 手动清理关联存储资产上的数据。
- 手动删除关联存储资产。
如果要重用相同的存储资产,请创建具有相同存储资产定义的新 PersistentVolume。
Delete(删除)
对于支持 Delete
回收策略的卷插件,删除操作将从 Kubernetes 中移除 PersistentVolume 对象,同时也会移除外部基础设施中关联的存储资产。动态供应的卷继承其 StorageClass 的回收策略,该策略默认为 Delete
。管理员应根据用户的期望配置 StorageClass;否则,必须在 PV 创建后对其进行编辑或修补。参阅更改 PersistentVolume 的回收策略。
Recycle(回收)
警告
Recycle
回收策略已弃用。推荐的方法是改用动态供应。如果底层卷插件支持,Recycle
回收策略会对卷执行基本清除(rm -rf /thevolume/*
),并使其再次可用于新的 PVC。
然而,管理员可以使用 Kubernetes 控制器管理器命令行参数配置自定义回收器 Pod 模板,如参考文档所述。自定义回收器 Pod 模板必须包含一个 volumes
规范,如下例所示:
apiVersion: v1
kind: Pod
metadata:
name: pv-recycler
namespace: default
spec:
restartPolicy: Never
volumes:
- name: vol
hostPath:
path: /any/path/will/be/replaced
containers:
- name: pv-recycler
image: "registry.k8s.io/busybox"
command: ["/bin/sh", "-c", "test -e /scrub && rm -rf /scrub/..?* /scrub/.[!.]* /scrub/* && test -z \"$(ls -A /scrub)\" || exit 1"]
volumeMounts:
- name: vol
mountPath: /scrub
然而,自定义回收器 Pod 模板中 volumes
部分指定的特定路径将被替换为正在回收的卷的特定路径。
PersistentVolume 删除保护终结器
Kubernetes v1.33 [stable]
(默认启用:true)可以在 PersistentVolume 上添加终结器,以确保具有 Delete
回收策略的 PersistentVolume 仅在后端存储被删除后才被删除。
终结器 external-provisioner.volume.kubernetes.io/finalizer
(v1.31 中引入)被添加到动态供应和静态供应的 CSI 卷中。
终结器 kubernetes.io/pv-controller
(v1.31 中引入)被添加到动态供应的树内插件卷中,并跳过静态供应的树内插件卷。
以下是一个动态供应的树内插件卷的示例:
kubectl describe pv pvc-74a498d6-3929-47e8-8c02-078c1ece4d78
Name: pvc-74a498d6-3929-47e8-8c02-078c1ece4d78
Labels: <none>
Annotations: kubernetes.io/createdby: vsphere-volume-dynamic-provisioner
pv.kubernetes.io/bound-by-controller: yes
pv.kubernetes.io/provisioned-by: kubernetes.io/vsphere-volume
Finalizers: [kubernetes.io/pv-protection kubernetes.io/pv-controller]
StorageClass: vcp-sc
Status: Bound
Claim: default/vcp-pvc-1
Reclaim Policy: Delete
Access Modes: RWO
VolumeMode: Filesystem
Capacity: 1Gi
Node Affinity: <none>
Message:
Source:
Type: vSphereVolume (a Persistent Disk resource in vSphere)
VolumePath: [vsanDatastore] d49c4a62-166f-ce12-c464-020077ba5d46/kubernetes-dynamic-pvc-74a498d6-3929-47e8-8c02-078c1ece4d78.vmdk
FSType: ext4
StoragePolicyName: vSAN Default Storage Policy
Events: <none>
终结器 external-provisioner.volume.kubernetes.io/finalizer
被添加到 CSI 卷。以下是一个示例:
Name: pvc-2f0bab97-85a8-4552-8044-eb8be45cf48d
Labels: <none>
Annotations: pv.kubernetes.io/provisioned-by: csi.vsphere.vmware.com
Finalizers: [kubernetes.io/pv-protection external-provisioner.volume.kubernetes.io/finalizer]
StorageClass: fast
Status: Bound
Claim: demo-app/nginx-logs
Reclaim Policy: Delete
Access Modes: RWO
VolumeMode: Filesystem
Capacity: 200Mi
Node Affinity: <none>
Message:
Source:
Type: CSI (a Container Storage Interface (CSI) volume source)
Driver: csi.vsphere.vmware.com
FSType: ext4
VolumeHandle: 44830fa8-79b4-406b-8b58-621ba25353fd
ReadOnly: false
VolumeAttributes: storage.kubernetes.io/csiProvisionerIdentity=1648442357185-8081-csi.vsphere.vmware.com
type=vSphere CNS Block Volume
Events: <none>
当特定树内卷插件启用 CSIMigration{provider}
功能门时,kubernetes.io/pv-controller
终结器将被 external-provisioner.volume.kubernetes.io/finalizer
终结器替换。
终结器确保 PV 对象仅在卷从存储后端被删除后才被移除,前提是 PV 的回收策略为 Delete
。这也确保无论 PV 和 PVC 的删除顺序如何,卷都会从存储后端被删除。
预留 PersistentVolume
控制平面可以将 PersistentVolumeClaims 绑定到集群中匹配的 PersistentVolumes。但是,如果你希望某个 PVC 绑定到特定的 PV,则需要预绑定它们。
通过在 PersistentVolumeClaim 中指定 PersistentVolume,你声明了该特定 PV 和 PVC 之间的绑定。如果 PersistentVolume 存在且尚未通过其 claimRef
字段预留给其他 PersistentVolumeClaims,则 PersistentVolume 和 PersistentVolumeClaim 将被绑定。
绑定发生时会忽略某些卷匹配条件,包括节点亲和性。控制平面仍然会检查存储类、访问模式和请求存储大小是否有效。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: foo-pvc
namespace: foo
spec:
storageClassName: "" # Empty string must be explicitly set otherwise default StorageClass will be set
volumeName: foo-pv
...
此方法不保证 PersistentVolume 拥有任何绑定特权。如果其他 PersistentVolumeClaims 可以使用你指定的 PV,你需要先预留该存储卷。在 PV 的 claimRef
字段中指定相关的 PersistentVolumeClaim,以便其他 PVC 无法绑定到它。
apiVersion: v1
kind: PersistentVolume
metadata:
name: foo-pv
spec:
storageClassName: ""
claimRef:
name: foo-pvc
namespace: foo
...
如果你想使用 persistentVolumeReclaimPolicy
设置为 Retain
的 PersistentVolumes,这很有用,包括重用现有 PV 的情况。
扩展 PersistentVolumeClaims
Kubernetes v1.24 [stable]
默认启用扩展 PersistentVolumeClaims (PVC) 的支持。你可以扩展以下类型的卷:
- csi(包括一些 CSI 迁移的卷类型)
- flexVolume(已弃用)
- portworxVolume(已弃用)
只有当 PVC 的 StorageClass 的 allowVolumeExpansion
字段设置为 true 时,才能扩展该 PVC。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: example-vol-default
provisioner: vendor-name.example/magicstorage
parameters:
resturl: "http://192.168.10.100:8080"
restuser: ""
secretNamespace: ""
secretName: ""
allowVolumeExpansion: true
要为 PVC 请求更大的卷,请编辑 PVC 对象并指定更大的大小。这将触发扩展支持底层 PersistentVolume 的卷。永远不会创建新的 PersistentVolume 来满足请求。相反,现有卷会被调整大小。
警告
直接编辑 PersistentVolume 的大小可能会阻止该卷的自动调整大小。如果你编辑 PersistentVolume 的容量,然后编辑匹配的 PersistentVolumeClaim 的.spec
以使 PersistentVolumeClaim 的大小与 PersistentVolume 匹配,则不会发生存储调整大小。Kubernetes 控制平面将看到两个资源的期望状态匹配,并断定后端卷大小已手动增加,无需调整大小。CSI 卷扩展
Kubernetes v1.24 [stable]
默认启用 CSI 卷扩展的支持,但这要求特定的 CSI 驱动程序支持卷扩展。有关更多信息,请参阅特定 CSI 驱动程序的文档。
调整包含文件系统的卷的大小
只有当文件系统是 XFS、Ext3 或 Ext4 时,才能调整包含文件系统的卷的大小。
当卷包含文件系统时,文件系统仅在新的 Pod 以 ReadWrite
模式使用 PersistentVolumeClaim 时才会被调整大小。文件系统扩展可以在 Pod 启动时进行,或者在 Pod 正在运行且底层文件系统支持在线扩展时进行。
FlexVolumes(自 Kubernetes v1.23 起已弃用)允许在驱动程序配置 RequiresFSResize
能力为 true
时调整大小。FlexVolume 可以在 Pod 重启时调整大小。
调整正在使用的 PersistentVolumeClaim 的大小
Kubernetes v1.24 [stable]
在这种情况下,你无需删除并重新创建正在使用现有 PVC 的 Pod 或 Deployment。只要文件系统已扩展,任何正在使用的 PVC 都会自动对其 Pod 可用。此功能对未被 Pod 或 Deployment 使用的 PVC 无效。你必须创建一个使用该 PVC 的 Pod,扩展才能完成。
与其它卷类型类似 - FlexVolume 卷在被 Pod 使用时也可以扩展。
说明
FlexVolume 调整大小仅在底层驱动程序支持调整大小时才可能。卷扩展失败后的恢复
如果用户指定的新大小超出了底层存储系统的承受范围,PVC 的扩展将持续重试,直到用户或集群管理员采取行动。这可能是不可取的,因此 Kubernetes 提供了以下方法来从此类故障中恢复。
如果扩展底层存储失败,集群管理员可以手动恢复 Persistent Volume Claim (PVC) 状态并取消调整大小请求。否则,控制器将持续重试调整大小请求,无需管理员干预。
- 将绑定到 PersistentVolumeClaim(PVC) 的 PersistentVolume(PV) 标记为
Retain
回收策略。 - 删除 PVC。由于 PV 具有
Retain
回收策略,重新创建 PVC 时不会丢失任何数据。 - 从 PV 规范中删除
claimRef
条目,以便新的 PVC 可以绑定到它。这应该会使 PV 变为Available
状态。 - 重新创建大小小于 PV 的 PVC,并将 PVC 的
volumeName
字段设置为 PV 的名称。这应该会将新 PVC 绑定到现有 PV。 - 不要忘记恢复 PV 的回收策略。
Kubernetes v1.32 [beta]
(默认启用:true)说明
通过用户恢复失败的 PVC 扩展(RecoverVolumeExpansionFailure
)自 Kubernetes 1.32 起作为 Beta 特性可用,并且应该默认启用。有关更多信息,请参阅功能门文档。使用 RecoverVolumeExpansionFailure
特性时,如果 PVC 扩展失败,你可以使用小于先前请求的值来重试扩展。要请求以较小的建议大小进行新的扩展尝试,请编辑该 PVC 的 .spec.resources
并选择一个小于先前尝试的值。如果由于容量限制而导致扩展到较大值未能成功,此方法很有用。如果发生这种情况,或者你怀疑可能发生这种情况,你可以通过指定一个在底层存储提供商容量限制范围内的尺寸来重试扩展。可以通过观察 PVC 的 .status.allocatedResourceStatuses
和事件来监控调整大小操作的状态。
请注意,尽管你可以指定比先前请求的存储量更小的数量,但新值仍必须高于 .status.capacity
。Kubernetes 不支持将 PVC 缩小到小于其当前大小。
PersistentVolume 类型
PersistentVolume 类型以插件形式实现。Kubernetes 目前支持以下插件:
csi
- 容器存储接口 (CSI)fc
- 光纤通道 (FC) 存储hostPath
- HostPath 卷(仅用于单节点测试;在多节点集群中**无法工作**;考虑改用local
卷)iscsi
- iSCSI (SCSI over IP) 存储local
- 挂载在节点上的本地存储设备。nfs
- 网络文件系统 (NFS) 存储
以下 PersistentVolume 类型已弃用,但仍然可用。如果你正在使用 flexVolume
、cephfs
和 rbd
之外的这些卷类型,请安装相应的 CSI 驱动程序。
awsElasticBlockStore
- AWS Elastic Block Store (EBS)(自 v1.23 起默认启用迁移)azureDisk
- Azure Disk(自 v1.23 起默认启用迁移)azureFile
- Azure File(自 v1.24 起默认启用迁移)cinder
- Cinder (OpenStack 块存储)(自 v1.21 起默认启用迁移)flexVolume
- FlexVolume(自 v1.23 起已**弃用**,无迁移计划,也无移除支持计划)gcePersistentDisk
- GCE Persistent Disk(自 v1.23 起默认启用迁移)portworxVolume
- Portworx 卷(自 v1.31 起默认启用迁移)vsphereVolume
- vSphere VMDK 卷(自 v1.25 起默认启用迁移)
旧版本的 Kubernetes 也支持以下树内 PersistentVolume 类型:
cephfs
(自 v1.31 起**不再可用**)flocker
- Flocker 存储。(自 v1.25 起**不再可用**)glusterfs
- GlusterFS 存储。(自 v1.26 起**不再可用**)photonPersistentDisk
- Photon controller 持久盘。(自 v1.15 起**不再可用**)quobyte
- Quobyte 卷。(自 v1.25 起**不再可用**)rbd
- Rados 块设备 (RBD) 卷(自 v1.31 起**不再可用**)scaleIO
- ScaleIO 卷。(自 v1.21 起**不再可用**)storageos
- StorageOS 卷。(自 v1.25 起**不再可用**)
永久卷
每个 PV 都包含一个 spec 和 status,它们是卷的规范和状态。PersistentVolume 对象的名称必须是合法的 DNS 子域名。
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp
server: 172.17.0.2
说明
卷类型相关的辅助程序可能需要才能在集群中使用 PersistentVolume。在此示例中,PersistentVolume 类型为 NFS,并且需要辅助程序 /sbin/mount.nfs 来支持挂载 NFS 文件系统。容量
通常,PV 会有一个特定的存储容量。这通过 PV 的 capacity
属性设置,该属性是一个Quantity 值。
目前,存储大小是唯一可以设置或请求的资源。未来的属性可能包括 IOPS、吞吐量等。
卷模式
Kubernetes v1.18 [stable]
Kubernetes 支持两种 PersistentVolume 的 volumeModes
:Filesystem
和 Block
。
volumeMode
是一个可选的 API 参数。当省略 volumeMode
参数时,默认模式为 Filesystem
。
具有 volumeMode: Filesystem
的卷被**挂载**到 Pod 的某个目录中。如果卷由块设备支持且设备为空,Kubernetes 会在首次挂载前在该设备上创建文件系统。
你可以将 volumeMode
的值设置为 Block
以将卷用作裸块设备。此类卷作为块设备呈现在 Pod 中,其上没有文件系统。这种模式对于为 Pod 提供访问卷的最快方式非常有用,无需 Pod 和卷之间有文件系统层。另一方面,在 Pod 中运行的应用程序必须知道如何处理裸块设备。有关如何在 Pod 中使用 volumeMode: Block
的卷的示例,请参阅裸块卷支持。
访问模式
PersistentVolume 可以通过资源提供商支持的任何方式挂载到主机上。如下表所示,提供商将具有不同的能力,每个 PV 的访问模式被设置为该特定卷支持的特定模式。例如,NFS 可以支持多个读/写客户端,但特定的 NFS PV 可能在服务器上被导出为只读。每个 PV 都有自己的一组访问模式,描述了该特定 PV 的能力。
访问模式有:
ReadWriteOnce
- 该卷可以被单个节点以读写模式挂载。当 Pod 运行在同一节点上时,ReadWriteOnce 访问模式仍然允许多个 Pod 访问(读取或写入)该卷。对于单个 Pod 访问,请参阅 ReadWriteOncePod。
ReadOnlyMany
- 该卷可以被许多节点以只读模式挂载。
ReadWriteMany
- 该卷可以被许多节点以读写模式挂载。
ReadWriteOncePod
- 特性状态:该卷可以被单个 Pod 以读写模式挂载。如果你想确保在整个集群中只有一个 Pod 可以读取或写入该 PVC,请使用 ReadWriteOncePod 访问模式。
Kubernetes v1.29 [stable]
在 CLI 中,访问模式缩写为:
- RWO - ReadWriteOnce
- ROX - ReadOnlyMany
- RWX - ReadWriteMany
- RWOP - ReadWriteOncePod
说明
Kubernetes 使用卷访问模式来匹配 PersistentVolumeClaims 和 PersistentVolumes。在某些情况下,卷访问模式也限制了 PersistentVolume 可以挂载的位置。卷访问模式不会在存储挂载后强制执行写入保护。即使访问模式被指定为 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany,它们也不会对卷设置任何限制。例如,即使 PersistentVolume 被创建为 ReadOnlyMany,也不能保证它是只读的。如果访问模式被指定为 ReadWriteOncePod,则卷受到限制,只能挂载到单个 Pod 上。重要提示! 一个卷一次只能使用一种访问模式挂载,即使它支持多种模式。
卷插件 | ReadWriteOnce | ReadOnlyMany | ReadWriteMany | ReadWriteOncePod |
---|---|---|---|---|
AzureFile | ✓ | ✓ | ✓ | - |
CephFS | ✓ | ✓ | ✓ | - |
CSI | 取决于驱动程序 | 取决于驱动程序 | 取决于驱动程序 | 取决于驱动程序 |
FC | ✓ | ✓ | - | - |
FlexVolume | ✓ | ✓ | 取决于驱动程序 | - |
HostPath | ✓ | - | - | - |
iSCSI | ✓ | ✓ | - | - |
NFS | ✓ | ✓ | ✓ | - |
RBD | ✓ | ✓ | - | - |
VsphereVolume | ✓ | - | - (Pod 在同一位置时可用) | - |
PortworxVolume | ✓ | - | ✓ | - |
类
PV 可以有一个类,通过将 storageClassName
属性设置为 StorageClass 的名称来指定。特定类的 PV 只能绑定到请求该类的 PVC。没有 storageClassName
的 PV 没有类,只能绑定到不请求特定类的 PVC。
过去,使用注解 volume.beta.kubernetes.io/storage-class
代替 storageClassName
属性。该注解仍然有效;但是,它将在未来的 Kubernetes 版本中完全弃用。
回收策略
当前的回收策略有
- Retain -- 手动回收
- Recycle -- 基本擦除(
rm -rf /thevolume/*
) - Delete -- 删除卷
对于 Kubernetes 1.33,只有 nfs
和 hostPath
卷类型支持回收。
挂载选项
Kubernetes 管理员可以为 Persistent Volume 挂载到节点时指定额外的挂载选项。
说明
并非所有 Persistent Volume 类型都支持挂载选项。以下卷类型支持挂载选项
csi
(包括 CSI 迁移的卷类型)iscsi
nfs
挂载选项未经验证。如果挂载选项无效,则挂载会失败。
过去,使用注解 volume.beta.kubernetes.io/mount-options
代替 mountOptions
属性。该注解仍然有效;但是,它将在未来的 Kubernetes 版本中完全弃用。
节点亲和性
说明
对于大多数卷类型,你不需要设置此字段。对于 local 卷,你需要显式设置此字段。PV 可以指定节点亲和性来定义限制,限制该卷可以从哪些节点访问。使用 PV 的 Pod 只会被调度到节点亲和性选择的节点上。要指定节点亲和性,请在 PV 的 .spec
中设置 nodeAffinity
。PersistentVolume API 参考中提供了有关此字段的更多详细信息。
阶段
PersistentVolume 将处于以下阶段之一
Available
- 尚未绑定到声明的空闲资源
Bound
- 卷已绑定到声明
Released
- 声明已被删除,但关联的存储资源尚未被集群回收
Failed
- 卷的(自动)回收失败
你可以使用 kubectl describe persistentvolume <name>
查看绑定到 PV 的 PVC 名称。
阶段转换时间戳
Kubernetes v1.31 [stable]
(默认启用: true)PersistentVolume 的 .status
字段可以包含一个 Alpha 阶段的 lastPhaseTransitionTime
字段。此字段记录了卷上次转换阶段的时间戳。对于新创建的卷,阶段设置为 Pending
,lastPhaseTransitionTime
设置为当前时间。
PersistentVolumeClaims
每个 PVC 都包含一个 spec 和 status,分别是声明的规范和状态。PersistentVolumeClaim 对象的名称必须是有效的 DNS 子域名。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 8Gi
storageClassName: slow
selector:
matchLabels:
release: "stable"
matchExpressions:
- {key: environment, operator: In, values: [dev]}
访问模式
声明在请求具有特定访问模式的存储时使用与卷相同的约定。
卷模式
声明使用与卷相同的约定来指示将卷用作文件系统还是块设备。
卷名称
声明可以使用 volumeName
字段显式绑定到特定的 PersistentVolume。你也可以将 volumeName
留空,表示希望 Kubernetes 设置一个与声明匹配的新 PersistentVolume。如果指定的 PV 已经绑定到另一个 PVC,则绑定将停留在 Pending 状态。
资源
声明(如 Pod)可以请求特定数量的资源。在此情况下,请求的是存储资源。相同的资源模型适用于卷和声明。
说明
对于Filesystem
卷,存储请求指的是“外部”卷大小(即从存储后端分配的大小)。这意味着对于那些在块设备之上构建文件系统的提供者,可写大小可能会略低,因为存在文件系统开销。使用 XFS 时尤其明显,因为许多元数据特性默认是启用的。选择器
声明可以指定标签选择器来进一步过滤卷集合。只有标签匹配选择器的卷才能绑定到声明。选择器可以包含两个字段
matchLabels
- 卷必须具有带有此值的标签matchExpressions
- 通过指定键、值列表以及关联键和值的操作符来构成的一系列要求。有效的操作符包括In
、NotIn
、Exists
和DoesNotExist
。
来自 matchLabels
和 matchExpressions
的所有要求都通过逻辑与 (AND) 组合在一起 – 它们必须全部满足才能匹配。
类
声明可以通过使用属性 storageClassName
指定 StorageClass 的名称来请求特定类。只有所请求类的 PV,即与 PVC 具有相同 storageClassName
的 PV,才能绑定到 PVC。
PVC 未必需要请求一个类。storageClassName
设置为 ""
的 PVC 始终被解释为请求一个没有类的 PV,因此它只能绑定到没有类的 PV(没有注解或注解值设置为 ""
)。没有 storageClassName
的 PVC 与此略有不同,并且根据 DefaultStorageClass
准入控制器插件是否开启,集群会以不同的方式处理它们。
- 如果准入控制器插件开启,管理员可以指定一个默认 StorageClass。所有没有
storageClassName
的 PVC 只能绑定到该默认 StorageClass 的 PV。指定默认 StorageClass 的方法是在 StorageClass 对象中将注解storageclass.kubernetes.io/is-default-class
设置为true
。如果管理员未指定默认 StorageClass,集群对 PVC 创建的响应就如同准入控制器插件关闭一样。如果指定了多个默认 StorageClass,则在动态创建 PVC 时使用最新的默认 StorageClass。 - 如果准入控制器插件关闭,则没有默认 StorageClass 的概念。所有将
storageClassName
设置为""
的 PVC 只能绑定到也将storageClassName
设置为""
的 PV。然而,缺少storageClassName
的 PVC 可以在默认 StorageClass 可用后更新。如果 PVC 被更新,它将不再绑定到也将storageClassName
设置为""
的 PV。
有关详细信息,请参阅回溯性默认 StorageClass 分配。
根据安装方法,可能在安装期间通过 addon manager 将默认 StorageClass 部署到 Kubernetes 集群。
当 PVC 除了请求 StorageClass 外还指定了 selector
时,要求会通过逻辑与 (AND) 组合:只有所请求类且带有请求标签的 PV 才能绑定到 PVC。
说明
目前,带有非空selector
的 PVC 无法为其动态创建 PV。过去,使用注解 volume.beta.kubernetes.io/storage-class
代替 storageClassName
属性。该注解仍然有效;但是,它将在未来的 Kubernetes 版本中不再受支持。
回溯性默认 StorageClass 分配
Kubernetes v1.28 [stable]
你可以创建 PersistentVolumeClaim 时不为新的 PVC 指定 storageClassName
,即使集群中不存在默认 StorageClass 也可以这样做。在这种情况下,新的 PVC 会按你定义的方式创建,并且该 PVC 的 storageClassName
会保持未设置状态,直到默认 StorageClass 可用。
当默认 StorageClass 可用时,控制平面会识别任何现有的没有 storageClassName
的 PVC。对于那些 storageClassName
为空值或没有此键的 PVC,控制平面会更新这些 PVC,将 storageClassName
设置为匹配新的默认 StorageClass。如果你有一个现有的 PVC,其 storageClassName
为 ""
,并且你配置了一个默认 StorageClass,则此 PVC 将不会被更新。
为了(在存在默认 StorageClass 的同时)保持与 storageClassName
设置为 ""
的 PV 绑定,你需要将关联 PVC 的 storageClassName
设置为 ""
。
这种行为有助于管理员更改默认 StorageClass,方法是先移除旧的默认 StorageClass,然后创建或设置另一个。在这段没有默认 StorageClass 的短暂时间内创建的 PVC 不会有默认 StorageClass,但由于回溯性默认 StorageClass 分配机制,这种更改默认值的方式是安全的。
将声明作为卷
Pod 通过将声明用作卷来访问存储。声明必须与使用声明的 Pod 位于同一命名空间中。集群会在 Pod 的命名空间中找到该声明,并使用它来获取支持该声明的 PersistentVolume。然后该卷将被挂载到宿主机和 Pod 中。
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim
关于命名空间的说明
PersistentVolumes 的绑定是排他性的,并且由于 PersistentVolumeClaims 是命名空间对象,因此以“Many”模式(ROX
、RWX
)挂载声明只能在一个命名空间内进行。
hostPath
类型的 PersistentVolumes
hostPath
PersistentVolume 使用节点上的文件或目录来模拟网络附加存储。请参阅hostPath
类型卷的示例。
裸块卷支持
Kubernetes v1.18 [stable]
以下卷插件支持裸块卷,包括适用的动态创建功能
- CSI(包括一些 CSI 迁移的卷类型)
- FC (Fibre Channel)
- iSCSI
- 本地卷
使用裸块卷的 PersistentVolume
apiVersion: v1
kind: PersistentVolume
metadata:
name: block-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
volumeMode: Block
persistentVolumeReclaimPolicy: Retain
fc:
targetWWNs: ["50060e801049cfd1"]
lun: 0
readOnly: false
请求裸块卷的 PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: block-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Block
resources:
requests:
storage: 10Gi
在容器中添加裸块设备路径的 Pod 规范
apiVersion: v1
kind: Pod
metadata:
name: pod-with-block-volume
spec:
containers:
- name: fc-container
image: fedora:26
command: ["/bin/sh", "-c"]
args: [ "tail -f /dev/null" ]
volumeDevices:
- name: data
devicePath: /dev/xvda
volumes:
- name: data
persistentVolumeClaim:
claimName: block-pvc
说明
为 Pod 添加裸块设备时,你在容器中指定设备路径,而不是挂载路径。绑定块卷
如果用户通过在 PersistentVolumeClaim 规范中使用 volumeMode
字段来请求裸块卷,则绑定规则与之前不将此模式视为规范一部分的版本略有不同。下表列出了用户和管理员为请求裸块设备可能指定的组合。该表指明了在给定组合下,卷是否会绑定:静态创建卷的卷绑定矩阵
PV volumeMode | PVC volumeMode | 结果 |
---|---|---|
未指定 | 未指定 | 绑定 (BIND) |
未指定 | Block | 不绑定 (NO BIND) |
未指定 | Filesystem | 绑定 (BIND) |
Block | 未指定 | 不绑定 (NO BIND) |
Block | Block | 绑定 (BIND) |
Block | Filesystem | 不绑定 (NO BIND) |
Filesystem | Filesystem | 绑定 (BIND) |
Filesystem | Block | 不绑定 (NO BIND) |
Filesystem | 未指定 | 绑定 (BIND) |
说明
对于 Alpha 版本仅支持静态创建卷。管理员在使用裸块设备时应注意考虑这些值。卷快照和从快照恢复卷支持
Kubernetes v1.20 [stable]
卷快照仅支持树外 CSI 卷插件。详情请参阅卷快照。树内卷插件已弃用。你可以在卷插件常见问题解答中阅读有关已弃用卷插件的信息。
从卷快照创建 PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: restore-pvc
spec:
storageClassName: csi-hostpath-sc
dataSource:
name: new-snapshot-test
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
卷克隆
卷克隆仅适用于 CSI 卷插件。
从现有 PVC 创建 PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: cloned-pvc
spec:
storageClassName: my-csi-plugin
dataSource:
name: existing-src-pvc-name
kind: PersistentVolumeClaim
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
卷填充器和数据源
Kubernetes v1.24 [beta]
Kubernetes 支持自定义卷填充器。要使用自定义卷填充器,你必须为 kube-apiserver 和 kube-controller-manager 启用 AnyVolumeDataSource
feature gate。
卷填充器利用了 PVC 规范中的一个字段 dataSourceRef
。与只能包含对另一个 PersistentVolumeClaim 或 VolumeSnapshot 的引用的 dataSource
字段不同,dataSourceRef
字段可以包含对同一命名空间中任何对象的引用,核心对象除 PVC 外。对于已启用该 feature gate 的集群,建议优先使用 dataSourceRef
而不是 dataSource
。
跨命名空间数据源
Kubernetes v1.26 [alpha]
Kubernetes 支持跨命名空间卷数据源。要使用跨命名空间卷数据源,你必须为 kube-apiserver 和 kube-controller-manager 启用 AnyVolumeDataSource
和 CrossNamespaceVolumeDataSource
feature gate。此外,你还必须为 csi-provisioner 启用 CrossNamespaceVolumeDataSource
feature gate。
启用 CrossNamespaceVolumeDataSource
feature gate 允许你在 dataSourceRef 字段中指定命名空间。
说明
当你为卷数据源指定命名空间时,Kubernetes 会在接受引用之前,在另一个命名空间中检查是否存在 ReferenceGrant。ReferenceGrant 是gateway.networking.k8s.io
扩展 API 的一部分。有关详细信息,请参阅 Gateway API 文档中的ReferenceGrant。这意味着在使用此机制之前,你的 Kubernetes 集群必须至少通过 Gateway API 扩展 ReferenceGrant。数据源引用
dataSourceRef
字段的行为与 dataSource
字段几乎相同。如果其中一个被指定而另一个未被指定,API 服务器将赋予这两个字段相同的值。创建后两个字段都不能更改,尝试为两个字段指定不同的值将导致验证错误。因此,这两个字段将始终具有相同的内容。
用户应注意 dataSourceRef
字段和 dataSource
字段之间存在两个差异
dataSource
字段会忽略无效值(如同该字段为空白),而dataSourceRef
字段绝不忽略值,并且在使用无效值时会导致错误。无效值是指除了 PVC 之外的任何核心对象(没有 apiGroup 的对象)。dataSourceRef
字段可能包含不同类型的对象,而dataSource
字段只允许 PVC 和 VolumeSnapshot。
当 CrossNamespaceVolumeDataSource
功能启用时,还有一些额外的差异
dataSource
字段只允许本地对象,而dataSourceRef
字段允许任何命名空间中的对象。- 当指定命名空间时,
dataSource
和dataSourceRef
不同步。
在启用了 feature gate 的集群上,用户应始终使用 dataSourceRef
;在未启用的集群上,回退到使用 dataSource
。在任何情况下都无需同时查看这两个字段。具有略微不同语义的重复值仅是为了向后兼容。特别是,新旧控制器可以协同工作,因为这些字段是相同的。
使用卷填充器
卷填充器是控制器,可以创建非空卷,卷的内容由自定义资源确定。用户通过使用 dataSourceRef
字段引用自定义资源来创建填充的卷
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: populated-pvc
spec:
dataSourceRef:
name: example-name
kind: ExampleDataSource
apiGroup: example.storage.k8s.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
由于卷填充器是外部组件,如果未安装所有正确的组件,尝试创建使用卷填充器的 PVC 可能会失败。外部控制器应在 PVC 上生成事件,以提供创建状态的反馈,包括如果因缺少某些组件而无法创建 PVC 的警告。
你可以在集群中安装 Alpha 阶段的卷数据源验证器控制器。该控制器会在没有注册任何填充器来处理该类型的数据源时,在 PVC 上生成警告事件。当为 PVC 安装了合适的填充器后,该填充器控制器负责报告与卷创建和过程中问题相关的事件。
使用跨命名空间卷数据源
Kubernetes v1.26 [alpha]
创建 ReferenceGrant 以允许命名空间所有者接受引用。你通过使用 dataSourceRef
字段指定跨命名空间卷数据源来定义填充的卷。你必须已经在源命名空间中有一个有效的 ReferenceGrant
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-ns1-pvc
namespace: default
spec:
from:
- group: ""
kind: PersistentVolumeClaim
namespace: ns1
to:
- group: snapshot.storage.k8s.io
kind: VolumeSnapshot
name: new-snapshot-demo
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: foo-pvc
namespace: ns1
spec:
storageClassName: example
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
dataSourceRef:
apiGroup: snapshot.storage.k8s.io
kind: VolumeSnapshot
name: new-snapshot-demo
namespace: default
volumeMode: Filesystem
编写可移植配置
如果你正在编写可在各种集群上运行并需要持久存储的配置模板或示例,建议使用以下模式
- 在你的配置包中包含 PersistentVolumeClaim 对象(与 Deployments、ConfigMaps 等一起)。
- 不要在配置中包含 PersistentVolume 对象,因为实例化配置的用户可能没有权限创建 PersistentVolumes。
- 在实例化模板时,给用户提供提供存储类名称的选项。
- 如果用户提供存储类名称,将该值放入
persistentVolumeClaim.storageClassName
字段中。如果集群的管理员启用了 StorageClasses,这将使 PVC 匹配正确的存储类。 - 如果用户未提供存储类名称,则将
persistentVolumeClaim.storageClassName
字段留空(或设为 nil)。这将导致集群中的默认 StorageClass 为用户自动创建 PV。许多集群环境都安装了默认 StorageClass,或者管理员可以创建自己的默认 StorageClass。
- 如果用户提供存储类名称,将该值放入
- 在你的工具中,观察一段时间后仍未被绑定的 PVC,并将此情况告知用户,因为这可能表明集群没有动态存储支持(在这种情况下用户应创建一个匹配的 PV),或者集群没有存储系统(在这种情况下用户无法部署需要 PVC 的配置)。
接下来
- 了解有关创建 PersistentVolume 的更多信息。
- 了解有关创建 PersistentVolumeClaim 的更多信息。
- 阅读持久存储设计文档。
API 参考
阅读本页面中描述的 API