持久卷

本文档描述了 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 不会立即删除。PVC 删除会推迟,直到 PVC 不再被任何 Pod 积极使用。此外,如果管理员删除了绑定到 PVC 的 PV,则 PV 不会立即删除。PV 删除会推迟,直到 PV 不再绑定到 PVC。

当 PVC 的状态为 TerminatingFinalizers 列表包含 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 的状态为 TerminatingFinalizers 列表也包含 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 回收策略允许手动回收资源。当持久卷声明被删除时,持久卷仍然存在,并且该卷被认为是“已释放”。但它尚未可用于其他声明,因为以前声明者的数据仍然存在于卷上。管理员可以使用以下步骤手动回收卷。

  1. 删除持久卷。删除 PV 后,外部基础设施中的关联存储资产仍然存在。
  2. 相应地手动清理关联存储资产上的数据。
  3. 手动删除关联存储资产。

如果您想重复使用相同的存储资产,请使用相同的存储资产定义创建一个新的持久卷。

删除

对于支持 Delete 回收策略的卷插件,删除操作会从 Kubernetes 中删除持久卷对象,以及外部基础设施中的关联存储资产。动态配置的卷会继承 其存储类的回收策略,默认值为 Delete。管理员应根据用户的期望配置存储类;否则,必须在创建 PV 后编辑或修补 PV。请参阅 更改持久卷的回收策略

回收

如果底层卷插件支持,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 对象并指定更大的大小。这将触发对支持底层持久卷的卷的扩展。永远不会创建新的持久卷来满足声明。相反,现有的卷会被调整大小。

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 使用时进行扩展。

从扩展卷失败中恢复

如果用户指定的新大小超出了底层存储系统的容量,则 PVC 的扩展将持续重试,直到用户或集群管理员采取某些措施。这可能不理想,因此 Kubernetes 提供以下从这种故障中恢复的方法。

如果扩展底层存储失败,集群管理员可以手动恢复持久卷声明 (PVC) 状态并取消调整大小请求。否则,调整大小请求将由控制器在没有管理员干预的情况下持续重试。

  1. 使用Retain回收策略标记绑定到持久卷声明 (PVC) 的持久卷 (PV)。
  2. 删除 PVC。由于 PV 具有Retain回收策略,因此在重新创建 PVC 时不会丢失任何数据。
  3. 从 PV 规范中删除claimRef条目,以便新的 PVC 可以绑定到它。这应该使 PV 变为Available
  4. 重新创建 PVC,大小小于 PV,并将 PVC 的volumeName字段设置为 PV 的名称。这应该将新的 PVC 绑定到现有的 PV。
  5. 不要忘记恢复 PV 的回收策略。

功能状态: Kubernetes v1.23 [alpha]

如果您的集群中启用了功能网关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) 存储

以下类型的持久卷已弃用,但仍然可用。如果您正在使用这些卷类型(flexVolumecephfsrbd除外),请安装相应的 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

容量

通常,PV 将具有特定的存储容量。这使用 PV 的capacity属性设置,该属性是一个数量值。

目前,存储大小是唯一可以设置或请求的资源。未来的属性可能包括 IOPS、吞吐量等。

卷模式

功能状态: Kubernetes v1.18 [稳定]

Kubernetes 支持两种持久卷的volumeModesFilesystemBlock

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 读写
功能状态: Kubernetes v1.29 [稳定]
该卷可以被单个 Pod 以读写模式挂载。如果您希望确保整个集群中只有一个 Pod 可以读取或写入该 PVC,请使用 ReadWriteOncePod 访问模式。

在 CLI 中,访问模式缩写为

  • RWO - ReadWriteOnce
  • ROX - ReadOnlyMany
  • RWX - ReadWriteMany
  • RWOP - ReadWriteOncePod

重要! 卷一次只能使用一种访问模式,即使它支持多种访问模式。

卷插件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,只有 nfshostPath 卷类型支持回收。

挂载选项

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 字段。此字段记录卷上次转换其阶段的时间戳。对于新创建的卷,阶段设置为 PendinglastPhaseTransitionTime 设置为当前时间。

持久卷声明

每个 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。

来自 matchLabelsmatchExpressions 的所有要求都将通过 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。

过去,注释 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”模式(ROXRWX)的声明。

类型为 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

绑定块卷

如果用户通过在 PersistentVolumeClaim 规范中使用 volumeMode 字段来指示,请求原始块卷,则绑定规则与之前版本略有不同,之前版本没有将此模式视为规范的一部分。以下是用户和管理员在请求原始块设备时可能指定的组合表格。该表格指示在给定组合的情况下卷是否将被绑定:静态配置卷的卷绑定矩阵

PV volumeModePVC volumeMode结果
未指定未指定绑定
未指定未绑定
未指定文件系统绑定
未指定未绑定
绑定
文件系统未绑定
文件系统文件系统绑定
文件系统未绑定
文件系统未指定绑定

卷快照和从快照恢复卷支持

功能状态: 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 启用 AnyVolumeDataSourceCrossNamespaceVolumeDataSource 功能开关。此外,您还必须为 csi-provisioner 启用 CrossNamespaceVolumeDataSource 功能开关。

启用 CrossNamespaceVolumeDataSource 功能开关允许您在 dataSourceRef 字段中指定命名空间。

数据源引用

dataSourceRef 字段的行为几乎与 dataSource 字段相同。如果指定了其中一个字段而另一个字段没有指定,则 API 服务器将为两个字段赋予相同的值。创建后不能更改任何字段,尝试为两个字段指定不同的值会导致验证错误。因此,这两个字段将始终具有相同的内容。

dataSourceRef 字段和 dataSource 字段之间有两个区别,用户应该注意

  • dataSource 字段忽略无效值(好像该字段为空),而 dataSourceRef 字段从不忽略值,如果使用无效值,则会导致错误。无效值是除 PVC 之外的任何核心对象(没有 apiGroup 的对象)。
  • dataSourceRef 字段可以包含不同类型的对象,而 dataSource 字段只允许 PVC 和 VolumeSnapshot。

启用 CrossNamespaceVolumeDataSource 功能时,还有其他区别

  • dataSource 字段只允许本地对象,而 dataSourceRef 字段允许任何命名空间中的对象。
  • 当指定命名空间时,dataSourcedataSourceRef 不会同步。

用户应始终在启用了功能开关的集群上使用 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 的配置)。

下一步

API 引用

了解有关本页所述 API 的信息

上次修改时间:2024 年 7 月 26 日下午 5:01 PST:持久卷的文档更新 (3b9ca420db)