持久卷
本文档描述了 Kubernetes 中的持久卷。建议熟悉 卷、存储类 和 卷属性类。
简介
存储管理与计算实例管理是截然不同的问题。持久卷子系统为用户和管理员提供了 API,将存储提供方式的细节与存储使用方式抽象出来。为此,我们引入了两种新的 API 资源:持久卷和持久卷声明。
持久卷 (PV) 是集群中的一块存储,由管理员配置或使用 存储类 动态配置。它与节点是集群资源一样,也是集群中的资源。PV 与卷一样是卷插件,但拥有独立于使用 PV 的任何 Pod 的生命周期。此 API 对象捕获了存储实现的详细信息,例如 NFS、iSCSI 或特定云提供商的存储系统。
持久卷声明 (PVC) 是用户对存储的请求。它类似于 Pod。Pod 消耗节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存)。声明可以请求特定的大小和访问模式(例如,它们可以被挂载为 ReadWriteOnce、ReadOnlyMany、ReadWriteMany 或 ReadWriteOncePod,请参阅 访问模式)。
尽管持久卷声明允许用户使用抽象存储资源,但用户通常需要具有不同属性的持久卷(例如,性能),以解决不同的问题。集群管理员需要能够提供各种持久卷,这些持久卷在大小和访问模式以外的不同方面有所差异,而不会将用户的细节暴露给这些卷的实现方式。为了满足这些需求,存在存储类资源。
请参阅 使用工作示例的详细演练。
卷和声明的生命周期
PV 是集群中的资源。PVC 是对这些资源的请求,并且还充当对资源的声明检查。PV 和 PVC 之间的交互遵循以下生命周期
配置
PV 可以通过两种方式配置:静态或动态。
静态
集群管理员创建一定数量的 PV。它们包含实际存储的详细信息,这些存储可供集群用户使用。它们存在于 Kubernetes API 中,可供使用。
动态
当管理员创建的静态 PV 中没有一个与用户的持久卷声明匹配时,集群可能会尝试专门为 PVC 动态配置一个卷。这种配置基于存储类:PVC 必须请求 存储类,并且管理员必须创建并配置该类才能进行动态配置。请求类 ""
的声明实际上会为自身禁用动态配置。
要启用基于存储类的动态存储配置,集群管理员需要在 API 服务器上启用 DefaultStorageClass
准入控制器。例如,可以通过确保 DefaultStorageClass
位于 API 服务器组件的 --enable-admission-plugins
标志的值的逗号分隔、有序列表中来实现。有关 API 服务器命令行标志的更多信息,请查看 kube-apiserver 文档。
Binding
用户创建或在动态配置的情况下,已经创建了具有特定请求存储量和某些访问模式的持久卷声明。控制平面中的控制循环会监视新的 PVC,查找匹配的 PV(如果可能),并将它们绑定在一起。如果为新的 PVC 动态配置了 PV,则循环始终将该 PV 绑定到 PVC。否则,用户始终至少会获得他们请求的存储,但卷可能超出请求的存储量。绑定后,持久卷声明绑定是排他的,无论它们是如何绑定的。PVC 到 PV 绑定是一对一的映射,使用 ClaimRef,这在持久卷和持久卷声明之间进行双向绑定。
如果不存在匹配的卷,声明将无限期地保持未绑定状态。声明将在匹配的卷可用时绑定。例如,一个配置了多个 50Gi PV 的集群将不会匹配请求 100Gi 的 PVC。当将 100Gi PV 添加到集群时,可以绑定 PVC。
使用
Pod 将声明用作卷。集群检查声明以查找绑定的卷,并将该卷挂载到 Pod。对于支持多种访问模式的卷,用户在 Pod 中使用其声明作为卷时,指定所需的模式。
一旦用户拥有声明并且该声明已绑定,绑定的 PV 将属于用户,只要他们需要它。用户通过在 Pod 的 volumes
块中包含一个 persistentVolumeClaim
部分来安排 Pod 并访问其声明的 PV。请参阅 声明作为卷,了解有关此方面的更多详细信息。
存储对象使用保护
存储对象使用保护功能的目的是确保 Pod 正在使用的持久卷声明 (PVC) 以及绑定到 PVC 的持久卷 (PV) 不会从系统中删除,因为这可能会导致数据丢失。
注意
当 Pod 对象存在并使用 PVC 时,PVC 正在由 Pod 积极使用。如果用户删除了 Pod 正在使用的 PVC,则 PVC 不会立即删除。PVC 删除会推迟,直到 PVC 不再被任何 Pod 积极使用。此外,如果管理员删除了绑定到 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 对象,以允许回收资源。持久卷的回收策略告诉集群在卷释放其声明后如何处理该卷。当前,卷可以被保留、回收或删除。
保留
Retain
回收策略允许手动回收资源。当持久卷声明被删除时,持久卷仍然存在,并且该卷被认为是“已释放”。但它尚未可用于其他声明,因为以前声明者的数据仍然存在于卷上。管理员可以使用以下步骤手动回收卷。
- 删除持久卷。删除 PV 后,外部基础设施中的关联存储资产仍然存在。
- 相应地手动清理关联存储资产上的数据。
- 手动删除关联存储资产。
如果您想重复使用相同的存储资产,请使用相同的存储资产定义创建一个新的持久卷。
删除
对于支持 Delete
回收策略的卷插件,删除操作会从 Kubernetes 中删除持久卷对象,以及外部基础设施中的关联存储资产。动态配置的卷会继承 其存储类的回收策略,默认值为 Delete
。管理员应根据用户的期望配置存储类;否则,必须在创建 PV 后编辑或修补 PV。请参阅 更改持久卷的回收策略。
回收
警告
Recycle
回收策略已弃用。建议的方法是使用动态配置。如果底层卷插件支持,Recycle
回收策略将在卷上执行基本清理 (rm -rf /thevolume/*
) 并使其可供新的声明使用。
但是,管理员可以使用 Kubernetes 控制器管理器命令行参数配置自定义回收器 Pod 模板,如 参考 中所述。自定义回收器 Pod 模板必须包含 volumes
规范,如下例所示
apiVersion: v1
kind: Pod
metadata:
name: pv-recycler
namespace: default
spec:
restartPolicy: Never
volumes:
- name: vol
hostPath:
path: /any/path/it/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
部分中指定的特定路径将替换为正在回收的卷的特定路径。
持久卷删除保护最终器
Kubernetes v1.31 [beta]
可以在持久卷上添加最终器,以确保只有在备份存储被删除后,才删除具有 Delete
回收策略的持久卷。
最终器 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 的删除顺序如何,都会从存储后端删除卷。
保留持久卷
控制平面可以将持久卷声明绑定到集群中匹配的持久卷。但是,如果您希望 PVC 绑定到特定 PV,则需要预先绑定它们。
通过在持久卷声明中指定持久卷,您声明了该特定 PV 和 PVC 之间的绑定。如果持久卷存在并且未通过其claimRef
字段保留持久卷声明,则持久卷和持久卷声明将被绑定。
绑定发生在某些卷匹配条件(包括节点亲和性)之外。控制平面仍然检查存储类、访问模式和请求的存储大小是否有效。
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
...
此方法不保证持久卷的任何绑定权限。如果其他持久卷声明可以使用您指定的 PV,则需要先保留该存储卷。在 PV 的claimRef
字段中指定相关的持久卷声明,以便其他 PVC 无法绑定到它。
apiVersion: v1
kind: PersistentVolume
metadata:
name: foo-pv
spec:
storageClassName: ""
claimRef:
name: foo-pvc
namespace: foo
...
如果您想要使用其persistentVolumeReclaimPolicy
设置为Retain
的持久卷,这很有用,包括您重用现有 PV 的情况。
扩展持久卷声明
Kubernetes v1.24 [稳定]
默认情况下启用对扩展持久卷声明 (PVC) 的支持。您可以扩展以下类型的卷
- azureFile(已弃用)
- csi
- flexVolume(已弃用)
- rbd(已弃用)
- portworxVolume(已弃用)
只有在存储类的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 对象并指定更大的大小。这将触发对支持底层持久卷的卷的扩展。永远不会创建新的持久卷来满足声明。相反,现有的卷会被调整大小。
警告
直接编辑持久卷的大小可能会阻止该卷的自动调整大小。如果您编辑持久卷的容量,然后编辑匹配的持久卷声明的.spec
以使持久卷声明的大小与持久卷匹配,则不会进行任何存储调整大小。Kubernetes 控制平面将看到这两个资源的期望状态匹配,从而得出结论,支持卷的大小已手动增加,并且不需要调整大小。CSI 卷扩展
Kubernetes v1.24 [稳定]
默认情况下启用对扩展 CSI 卷的支持,但它还需要特定的 CSI 驱动程序来支持卷扩展。有关更多信息,请参阅特定 CSI 驱动程序的文档。
调整包含文件系统的卷的大小
只有在文件系统为 XFS、Ext3 或 Ext4 时,您才能调整包含文件系统的卷的大小。
当卷包含文件系统时,只有当新的 Pod 在ReadWrite
模式下使用持久卷声明时,文件系统才会被调整大小。文件系统扩展是在 Pod 启动时或 Pod 正在运行且底层文件系统支持在线扩展时完成的。
FlexVolume(自 Kubernetes v1.23 起已弃用)允许调整大小,如果驱动程序配置了RequiresFSResize
功能为true
。FlexVolume 可以通过 Pod 重启进行调整大小。
调整正在使用的持久卷声明的大小
Kubernetes v1.24 [稳定]
在这种情况下,您不需要删除和重新创建正在使用现有 PVC 的 Pod 或部署。任何正在使用的 PVC 在其文件系统扩展后会立即对 Pod 可用。此功能对 Pod 或部署未使用的 PVC 没有影响。您必须创建一个使用 PVC 的 Pod,然后扩展才能完成。
与其他卷类型类似 - FlexVolume 卷也可以在 Pod 使用时进行扩展。
注意
只有在底层驱动程序支持调整大小的情况下,FlexVolume 调整大小才有可能。从扩展卷失败中恢复
如果用户指定的新大小超出了底层存储系统的容量,则 PVC 的扩展将持续重试,直到用户或集群管理员采取某些措施。这可能不理想,因此 Kubernetes 提供以下从这种故障中恢复的方法。
如果扩展底层存储失败,集群管理员可以手动恢复持久卷声明 (PVC) 状态并取消调整大小请求。否则,调整大小请求将由控制器在没有管理员干预的情况下持续重试。
- 使用
Retain
回收策略标记绑定到持久卷声明 (PVC) 的持久卷 (PV)。 - 删除 PVC。由于 PV 具有
Retain
回收策略,因此在重新创建 PVC 时不会丢失任何数据。 - 从 PV 规范中删除
claimRef
条目,以便新的 PVC 可以绑定到它。这应该使 PV 变为Available
。 - 重新创建 PVC,大小小于 PV,并将 PVC 的
volumeName
字段设置为 PV 的名称。这应该将新的 PVC 绑定到现有的 PV。 - 不要忘记恢复 PV 的回收策略。
Kubernetes v1.23 [alpha]
注意
自 Kubernetes 1.23 起,用户从失败的 PVC 扩展中恢复的功能已作为 alpha 功能提供。要使此功能正常工作,必须启用RecoverVolumeExpansionFailure
功能。有关更多信息,请参阅功能网关文档。如果您的集群中启用了功能网关RecoverVolumeExpansionFailure
,并且 PVC 的扩展失败,您可以尝试使用小于之前请求的值的大小重新扩展。要尝试使用更小的提议大小进行新的扩展,请编辑该 PVC 的.spec.resources
并选择一个小于您之前尝试的值。如果扩展到更高的值由于容量限制而没有成功,这很有用。如果发生这种情况,或者您怀疑它可能已经发生,您可以通过指定一个在底层存储提供商的容量限制内的尺寸来重新尝试扩展。您可以通过观察.status.allocatedResourceStatuses
和 PVC 上的事件来监控调整大小操作的状态。
请注意,虽然您可以指定少于之前请求的存储量,但新值必须仍然高于.status.capacity
。Kubernetes 不支持将 PVC 缩小到小于其当前大小。
持久卷类型
持久卷类型作为插件实现。Kubernetes 目前支持以下插件
csi
- 容器存储接口 (CSI)fc
- 光纤通道 (FC) 存储hostPath
- HostPath 卷(仅用于单节点测试;在多节点集群中将**无法使用**;请考虑使用local
卷代替)iscsi
- iSCSI(IP 上的 SCSI)存储local
- 安装在节点上的本地存储设备。nfs
- 网络文件系统 (NFS) 存储
以下类型的持久卷已弃用,但仍然可用。如果您正在使用这些卷类型(flexVolume
、cephfs
和rbd
除外),请安装相应的 CSI 驱动程序。
awsElasticBlockStore
- AWS Elastic Block Store (EBS)(**从 v1.23 开始默认启用迁移**)azureDisk
- Azure 磁盘(**从 v1.23 开始默认启用迁移**)azureFile
- Azure 文件(**从 v1.24 开始默认启用迁移**)cinder
- Cinder(OpenStack 块存储)(**从 v1.21 开始默认启用迁移**)flexVolume
- FlexVolume(**从 v1.23 开始弃用**,没有迁移计划,也没有计划删除支持)gcePersistentDisk
- GCE 持久磁盘(**从 v1.23 开始默认启用迁移**)portworxVolume
- Portworx 卷(**从 v1.31 开始默认启用迁移**)vsphereVolume
- vSphere VMDK 卷(**从 v1.25 开始默认启用迁移**)
旧版本的 Kubernetes 还支持以下内建持久卷类型
cephfs
(**从 v1.31 开始不可用**)flocker
- Flocker 存储。(**从 v1.25 开始不可用**)photonPersistentDisk
- Photon 控制器持久磁盘。(**从 v1.15 开始不可用**)quobyte
- Quobyte 卷。(**从 v1.25 开始不可用**)rbd
- Rados 块设备 (RBD) 卷(**从 v1.31 开始不可用**)scaleIO
- ScaleIO 卷。(**从 v1.21 开始不可用**)storageos
- StorageOS 卷。(**从 v1.25 开始不可用**)
持久卷
每个 PV 都包含一个规范和一个状态,它们是卷的规范和状态。持久卷对象的名称必须是有效的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
注意
可能需要与卷类型相关的辅助程序来在集群中使用持久卷。在本例中,持久卷类型为 NFS,需要辅助程序 /sbin/mount.nfs 来支持 NFS 文件系统的挂载。容量
通常,PV 将具有特定的存储容量。这使用 PV 的capacity
属性设置,该属性是一个数量值。
目前,存储大小是唯一可以设置或请求的资源。未来的属性可能包括 IOPS、吞吐量等。
卷模式
Kubernetes v1.18 [稳定]
Kubernetes 支持两种持久卷的volumeModes
:Filesystem
和Block
。
volumeMode
是一个可选的 API 参数。Filesystem
是省略volumeMode
参数时使用的默认模式。
具有volumeMode: Filesystem
的卷被挂载到 Pod 中的目录中。如果卷由块设备支持并且设备为空,Kubernetes 会在首次挂载之前在设备上创建文件系统。
您可以将volumeMode
的值设置为Block
以将卷用作原始块设备。此类卷作为块设备呈现到 Pod 中,没有文件系统。此模式对于为 Pod 提供最快的方式访问卷很有用,Pod 和卷之间没有文件系统层。另一方面,在 Pod 中运行的应用程序必须知道如何处理原始块设备。有关如何在 Pod 中使用具有volumeMode: Block
的卷的示例,请参阅原始块卷支持。
访问模式
持久卷可以以资源提供者支持的任何方式安装在主机上。如下表所示,提供者将具有不同的功能,并且每个 PV 的访问模式都设置为该特定卷支持的特定模式。例如,NFS 可以支持多个读/写客户端,但特定的 NFS PV 可能会在服务器上作为只读导出。每个 PV 都有一组自己的访问模式,描述了该特定 PV 的功能。
访问模式为
ReadWriteOnce
- 该卷可以由单个节点以读写方式挂载。ReadWriteOnce 访问模式仍然允许多个 Pod 在同一个节点上运行时访问卷。对于单个 Pod 访问,请参阅 ReadWriteOncePod。
只读多节点
- 该卷可以被多个节点以只读模式挂载。
读写多节点
- 该卷可以被多个节点以读写模式挂载。
单 Pod 读写
- 功能状态:该卷可以被单个 Pod 以读写模式挂载。如果您希望确保整个集群中只有一个 Pod 可以读取或写入该 PVC,请使用 ReadWriteOncePod 访问模式。
Kubernetes v1.29 [稳定]
在 CLI 中,访问模式缩写为
- RWO - ReadWriteOnce
- ROX - ReadOnlyMany
- RWX - ReadWriteMany
- RWOP - ReadWriteOncePod
注意
Kubernetes 使用卷访问模式来匹配持久卷声明和持久卷。在某些情况下,卷访问模式还会限制持久卷的挂载位置。卷访问模式不会在存储挂载后执行写入保护。即使访问模式指定为 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany,它们也不会对卷设置任何限制。例如,即使持久卷创建为 ReadOnlyMany,也不能保证它是只读的。如果访问模式指定为 ReadWriteOncePod,则卷将受到限制,并且只能挂载在单个 Pod 上。重要! 卷一次只能使用一种访问模式,即使它支持多种访问模式。
卷插件 | ReadWriteOnce | 只读多节点 | 读写多节点 | 单 Pod 读写 |
---|---|---|---|---|
AzureFile | ✓ | ✓ | ✓ | - |
CephFS | ✓ | ✓ | ✓ | - |
CSI | 取决于驱动程序 | 取决于驱动程序 | 取决于驱动程序 | 取决于驱动程序 |
FC | ✓ | ✓ | - | - |
FlexVolume | ✓ | ✓ | 取决于驱动程序 | - |
HostPath | ✓ | - | - | - |
iSCSI | ✓ | ✓ | - | - |
NFS | ✓ | ✓ | ✓ | - |
RBD | ✓ | ✓ | - | - |
VsphereVolume | ✓ | - | - (当 Pod 位于同一位置时有效) | - |
PortworxVolume | ✓ | - | ✓ | - |
类别
PV 可以具有类别,通过将 storageClassName
属性设置为 存储类 的名称来指定类别。特定类别的 PV 只能绑定到请求该类别的 PVC。没有 storageClassName
的 PV 没有类别,只能绑定到不请求特定类别的 PVC。
过去,注释 volume.beta.kubernetes.io/storage-class
用于替代 storageClassName
属性。该注释仍然有效;但是,它将在将来的 Kubernetes 版本中完全弃用。
回收策略
当前的回收策略是
- 保留 - 手动回收
- 回收 - 基本清理 (
rm -rf /thevolume/*
) - 删除 - 删除卷
对于 Kubernetes 1.31,只有 nfs
和 hostPath
卷类型支持回收。
挂载选项
Kubernetes 管理员可以为持久卷挂载在节点上的情况指定额外的挂载选项。
注意
并非所有持久卷类型都支持挂载选项。以下卷类型支持挂载选项
azureFile
cephfs
(在 v1.28 中已弃用)cinder
(在 v1.18 中已弃用)iscsi
nfs
rbd
(在 v1.28 中已弃用)vsphereVolume
挂载选项不会被验证。如果挂载选项无效,则挂载会失败。
过去,注释 volume.beta.kubernetes.io/mount-options
用于替代 mountOptions
属性。该注释仍然有效;但是,它将在将来的 Kubernetes 版本中完全弃用。
节点亲和性
注意
对于大多数卷类型,您不需要设置此字段。您需要为 本地 卷显式设置此字段。PV 可以指定节点亲和性,以定义限制该卷可以从哪些节点访问的约束。使用 PV 的 Pod 只能调度到节点亲和性所选择的节点。要指定节点亲和性,请在 PV 的 .spec
中设置 nodeAffinity
。 持久卷 API 参考提供了有关此字段的更多详细信息。
阶段
持久卷将处于以下阶段之一
可用
- 尚未绑定到声明的空闲资源
已绑定
- 卷已绑定到声明
已释放
- 声明已删除,但关联的存储资源尚未被集群回收
失败
- 卷的(自动)回收失败
您可以使用 kubectl describe persistentvolume <name>
查看绑定到 PV 的 PVC 的名称。
阶段转换时间戳
Kubernetes v1.31 [稳定]
持久卷的 .status
字段可以包含 alpha lastPhaseTransitionTime
字段。此字段记录卷上次转换其阶段的时间戳。对于新创建的卷,阶段设置为 Pending
,lastPhaseTransitionTime
设置为当前时间。
持久卷声明
每个 PVC 包含一个规范和一个状态,它们分别是声明的规范和状态。持久卷声明对象的名称必须是有效的 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]}
访问模式
卷模式
声明使用 与卷相同的约定 来指示卷的消耗方式,无论是文件系统还是块设备。
资源
声明(与 Pod 一样)可以请求特定数量的资源。在这种情况下,请求的是存储。 相同资源模型 适用于卷和声明。
选择器
声明可以指定一个 标签选择器 来进一步筛选卷集。只有标签与选择器匹配的卷才能绑定到声明。选择器可以包含两个字段
matchLabels
- 卷必须具有此值的标签matchExpressions
- 通过指定键、值列表和关联键和值的运算符来指定的一系列要求。有效的运算符包括 In、NotIn、Exists 和 DoesNotExist。
来自 matchLabels
和 matchExpressions
的所有要求都将通过 AND 运算连接在一起 - 它们必须全部满足才能匹配。
类别
声明可以通过使用属性 storageClassName
指定 存储类 的名称来请求特定类别。只有请求类别的 PV(具有与 PVC 相同 storageClassName
的 PV)才能绑定到 PVC。
PVC 不一定必须请求类别。storageClassName
设置为 ""
的 PVC 始终被解释为请求没有类别的 PV,因此它只能绑定到没有类别的 PV(没有注释或设置为 ""
的注释)。没有 storageClassName
的 PVC 并不完全相同,集群对其的处理方式也不同,具体取决于是否启用了 DefaultStorageClass
准入插件。
- 如果准入插件已启用,则管理员可以指定一个默认存储类。所有没有
storageClassName
的 PVC 只能绑定到该默认存储类的 PV。通过在存储类对象中将注释storageclass.kubernetes.io/is-default-class
设置为true
来指定默认存储类。如果管理员未指定默认值,则集群会像准入插件已禁用一样响应 PVC 创建。如果指定了多个默认存储类,则在动态配置 PVC 时,将使用最新的默认值。 - 如果准入插件已禁用,则没有默认存储类的概念。所有
storageClassName
设置为""
的 PVC 只能绑定到storageClassName
也设置为""
的 PV。但是,在默认存储类变为可用后,可以稍后更新缺少storageClassName
的 PVC。如果 PVC 被更新,它将不再绑定到storageClassName
也设置为""
的 PV。
有关更多详细信息,请参阅 追溯默认存储类分配。
根据安装方法,默认存储类可能在安装过程中由插件管理器部署到 Kubernetes 集群中。
当 PVC 在请求存储类时还指定了 selector
时,要求将通过 AND 运算连接在一起:只有请求类别的 PV 并且具有请求标签的 PV 才能绑定到 PVC。
注意
目前,具有非空selector
的 PVC 无法为其动态配置 PV。过去,注释 volume.beta.kubernetes.io/storage-class
用于替代 storageClassName
属性。该注释仍然有效;但是,它将在将来的 Kubernetes 版本中不再受支持。
追溯默认存储类分配
Kubernetes v1.28 [稳定]
您可以在不为新 PVC 指定 storageClassName
的情况下创建持久卷声明,即使您的集群中不存在默认存储类,您也可以这样做。在这种情况下,新 PVC 将按照您定义的方式创建,并且该 PVC 的 storageClassName
将保持未设置状态,直到默认值可用为止。
当默认存储类变为可用时,控制平面会识别任何没有 storageClassName
的现有 PVC。对于 storageClassName
为空值或没有此键的 PVC,控制平面会更新这些 PVC 以将 storageClassName
设置为与新的默认存储类匹配。如果您有一个 storageClassName
为 ""
的现有 PVC,并且您配置了默认存储类,则该 PVC 不会被更新。
为了继续绑定到 storageClassName
设置为 ""
的 PV(在存在默认存储类的同时),您需要将关联 PVC 的 storageClassName
设置为 ""
。
此行为有助于管理员通过首先删除旧的默认存储类,然后创建或设置另一个默认存储类来更改默认存储类。当没有默认存储类时,这个短暂的窗口会导致在此期间创建的没有 storageClassName
的 PVC 没有任何默认值,但由于追溯默认存储类分配,这种更改默认值的方式是安全的。
声明作为卷
Pod 通过使用声明作为卷来访问存储。声明必须与使用声明的 Pod 位于同一个命名空间。集群在 Pod 的命名空间中找到声明,并使用它来获取支持声明的持久卷。然后,该卷被挂载到主机和 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
关于命名空间的说明
持久卷绑定是独占的,并且由于持久卷声明是命名空间对象,因此只能在一个命名空间内挂载具有“Many”模式(ROX
、RWX
)的声明。
类型为 hostPath
的持久卷
hostPath
持久卷使用节点上的文件或目录来模拟网络连接的存储。请参阅 类型为 hostPath
的卷示例。
原始块卷支持
Kubernetes v1.18 [稳定]
以下卷插件支持原始块卷,包括动态配置(如果适用)
- CSI
- FC(光纤通道)
- iSCSI
- 本地卷
- OpenStack Cinder
- RBD(已弃用)
- RBD(Ceph 块设备;已弃用)
- VsphereVolume
使用原始块卷的持久卷
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
请求原始块卷的持久卷声明
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 | 结果 |
---|---|---|
未指定 | 未指定 | 绑定 |
未指定 | 块 | 未绑定 |
未指定 | 文件系统 | 绑定 |
块 | 未指定 | 未绑定 |
块 | 块 | 绑定 |
块 | 文件系统 | 未绑定 |
文件系统 | 文件系统 | 绑定 |
文件系统 | 块 | 未绑定 |
文件系统 | 未指定 | 绑定 |
注意
Alpha 版本仅支持静态配置卷。管理员在使用原始块设备时应注意这些值。卷快照和从快照恢复卷支持
Kubernetes v1.20 [稳定]
卷快照仅支持树外 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
功能开关。
卷填充器利用 PVC 规范字段 dataSourceRef
。与 dataSource
字段不同,dataSource
字段只能包含对另一个 PersistentVolumeClaim 或 VolumeSnapshot 的引用,dataSourceRef
字段可以包含对同一命名空间中任何对象的引用,除了 PVC 之外的核心对象。对于启用了功能开关的集群,使用 dataSourceRef
比使用 dataSource
更可取。
跨命名空间数据源
Kubernetes v1.26 [alpha]
Kubernetes 支持跨命名空间卷数据源。要使用跨命名空间卷数据源,您必须为 kube-apiserver 和 kube-controller-manager 启用 AnyVolumeDataSource
和 CrossNamespaceVolumeDataSource
功能开关。此外,您还必须为 csi-provisioner 启用 CrossNamespaceVolumeDataSource
功能开关。
启用 CrossNamespaceVolumeDataSource
功能开关允许您在 dataSourceRef 字段中指定命名空间。
注意
当您为卷数据源指定命名空间时,Kubernetes 会在接受引用之前检查其他命名空间中的 ReferenceGrant。ReferenceGrant 是gateway.networking.k8s.io
扩展 API 的一部分。有关详细信息,请参阅 Gateway API 文档中的 ReferenceGrant。这意味着您必须使用 Gateway API 扩展 Kubernetes 集群(至少包含 ReferenceGrant),然后才能使用此机制。数据源引用
dataSourceRef
字段的行为几乎与 dataSource
字段相同。如果指定了其中一个字段而另一个字段没有指定,则 API 服务器将为两个字段赋予相同的值。创建后不能更改任何字段,尝试为两个字段指定不同的值会导致验证错误。因此,这两个字段将始终具有相同的内容。
dataSourceRef
字段和 dataSource
字段之间有两个区别,用户应该注意
dataSource
字段忽略无效值(好像该字段为空),而dataSourceRef
字段从不忽略值,如果使用无效值,则会导致错误。无效值是除 PVC 之外的任何核心对象(没有 apiGroup 的对象)。dataSourceRef
字段可以包含不同类型的对象,而dataSource
字段只允许 PVC 和 VolumeSnapshot。
启用 CrossNamespaceVolumeDataSource
功能时,还有其他区别
dataSource
字段只允许本地对象,而dataSourceRef
字段允许任何命名空间中的对象。- 当指定命名空间时,
dataSource
和dataSourceRef
不会同步。
用户应始终在启用了功能开关的集群上使用 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
编写可移植配置
如果您正在编写在各种集群上运行的配置模板或示例,并且需要持久存储,建议您使用以下模式
- 在您的配置包(与 Deployment、ConfigMap 等一起)中包含 PersistentVolumeClaim 对象。
- 不要在配置中包含 PersistentVolume 对象,因为实例化配置的用户可能没有创建 PersistentVolume 的权限。
- 让用户在实例化模板时可以选择提供存储类名称。
- 如果用户提供了存储类名称,请将该值放入
persistentVolumeClaim.storageClassName
字段中。如果集群启用了管理员的 StorageClass,这将导致 PVC 与正确的存储类匹配。 - 如果用户没有提供存储类名称,请将
persistentVolumeClaim.storageClassName
字段保留为 nil。这将导致为用户自动配置一个 PV,并使用集群中的默认 StorageClass。许多集群环境都安装了默认 StorageClass,或者管理员可以创建自己的默认 StorageClass。
- 如果用户提供了存储类名称,请将该值放入
- 在您的工具中,监控一段时间后未绑定的 PVC,并将此情况告知用户,因为这可能表明集群没有动态存储支持(在这种情况下,用户应该创建一个匹配的 PV),或者集群没有存储系统(在这种情况下,用户无法部署需要 PVC 的配置)。
下一步
- 了解有关 创建 PersistentVolume 的更多信息。
- 了解有关 创建 PersistentVolumeClaim 的更多信息。
- 阅读 持久存储设计文档。
API 引用
了解有关本页所述 API 的信息