持久卷
This document describes persistent volumes in Kubernetes. Familiarity with volumes, StorageClasses and VolumeAttributesClasses is suggested.
Introduction
Managing storage is a distinct problem from managing compute instances. The PersistentVolume subsystem provides an API for users and administrators that abstracts details of how storage is provided from how it is consumed. To do this, we introduce two new API resources: PersistentVolume and PersistentVolumeClaim.
A PersistentVolume (PV) is a piece of storage in the cluster that has been provisioned by an administrator or dynamically provisioned using Storage Classes. It is a resource in the cluster just like a node is a cluster resource. PVs are volume plugins like Volumes, but have a lifecycle independent of any individual Pod that uses the PV. This API object captures the details of the implementation of the storage, be that NFS, iSCSI, or a cloud-provider-specific storage system.
A PersistentVolumeClaim (PVC) is a request for storage by a user. It is similar to a Pod. Pods consume node resources and PVCs consume PV resources. Pods can request specific levels of resources (CPU and Memory). Claims can request specific size and access modes (e.g., they can be mounted ReadWriteOnce, ReadOnlyMany, ReadWriteMany, or ReadWriteOncePod, see AccessModes).
While PersistentVolumeClaims allow a user to consume abstract storage resources, it is common that users need PersistentVolumes with varying properties, such as performance, for different problems. Cluster administrators need to be able to offer a variety of PersistentVolumes that differ in more ways than size and access modes, without exposing users to the details of how those volumes are implemented. For these needs, there is the StorageClass resource.
See the detailed walkthrough with working examples.
Lifecycle of a volume and claim
PVs are resources in the cluster. PVCs are requests for those resources and also act as claim checks to the resource. The interaction between PVs and PVCs follows this lifecycle
Provisioning
There are two ways PVs may be provisioned: statically or dynamically.
Static
A cluster administrator creates a number of PVs. They carry the details of the real storage, which is available for use by cluster users. They exist in the Kubernetes API and are available for consumption.
Dynamic
When none of the static PVs the administrator created match a user's PersistentVolumeClaim, the cluster may try to dynamically provision a volume specially for the PVC. This provisioning is based on StorageClasses: the PVC must request a storage class and the administrator must have created and configured that class for dynamic provisioning to occur. Claims that request the class ""
effectively disable dynamic provisioning for themselves.
To enable dynamic storage provisioning based on storage class, the cluster administrator needs to enable the DefaultStorageClass
admission controller on the API server. This can be done, for example, by ensuring that DefaultStorageClass
is among the comma-delimited, ordered list of values for the --enable-admission-plugins
flag of the API server component. For more information on API server command-line flags, check kube-apiserver documentation.
绑定
A user creates, or in the case of dynamic provisioning, has already created, a PersistentVolumeClaim with a specific amount of storage requested and with certain access modes. A control loop in the control plane watches for new PVCs, finds a matching PV (if possible), and binds them together. If a PV was dynamically provisioned for a new PVC, the loop will always bind that PV to the PVC. Otherwise, the user will always get at least what they asked for, but the volume may be in excess of what was requested. Once bound, PersistentVolumeClaim binds are exclusive, regardless of how they were bound. A PVC to PV binding is a one-to-one mapping, using a ClaimRef which is a bi-directional binding between the PersistentVolume and the PersistentVolumeClaim.
Claims will remain unbound indefinitely if a matching volume does not exist. Claims will be bound as matching volumes become available. For example, a cluster provisioned with many 50Gi PVs would not match a PVC requesting 100Gi. The PVC can be bound when a 100Gi PV is added to the cluster.
Using
Pods use claims as volumes. The cluster inspects the claim to find the bound volume and mounts that volume for a Pod. For volumes that support multiple access modes, the user specifies which mode is desired when using their claim as a volume in a Pod.
Once a user has a claim and that claim is bound, the bound PV belongs to the user for as long as they need it. Users schedule Pods and access their claimed PVs by including a persistentVolumeClaim
section in a Pod's volumes
block. See Claims As Volumes for more details on this.
Storage Object in Use Protection
The purpose of the Storage Object in Use Protection feature is to ensure that PersistentVolumeClaims (PVCs) in active use by a Pod and PersistentVolume (PVs) that are bound to PVCs are not removed from the system, as this may result in data loss.
Note
PVC is in active use by a Pod when a Pod object exists that is using the PVC.If a user deletes a PVC in active use by a Pod, the PVC is not removed immediately. PVC removal is postponed until the PVC is no longer actively used by any Pods. Also, if an admin deletes a PV that is bound to a PVC, the PV is not removed immediately. PV removal is postponed until the PV is no longer bound to a PVC.
You can see that a PVC is protected when the PVC's status is Terminating
and the Finalizers
list includes kubernetes.io/pvc-protection
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]
...
You can see that a PV is protected when the PV's status is Terminating
and the Finalizers
list includes kubernetes.io/pv-protection
too
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>
Reclaiming
当用户不再需要其卷时,他们可以从 API 中删除 PVC 对象,从而回收资源。PersistentVolume 的回收策略告诉集群在声明被释放后如何处理卷。目前,卷可以被保留(Retained)、回收(Recycled)或删除(Deleted)。
保留 (Retain)
Retain
回收策略允许手动回收资源。当 PersistentVolumeClaim 被删除时,PersistentVolume 仍然存在,并且该卷被认为是“已释放”的。但它还不能用于新的声明,因为之前声明者的数据仍然保留在卷上。管理员可以通过以下步骤手动回收该卷。
- 删除 PersistentVolume。删除 PV 后,外部基础设施中关联的存储资产仍然存在。
- 相应地手动清理关联存储资产上的数据。
- 手动删除关联的存储资产。
如果您想重用相同的存储资产,请使用相同的存储资产定义创建新的 PersistentVolume。
删除 (Delete)
对于支持 Delete
回收策略的卷插件,删除操作会从 Kubernetes 中移除 PersistentVolume 对象,并删除外部基础设施中关联的存储资产。动态配置的卷会继承其 StorageClass 的回收策略,默认设置为 Delete
。管理员应根据用户的期望配置 StorageClass;否则,必须在创建 PV 后对其进行编辑或修补。请参阅更改 PersistentVolume 的回收策略。
回收 (Recycle)
警告
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
部分中指定的特定路径将被替换为正在回收的卷的特定路径。
PersistentVolume 删除保护终结器
Kubernetes v1.31 [beta]
(默认启用: 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
控制平面可以将PersistentVolumeClaim 绑定到集群中匹配的 PersistentVolume。但是,如果您希望 PVC 绑定到特定的 PV,则需要预先绑定它们。
通过在 PersistentVolumeClaim 中指定 PersistentVolume,您声明了该特定 PV 和 PVC 之间的绑定。如果 PersistentVolume 存在,并且尚未通过其 claimRef
字段保留 PersistentVolumeClaim,则 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 的绑定权限。如果其他 PersistentVolumeClaim 可以使用您指定的 PV,您首先需要保留该存储卷。在 PV 的 claimRef
字段中指定相关的 PersistentVolumeClaim,以便其他 PVC 无法绑定到它。
apiVersion: v1
kind: PersistentVolume
metadata:
name: foo-pv
spec:
storageClassName: ""
claimRef:
name: foo-pvc
namespace: foo
...
如果您想使用将其 persistentVolumeReclaimPolicy
设置为 Retain
的 PersistentVolume,包括重用现有 PV 的情况,则此方法非常有用。
扩展 Persistent Volumes Claims
Kubernetes v1.24 [stable]
默认情况下启用对扩展 PersistentVolumeClaim (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 对象并指定更大的大小。这将触发支持底层 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 运行时(如果底层文件系统支持在线扩展)完成。
如果驱动程序配置了 RequiresFSResize
功能为 true
,则 FlexVolumes(自 Kubernetes v1.23 起已弃用)允许调整大小。FlexVolume 可以在 Pod 重启时调整大小。
调整正在使用的 PersistentVolumeClaim 的大小
Kubernetes v1.24 [stable]
在这种情况下,您无需删除并重新创建正在使用现有 PVC 的 Pod 或部署。任何正在使用的 PVC 都会在其文件系统扩展后立即自动可供其 Pod 使用。此功能对 Pod 或部署未使用的 PVC 没有影响。您必须创建一个使用 PVC 的 Pod,然后才能完成扩展。
与其他卷类型类似,FlexVolume 卷也可以在 Pod 使用时进行扩展。
Note
仅当底层驱动程序支持调整大小时,才能进行 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.23 [alpha]
(默认启用: false)Note
用户从失败的 PVC 扩展中恢复 (RecoverVolumeExpansionFailure
) 自 Kubernetes 1.32 起作为 beta 功能提供,并且应默认启用。有关更多信息,请参阅功能门文档。当使用 RecoverVolumeExpansionFailure
功能时,如果 PVC 的扩展失败,您可以尝试使用小于先前请求的值的大小来重试扩展。要使用较小的提议大小请求新的扩展尝试,请编辑该 PVC 的 .spec.resources
并选择一个小于您先前尝试的值的值。如果由于容量限制而无法成功扩展到更高的值,这将非常有用。如果发生这种情况,或者您怀疑可能发生了这种情况,则可以通过指定一个在底层存储提供商的容量限制内的值来重试扩展。您可以通过查看 PVC 上的 .status.allocatedResourceStatuses
和事件来监视调整大小操作的状态。
请注意,尽管您可以指定比先前请求的存储量更少的存储量,但新值仍然必须高于 .status.capacity
。Kubernetes 不支持将 PVC 缩小到小于其当前大小。
Persistent Volume 的类型
PersistentVolume 类型作为插件实现。Kubernetes 目前支持以下插件
csi
- 容器存储接口 (CSI)fc
- 光纤通道 (FC) 存储hostPath
- HostPath 卷(仅用于单节点测试;在多节点集群中不起作用;请考虑改用local
卷)iscsi
- iSCSI(基于 IP 的 SCSI)存储local
- 安装在节点上的本地存储设备。nfs
- 网络文件系统 (NFS) 存储
以下类型的 PersistentVolume 已弃用,但仍然可用。如果您使用这些卷类型(flexVolume
、cephfs
和 rbd
除外),请安装相应的 CSI 驱动程序。
awsElasticBlockStore
- AWS 弹性块存储 (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 版本开始不可用)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
Note
在集群中使用 PersistentVolume 可能需要与卷类型相关的辅助程序。在此示例中,PersistentVolume 的类型为 NFS,并且需要辅助程序 /sbin/mount.nfs 来支持 NFS 文件系统的挂载。容量
通常,PV 将具有特定的存储容量。这是使用 PV 的 capacity
属性设置的,该属性是一个数量值。
目前,只有存储大小是可以设置或请求的资源。未来的属性可能包括 IOPS、吞吐量等。
卷模式
Kubernetes v1.18 [稳定]
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 [稳定]
Note
ReadWriteOncePod
访问模式仅支持 CSI 卷和 Kubernetes 1.22+ 版本。要使用此功能,您需要将以下 CSI sidecar 更新到这些版本或更高版本
在 CLI 中,访问模式缩写为
- RWO - ReadWriteOnce
- ROX - ReadOnlyMany
- RWX - ReadWriteMany
- RWOP - ReadWriteOncePod
Note
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.32,只有 nfs
和 hostPath
卷类型支持回收。
挂载选项
Kubernetes 管理员可以指定当持久卷挂载在节点上时使用的其他挂载选项。
Note
并非所有持久卷类型都支持挂载选项。以下卷类型支持挂载选项
azureFile
cephfs
(在 v1.28 中已弃用)cinder
(在 v1.18 中已弃用)iscsi
nfs
rbd
(在 v1.28 中已弃用)vsphereVolume
挂载选项未经验证。如果挂载选项无效,则挂载失败。
过去,使用注解 volume.beta.kubernetes.io/mount-options
代替 mountOptions
属性。此注解仍然有效;但是,它将在未来的 Kubernetes 版本中完全弃用。
节点亲和性
Note
对于大多数卷类型,您无需设置此字段。您需要为 本地 卷显式设置此字段。PV 可以指定节点亲和性,以定义限制可以从哪些节点访问此卷的约束。使用 PV 的 Pod 将仅计划到由节点亲和性选择的节点。要指定节点亲和性,请在 PV 的 .spec
中设置 nodeAffinity
。PersistentVolume API 参考中提供了有关此字段的更多详细信息。
阶段
PersistentVolume 将处于以下阶段之一
Available
- 尚未绑定到声明的可用资源
Bound
- 该卷已绑定到声明
Released
- 声明已删除,但关联的存储资源尚未被集群回收
Failed
- 该卷的(自动)回收已失败
您可以使用 kubectl describe persistentvolume <名称>
查看绑定到 PV 的 PVC 的名称。
阶段转换时间戳
Kubernetes v1.31 [稳定]
(默认启用: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]}
访问模式
在请求具有特定访问模式的存储时,声明使用与卷相同的约定。
卷模式
声明使用与卷相同的约定来指示将卷作为文件系统还是块设备使用。
资源
声明(如 Pod)可以请求特定数量的资源。在这种情况下,请求是用于存储的。相同的 资源模型 适用于卷和声明。
选择器
声明可以指定一个标签选择器以进一步筛选卷集。只有标签与选择器匹配的卷才能绑定到声明。选择器可以包含两个字段
matchLabels
- 该卷必须具有带有此值的标签matchExpressions
- 通过指定键、值列表以及关联键和值的运算符所做的需求列表。有效的运算符包括 In、NotIn、Exists 和 DoesNotExist。
所有要求(来自 matchLabels
和 matchExpressions
)都使用 AND 逻辑组合在一起 - 它们必须全部满足才能匹配。
类
声明可以通过使用 storageClassName
属性指定 StorageClass 的名称来请求特定的类。只有请求的类别的 PV,即具有与 PVC 相同的 storageClassName
的 PV,才能绑定到 PVC。
PVC 不一定需要请求类别。将其 storageClassName
设置为 ""
的 PVC 始终被解释为请求没有类别的 PV,因此它只能绑定到没有类别的 PV(没有注解或注解设置为 ""
的 PV)。没有 storageClassName
的 PVC 并不完全相同,集群会根据 DefaultStorageClass
准入插件 是否启用,对其进行不同的处理。
- 如果启用了准入插件,则管理员可以指定默认的 StorageClass。所有没有
storageClassName
的 PVC 只能绑定到该默认类别的 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 分配。
根据安装方法,在安装期间,插件管理器可以将默认的 StorageClass 部署到 Kubernetes 集群。
当 PVC 除了请求 StorageClass 外还指定了 selector
时,要求是 ANDed 在一起的:只有请求的类别且具有请求标签的 PV 才能绑定到 PVC。
Note
目前,具有非空selector
的 PVC 不能为其动态配置 PV。过去,使用注解 volume.beta.kubernetes.io/storage-class
代替 storageClassName
属性。此注解仍然有效;但是,它在未来的 Kubernetes 版本中将不再受支持。
追溯默认 StorageClass 分配
Kubernetes v1.28 [stable]
您可以创建一个 PersistentVolumeClaim 而无需为新的 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。在此短暂的窗口期(没有默认 StorageClass 的情况下),此时创建的没有 storageClassName
的 PVC 将没有任何默认值,但是由于追溯默认 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
关于命名空间的说明
PersistentVolume 的绑定是独占的,并且由于 PersistentVolumeClaim 是命名空间对象,因此只能在一个命名空间内挂载具有“Many”模式(ROX
、RWX
)的声明。
类型为 hostPath
的 PersistentVolumes
hostPath
PersistentVolume 使用节点上的文件或目录来模拟网络连接的存储。请参阅hostPath
类型卷的示例。
原始块卷支持
Kubernetes v1.18 [稳定]
以下卷插件支持原始块卷,包括在适用的情况下的动态配置
- CSI
- FC(光纤通道)
- iSCSI
- 本地卷
- OpenStack Cinder
- RBD(已弃用)
- RBD(Ceph 块设备;已弃用)
- VsphereVolume
使用原始块卷的 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
Note
当为 Pod 添加原始块设备时,您需要在容器中指定设备路径,而不是挂载路径。绑定块卷
如果用户通过在 PersistentVolumeClaim 规范中使用 volumeMode
字段来指示请求原始块卷,则绑定规则与以前的版本略有不同,以前的版本没有将此模式视为规范的一部分。下面列出了用户和管理员可能指定请求原始块设备的所有可能组合。该表指示给定组合是否绑定卷:静态配置卷的卷绑定矩阵
PV volumeMode | PVC volumeMode | 结果 |
---|---|---|
未指定 | 未指定 | 绑定 |
未指定 | 块 | 不绑定 |
未指定 | 文件系统 | 绑定 |
块 | 未指定 | 不绑定 |
块 | 块 | 绑定 |
块 | 文件系统 | 不绑定 |
文件系统 | 文件系统 | 绑定 |
文件系统 | 块 | 不绑定 |
文件系统 | 未指定 | 绑定 |
Note
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
功能门。
卷填充器利用名为 dataSourceRef
的 PVC 规范字段。与 dataSource
字段(只能包含对另一个 PersistentVolumeClaim 或 VolumeSnapshot 的引用)不同,dataSourceRef
字段可以包含对同一命名空间中任何对象的引用,但 PVC 以外的核心对象除外。对于启用了功能门的集群,建议使用 dataSourceRef
而不是 dataSource
。
跨命名空间数据源
Kubernetes v1.26 [alpha]
Kubernetes 支持跨命名空间卷数据源。要使用跨命名空间卷数据源,您必须为 kube-apiserver 和 kube-controller-manager 启用 AnyVolumeDataSource
和 CrossNamespaceVolumeDataSource
功能门。此外,您必须为 csi-provisioner 启用 CrossNamespaceVolumeDataSource
功能门。
启用 CrossNamespaceVolumeDataSource
功能门允许您在 dataSourceRef 字段中指定命名空间。
Note
当您为卷数据源指定命名空间时,Kubernetes 会在接受引用之前检查另一个命名空间中的 ReferenceGrant。ReferenceGrant 是gateway.networking.k8s.io
扩展 API 的一部分。有关详细信息,请参阅 Gateway API 文档中的 ReferenceGrant。这意味着您必须至少使用 Gateway API 中的 ReferenceGrant 扩展您的 Kubernetes 集群,然后才能使用此机制。数据源引用
dataSourceRef
字段的行为与 dataSource
字段几乎相同。如果指定了一个而没有指定另一个,则 API 服务器将为这两个字段提供相同的值。创建后,这两个字段都不能更改,并且尝试为这两个字段指定不同的值会导致验证错误。因此,这两个字段将始终具有相同的内容。
用户应注意 dataSourceRef
字段和 dataSource
字段之间的两个区别
dataSource
字段会忽略无效值(如同该字段为空),而dataSourceRef
字段永远不会忽略值,如果使用无效值将导致错误。无效值是任何核心对象(没有 apiGroup 的对象),但 PVC 除外。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 对象(与 Deployments、ConfigMaps 等一起)。
- 不要在配置中包含 PersistentVolume 对象,因为实例化配置的用户可能没有创建 PersistentVolumes 的权限。
- 让用户可以选择在实例化模板时提供存储类名称。
- 如果用户提供了存储类名称,则将该值放入
persistentVolumeClaim.storageClassName
字段。这将使 PVC 与正确的存储类匹配(如果集群管理员启用了 StorageClass)。 - 如果用户没有提供存储类名称,则将
persistentVolumeClaim.storageClassName
字段保留为 nil。这将导致为用户自动配置一个 PV,使用集群中的默认 StorageClass。许多集群环境都安装了默认的 StorageClass,或者管理员可以创建他们自己的默认 StorageClass。
- 如果用户提供了存储类名称,则将该值放入
- 在您的工具中,请留意一段时间后仍未绑定的 PVC,并将其呈现给用户。这可能表示集群没有动态存储支持(在这种情况下,用户应该创建匹配的 PV),或者集群没有存储系统(在这种情况下,用户无法部署需要 PVC 的配置)。
下一步是什么
- 了解更多关于创建 PersistentVolume的信息。
- 了解更多关于创建 PersistentVolumeClaim的信息。
- 阅读持久存储设计文档。
API 参考
阅读此页面中描述的 API