持久卷
本文档介绍了 Kubernetes 中的**持久卷**。建议熟悉卷、StorageClasses和VolumeAttributesClasses。
介绍
管理存储与管理计算实例是不同的问题。PersistentVolume 子系统为用户和管理员提供了一个 API,用于抽象存储的提供方式和消耗方式的细节。为此,我们引入了两个新的 API 资源:PersistentVolume 和 PersistentVolumeClaim。
一个 **PersistentVolume** (PV) 是集群中的一块存储,它由管理员配置,或使用StorageClass动态配置。它就像节点是集群资源一样,是集群中的一种资源。PV 类似于卷插件,但其生命周期独立于使用该 PV 的任何单个 Pod。这个 API 对象捕获了存储实现的细节,无论是 NFS、iSCSI 还是云提供商特定的存储系统。
一个 **PersistentVolumeClaim** (PVC) 是用户对存储的请求。它类似于 Pod。Pod 消耗节点资源,而 PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存)。声明可以请求特定大小和访问模式(例如,它们可以以 ReadWriteOnce、ReadOnlyMany、ReadWriteMany 或 ReadWriteOncePod 方式挂载,参见访问模式)。
虽然 PersistentVolumeClaims 允许用户抽象地使用存储资源,但用户通常需要具有不同属性(例如性能)的 PersistentVolumes 来解决不同的问题。集群管理员需要能够提供多种在大小和访问模式之外存在差异的 PersistentVolumes,同时又不会向用户暴露这些卷的具体实现细节。为了满足这些需求,存在 **StorageClass** 资源。
请参阅包含工作示例的详细演练。
卷和声明的生命周期
PV 是集群中的资源。PVC 是对这些资源的请求,也作为资源的认领凭证。PV 和 PVC 之间的交互遵循以下生命周期:
供应
PV 的供应方式有两种:静态或动态。
静态
集群管理员创建多个 PV。它们承载真实存储的详细信息,可供集群用户使用。它们存在于 Kubernetes API 中并可供使用。
动态
当管理员创建的任何静态 PV 都不匹配用户的 PersistentVolumeClaim 时,集群可能会尝试专门为 PVC 动态配置卷。此配置基于 StorageClass:PVC 必须请求存储类,并且管理员必须已创建和配置该类才能进行动态配置。请求类为 ""
的声明实际上会禁用自身的动态配置。
为了启用基于存储类的动态存储配置,集群管理员需要在 API 服务器上启用 DefaultStorageClass
准入控制器。例如,可以通过确保 DefaultStorageClass
位于 API 服务器组件的 --enable-admission-plugins
标志的逗号分隔有序值列表中来实现。有关 API 服务器命令行标志的更多信息,请查看kube-apiserver文档。
绑定
用户创建,或者在动态配置的情况下,已经创建了一个 PersistentVolumeClaim,其中包含特定数量的存储请求和某些访问模式。控制平面中的一个控制循环监视新的 PVC,查找匹配的 PV(如果可能),并将它们绑定在一起。如果为新的 PVC 动态配置了 PV,则该循环将始终将该 PV 绑定到 PVC。否则,用户将始终获得至少所请求的内容,但卷可能超出所请求的大小。一旦绑定,PersistentVolumeClaim 绑定是排他性的,无论它们如何绑定。PVC 到 PV 的绑定是一对一的映射,使用 ClaimRef,它是 PersistentVolume 和 PersistentVolumeClaim 之间的双向绑定。
如果不存在匹配的卷,声明将无限期保持未绑定状态。当匹配的卷可用时,声明将被绑定。例如,一个配置了许多 50Gi PV 的集群将不匹配请求 100Gi 的 PVC。当 100Gi PV 被添加到集群时,PVC 可以被绑定。
使用
Pod 将声明用作卷。集群会检查声明以找到已绑定的卷,并为 Pod 挂载该卷。对于支持多种访问模式的卷,用户在使用其声明作为 Pod 中的卷时会指定所需的模式。
一旦用户拥有一个声明且该声明已绑定,则已绑定的 PV 将属于该用户,只要他们需要它。用户通过在 Pod 的 volumes
块中包含 persistentVolumeClaim
部分来调度 Pod 并访问其声明的 PV。有关此内容的更多详细信息,请参见作为卷的声明。
使用中存储对象的保护
使用中存储对象保护功能的目的是确保 Pod 正在积极使用的 PersistentVolumeClaims (PVC) 和绑定到 PVC 的 PersistentVolume (PV) 不会从系统中移除,因为这可能导致数据丢失。
注意
当存在使用 PVC 的 Pod 对象时,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 对象,这允许回收资源。PersistentVolume 的回收策略告诉集群在卷被其声明释放后如何处理它。目前,卷可以被保留(Retained)、回收(Recycled)或删除(Deleted)。
保留
`Retain` 回收策略允许手动回收资源。当 PersistentVolumeClaim 被删除时,PersistentVolume 仍然存在,并且该卷被认为是“已释放”。但它尚未可用于另一个声明,因为前一个声明者的数据仍在卷上。管理员可以通过以下步骤手动回收该卷。
- 删除 PersistentVolume。在 PV 被删除后,外部基础设施中相关的存储资产仍然存在。
- 根据需要手动清理关联存储资产上的数据。
- 手动删除关联的存储资产。
如果你想重复使用相同的存储资产,请创建一个具有相同存储资产定义的新 PersistentVolume。
删除
对于支持 `Delete` 回收策略的卷插件,删除会从 Kubernetes 中移除 PersistentVolume 对象,以及外部基础设施中关联的存储资产。动态配置的卷继承其 StorageClass 的回收策略,该策略默认为 `Delete`。管理员应根据用户的期望配置 StorageClass;否则,在创建 PV 后必须对其进行编辑或修补。请参阅 更改 PersistentVolume 的回收策略。
回收
警告
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/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 引入) 被添加到动态配置的 in-tree 插件卷中,并跳过静态配置的 in-tree 插件卷。
以下是动态配置的 in-tree 插件卷的示例:
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 的回收策略为 `Delete` 的情况下,在卷从存储后端删除后才移除 PV 对象。这还确保无论 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 的情况,这会很有用。
扩展持久卷声明
Kubernetes v1.24 [stable]
扩展 PersistentVolumeClaims (PVC) 的支持默认启用。你可以扩展以下类型的卷:
- csi(包括一些 CSI 迁移的卷类型)
- flexVolume (已弃用)
- 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 对象并指定更大的大小。这将触发支持底层 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 或部署。一旦文件系统扩展完成,任何正在使用的 PVC 会自动对其 Pod 可用。此功能对未被 Pod 或部署使用的 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 且其 `volumeName` 字段设置为 PV 名称的 PVC。这将把新的 PVC 绑定到现有的 PV。
- 别忘了恢复 PV 的回收策略。
如果 PVC 扩展失败,你可以尝试以小于之前请求值的大小再次扩展。要以更小的新建议大小重新尝试扩展,请编辑该 PVC 的 `resources.spec` 并选择一个小于你之前尝试的值。这在由于容量限制导致扩展到更大值未成功时很有用。如果发生这种情况,或者你怀疑可能发生,你可以通过指定一个在底层存储提供商容量限制范围内的大小来重试扩展。你可以通过观察 `status.allocatedResourceStatuses` 和 PVC 上的事件来监控调整大小操作的状态。
请注意,尽管你可以指定低于先前请求的存储量,但新值仍必须高于 .status.capacity
。Kubernetes 不支持将 PVC 缩小到小于其当前大小。
持久卷类型
PersistentVolume 类型以插件形式实现。Kubernetes 目前支持以下插件:
csi
- 容器存储接口 (CSI)fc
- 光纤通道 (FC) 存储hostPath
- HostPath 卷(仅用于单节点测试;在多节点集群中将**不工作**;请考虑改用local
卷)iscsi
- iSCSI(通过 IP 的 SCSI)存储local
- 挂载在节点上的本地存储设备。nfs
- 网络文件系统 (NFS) 存储
以下 PersistentVolume 类型已弃用但仍可用。如果你正在使用除 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 也支持以下树内 PersistentVolume 类型:
cephfs
(从 v1.31 起**不再可用**)flocker
- Flocker 存储。(从 v1.25 起**不再可用**)glusterfs
- GlusterFS 存储。(从 v1.26 起**不再可用**)photonPersistentDisk
- Photon 控制器持久磁盘。(从 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
- 该卷可以被单个节点以读写方式挂载。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 | ✓ | - | - (当 Pods 位于同一位置时工作) | - |
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.34,只有 nfs
和 hostPath
卷类型支持回收。
挂载选项
Kubernetes 管理员可以指定当 Persistent Volume 挂载到节点时额外的挂载选项。
注意
并非所有 Persistent Volume 类型都支持挂载选项。以下卷类型支持挂载选项:
csi
(包括 CSI 迁移的卷类型)iSCSI
nfs
挂载选项不进行验证。如果挂载选项无效,挂载将失败。
过去,使用注解 `volume.beta.kubernetes.io/mount-options` 而不是 `mountOptions` 属性。此注解仍然有效;但是,它将在未来的 Kubernetes 版本中完全弃用。
节点亲和性
注意
对于大多数卷类型,你无需设置此字段。对于本地卷,你需要明确设置此字段。PV 可以指定节点亲和性,以定义限制该卷可从哪些节点访问的约束。使用 PV 的 Pod 只会被调度到由节点亲和性选择的节点上。要指定节点亲和性,请在 PV 的 .spec
中设置 nodeAffinity
。有关此字段的更多详细信息,请参阅PersistentVolume API 参考。
阶段
PersistentVolume 将处于以下阶段之一:
Available
- 一个未绑定到声明的空闲资源
Bound
- 该卷已绑定到一个声明
Released
- 该声明已被删除,但相关存储资源尚未被集群回收
Failed
- 卷的(自动)回收失败
你可以使用 `kubectl describe persistentvolume
阶段转换时间戳
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,则绑定将处于挂起状态。
资源
声明与 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.kubernetes.io/is-default-class
设置为true
来指定默认 StorageClass。如果管理员未指定默认值,集群将像关闭准入插件一样响应 PVC 创建。如果指定了多个默认 StorageClass,则在动态配置 PVC 时使用最新的默认值。 - 如果准入插件被关闭,则没有默认 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]
你可以在创建新的 PVC 时不指定 `storageClassName`,即使你的集群中不存在默认的 StorageClass 也可以。在这种情况下,新的 PVC 会按照你定义的方式创建,并且该 PVC 的 `storageClassName` 保持未设置状态,直到默认值可用。
当默认 StorageClass 可用时,控制平面会识别所有现有但没有 storageClassName
的 PVC。对于那些 storageClassName
值为空或没有此键的 PVC,控制平面会更新这些 PVC,将 storageClassName
设置为新的默认 StorageClass。如果你有一个现有 PVC,其 storageClassName
为 ""
,并且你配置了一个默认 StorageClass,那么这个 PVC 将不会被更新。
为了继续绑定到 storageClassName
设置为 ""
的 PV(当存在默认 StorageClass 时),你需要将相关联的 PVC 的 storageClassName
设置为 ""
。
此行为有助于管理员通过先移除旧的默认 StorageClass,然后创建或设置另一个默认 StorageClass 来更改它。在这段没有默认 StorageClass 的短暂时间内创建的 PVC 将没有默认 StorageClass,但由于追溯默认 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 是命名空间对象,因此以“多”模式(ROX
、RWX
)挂载声明仅在一个命名空间内是可能的。
HostPath 类型的 PersistentVolumes
hostPath
PersistentVolume 使用节点上的文件或目录来模拟网络附加存储。请参阅hostPath
类型卷的示例。
裸块卷支持
Kubernetes v1.18 [stable]
以下卷插件支持裸块卷,包括在适用的情况下进行动态配置:
- CSI (包括一些 CSI 迁移的卷类型)
- FC (光纤通道)
- 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 | 结果 |
---|---|---|
未指定 | 未指定 | 绑定 |
未指定 | Block | 不绑定 |
未指定 | Filesystem | 绑定 |
Block | 未指定 | 不绑定 |
Block | Block | 绑定 |
Block | Filesystem | 不绑定 |
Filesystem | Filesystem | 绑定 |
Filesystem | Block | 不绑定 |
Filesystem | 未指定 | 绑定 |
注意
仅静态配置卷支持 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
特性门控。
卷填充器利用了 PVC 规范中的一个名为 dataSourceRef
的字段。与只能包含对另一个 PersistentVolumeClaim 或 VolumeSnapshot 的引用的 dataSource
字段不同,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 中的 ReferenceGrant 扩展你的 Kubernetes 集群,然后才能使用此机制。数据源引用
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
编写可移植配置
如果你正在编写可在各种集群上运行且需要持久存储的配置模板或示例,建议你使用以下模式:
- 在你的配置包中包含 PersistentVolumeClaim 对象(与 Deployment、ConfigMap 等一起)。
- 不要在配置中包含 PersistentVolume 对象,因为实例化配置的用户可能没有创建 PersistentVolumes 的权限。
- 在实例化模板时,向用户提供提供存储类名称的选项。
- 如果用户提供了存储类名称,请将该值放入 `persistentVolumeClaim.storageClassName` 字段中。如果集群已由管理员启用 StorageClasses,这将使 PVC 匹配正确的存储类。
- 如果用户未提供存储类名称,则将
persistentVolumeClaim.storageClassName
字段留空。这将导致使用集群中的默认 StorageClass 为用户自动配置 PV。许多集群环境都安装了默认 StorageClass,或者管理员可以创建自己的默认 StorageClass。
- 在你的工具中,监视一段时间后仍未绑定的 PVC,并将此情况告知用户,因为这可能表示集群没有动态存储支持(在这种情况下,用户应创建一个匹配的 PV)或集群没有存储系统(在这种情况下,用户无法部署需要 PVC 的配置)。
下一步
- 了解更多关于创建 PersistentVolume 的信息。
- 了解更多关于创建 PersistentVolumeClaim 的信息。
- 阅读持久存储设计文档。
API 参考
阅读本页描述的 API