本文发布时间已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。

推出 PersistentVolumes 的单 Pod 访问模式

上个月发布的 Kubernetes v1.22 为 PersistentVolumesPersistentVolumeClaims 引入了一种新的 ReadWriteOncePod 访问模式。 通过此 alpha 功能,Kubernetes 允许您将卷访问限制为集群中的单个 Pod。

什么是访问模式,为什么它们很重要?

使用存储时,有不同的方式来建模存储的使用方式。

例如,像网络文件共享这样的存储系统可以有许多用户同时读取和写入数据。在其他情况下,可能允许每个人读取数据但不写入数据。对于高度敏感的数据,可能只允许一个用户读取和写入数据,而其他人都不允许。

在 Kubernetes 的世界中,访问模式是您定义如何使用持久存储的方式。这些访问模式是 PersistentVolumes (PV) 和 PersistentVolumeClaims (PVC) 规范的一部分。

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: shared-cache
spec:
  accessModes:
  - ReadWriteMany # Allow many nodes to access shared-cache simultaneously.
  resources:
    requests:
      storage: 1Gi

在 v1.22 之前,Kubernetes 为 PV 和 PVC 提供了三种访问模式

  • ReadWriteOnce – 该卷可以由单个节点以读写方式挂载
  • ReadOnlyMany – 该卷可以由多个节点以只读方式挂载
  • ReadWriteMany – 该卷可以由多个节点以读写方式挂载

这些访问模式由 Kubernetes 组件(如 kube-controller-managerkubelet)强制执行,以确保只有特定的 Pod 被允许访问给定的 PersistentVolume。

这种新的访问模式是什么,它是如何工作的?

Kubernetes v1.22 为 PV 和 PVC 引入了第四种访问模式,您可以将其用于 CSI 卷

  • ReadWriteOncePod – 该卷可以由单个 Pod 以读写方式挂载

如果您创建了一个使用 ReadWriteOncePod 访问模式的 PVC 的 Pod,Kubernetes 将确保该 Pod 是您的整个集群中唯一可以读取该 PVC 或写入该 PVC 的 Pod。

如果您创建另一个引用具有此访问模式的相同 PVC 的 Pod,则该 Pod 将无法启动,因为该 PVC 已被另一个 Pod 使用。例如

Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  1s    default-scheduler  0/1 nodes are available: 1 node has pod using PersistentVolumeClaim with the same name and ReadWriteOncePod access mode.

这与 ReadWriteOnce 访问模式有何不同?

ReadWriteOnce 访问模式将卷访问限制为单个*节点*,这意味着同一节点上的多个 Pod 可能从同一卷读取和写入数据。对于某些应用程序来说,这可能会成为一个主要问题,特别是如果它们要求最多有一个写入器来保证数据安全。

使用 ReadWriteOncePod,这些问题都消失了。设置 PVC 上的访问模式,Kubernetes 保证只有一个 Pod 可以访问。

如何使用它?

ReadWriteOncePod 访问模式在 Kubernetes v1.22 中处于 alpha 阶段,仅支持 CSI 卷。第一步,您需要为 kube-apiserverkube-schedulerkubelet 启用 ReadWriteOncePod 功能门。您可以通过设置命令行参数来启用该功能

--feature-gates="...,ReadWriteOncePod=true"

您还需要将以下 CSI Sidecar 更新到这些版本或更高版本

创建 PersistentVolumeClaim

为了将 ReadWriteOncePod 访问模式用于您的 PV 和 PVC,您需要创建一个新的具有访问模式的 PVC

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: single-writer-only
spec:
  accessModes:
  - ReadWriteOncePod # Allow only a single pod to access single-writer-only.
  resources:
    requests:
      storage: 1Gi

如果您的存储插件支持动态配置,则将创建新的 PersistentVolume 并应用 ReadWriteOncePod 访问模式。

迁移现有的 PersistentVolumes

如果您有现有的 PersistentVolumes,则可以将其迁移为使用 ReadWriteOncePod。

在此示例中,我们已经有一个绑定到 “cat-pictures-pv” PersistentVolume 的 “cat-pictures-pvc” PersistentVolumeClaim,以及一个使用此 PersistentVolumeClaim 的 “cat-pictures-writer” Deployment。

第一步,您需要编辑您的 PersistentVolume 的 spec.persistentVolumeReclaimPolicy 并将其设置为 Retain。这可确保在删除相应的 PersistentVolumeClaim 时不会删除您的 PersistentVolume

kubectl patch pv cat-pictures-pv -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'

接下来,您需要停止任何正在使用绑定到要迁移的 PersistentVolume 的 PersistentVolumeClaim 的工作负载,然后删除 PersistentVolumeClaim。

完成后,您需要清除 PersistentVolume 的 spec.claimRef.uid,以确保 PersistentVolumeClaims 可以在重新创建时绑定到它

kubectl scale --replicas=0 deployment cat-pictures-writer
kubectl delete pvc cat-pictures-pvc
kubectl patch pv cat-pictures-pv -p '{"spec":{"claimRef":{"uid":""}}}'

之后,您需要将 PersistentVolume 的访问模式替换为 ReadWriteOncePod

kubectl patch pv cat-pictures-pv -p '{"spec":{"accessModes":["ReadWriteOncePod"]}}'

接下来,您需要修改 PersistentVolumeClaim 以将 ReadWriteOncePod 设置为唯一的访问模式。您还应将 PersistentVolumeClaim 的 spec.volumeName 设置为您的 PersistentVolume 的名称。

完成后,您可以重新创建 PersistentVolumeClaim 并启动您的工作负载

# IMPORTANT: Make sure to edit your PVC in cat-pictures-pvc.yaml before applying. You need to:
# - Set ReadWriteOncePod as the only access mode
# - Set spec.volumeName to "cat-pictures-pv"

kubectl apply -f cat-pictures-pvc.yaml
kubectl apply -f cat-pictures-writer-deployment.yaml

最后,您可以编辑 PersistentVolume 的 spec.persistentVolumeReclaimPolicy 并将其设置回 Delete (如果之前已更改)。

kubectl patch pv cat-pictures-pv -p '{"spec":{"persistentVolumeReclaimPolicy":"Delete"}}'

您可以阅读 配置 Pod 以使用 PersistentVolume 进行存储,了解有关使用 PersistentVolumes 和 PersistentVolumeClaims 的更多详细信息。

哪些卷插件支持此功能?

唯一支持此功能的卷插件是 CSI 驱动程序。SIG Storage 不计划为内部插件支持此功能,因为它们正作为 CSI 迁移 的一部分被弃用。 对于喜欢使用启用 CSI 迁移的旧版内部卷 API 的用户,可能会考虑支持 beta 版本。

作为存储供应商,我如何为我的 CSI 驱动程序添加对此访问模式的支持?

ReadWriteOncePod 访问模式可以开箱即用,而无需对 CSI 驱动程序进行任何更新,但确实需要更新 CSI sidecar。 话虽如此,如果您想了解 CSI 规范(v1.5.0+)的最新更改,请继续阅读。

为了消除旧的 SINGLE_NODE_WRITER 访问模式的歧义,CSI 规范中引入了两种新的访问模式。它们是 SINGLE_NODE_SINGLE_WRITERSINGLE_NODE_MULTI_WRITER。 为了向 Sidecar(如 external-provisioner)传达您的驱动程序理解并接受这两种新的 CSI 访问模式,您的驱动程序还需要为控制器服务节点服务宣传 SINGLE_NODE_MULTI_WRITER 功能。

如果您想了解这些访问模式和能力位的动机,您还可以阅读 KEP-2485(ReadWriteOncePod PersistentVolume 访问模式)的“CSI 规范更改,卷能力”部分。

更新您的 CSI 驱动程序以使用新的接口

第一步,您需要将驱动程序的 container-storage-interface 依赖项更新到 v1.5.0+,其中包含对这些新访问模式和能力的支持。

接受新的 CSI 访问模式

如果您的 CSI 驱动程序包含用于验证请求的 CSI 访问模式的逻辑,则可能需要更新它。如果它当前接受 SINGLE_NODE_WRITER,则应更新为也接受 SINGLE_NODE_SINGLE_WRITERSINGLE_NODE_MULTI_WRITER

GCP PD CSI 驱动程序的验证逻辑为例,以下是如何进行扩展

diff --git a/pkg/gce-pd-csi-driver/utils.go b/pkg/gce-pd-csi-driver/utils.go
index 281242c..b6c5229 100644
--- a/pkg/gce-pd-csi-driver/utils.go
+++ b/pkg/gce-pd-csi-driver/utils.go
@@ -123,6 +123,8 @@ func validateAccessMode(am *csi.VolumeCapability_AccessMode) error {
        case csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY:
        case csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY:
        case csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER:
+       case csi.VolumeCapability_AccessMode_SINGLE_NODE_SINGLE_WRITER:
+       case csi.VolumeCapability_AccessMode_SINGLE_NODE_MULTI_WRITER:
        default:
                return fmt.Errorf("%v access mode is not supported for for PD", am.GetMode())
        }

您的 CSI 驱动程序还需要将新的 SINGLE_NODE_MULTI_WRITER 功能作为 ControllerGetCapabilitiesNodeGetCapabilities RPC 的一部分返回。

GCP PD CSI 驱动程序的能力声明逻辑为例,以下是如何进行扩展

diff --git a/pkg/gce-pd-csi-driver/gce-pd-driver.go b/pkg/gce-pd-csi-driver/gce-pd-driver.go
index 45903f3..0d7ea26 100644
--- a/pkg/gce-pd-csi-driver/gce-pd-driver.go
+++ b/pkg/gce-pd-csi-driver/gce-pd-driver.go
@@ -56,6 +56,8 @@ func (gceDriver *GCEDriver) SetupGCEDriver(name, vendorVersion string, extraVolu
                csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
                csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY,
                csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
+               csi.VolumeCapability_AccessMode_SINGLE_NODE_SINGLE_WRITER,
+               csi.VolumeCapability_AccessMode_SINGLE_NODE_MULTI_WRITER,
        }
        gceDriver.AddVolumeCapabilityAccessModes(vcam)
        csc := []csi.ControllerServiceCapability_RPC_Type{
@@ -67,12 +69,14 @@ func (gceDriver *GCEDriver) SetupGCEDriver(name, vendorVersion string, extraVolu
                csi.ControllerServiceCapability_RPC_EXPAND_VOLUME,
                csi.ControllerServiceCapability_RPC_LIST_VOLUMES,
                csi.ControllerServiceCapability_RPC_LIST_VOLUMES_PUBLISHED_NODES,
+               csi.ControllerServiceCapability_RPC_SINGLE_NODE_MULTI_WRITER,
        }
        gceDriver.AddControllerServiceCapabilities(csc)
        ns := []csi.NodeServiceCapability_RPC_Type{
                csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME,
                csi.NodeServiceCapability_RPC_EXPAND_VOLUME,
                csi.NodeServiceCapability_RPC_GET_VOLUME_STATS,
+               csi.NodeServiceCapability_RPC_SINGLE_NODE_MULTI_WRITER,
        }
        gceDriver.AddNodeServiceCapabilities(ns)

实现 NodePublishVolume 行为

CSI 规范概述了针对同一卷但使用不同参数(如目标路径)多次调用 NodePublishVolume RPC 的预期行为。有关在驱动程序中实现时的预期行为的更多详细信息,请参阅 CSI 规范的 NodePublishVolume 部分的第二个表

更新您的 CSI sidecar

部署 CSI 驱动程序时,必须将以下 CSI sidecar 更新到依赖于 CSI 规范 v1.5.0+ 和 Kubernetes v1.22 API 的版本。 最低要求版本为

下一步是什么?

作为此功能的 Beta 毕业的一部分,SIG Storage 计划更新 Kubernetes 调度程序,以支持与 ReadWriteOncePod 存储相关的 Pod 抢占。这意味着如果两个 Pod 请求具有 ReadWriteOncePod 的 PersistentVolumeClaim,则优先级最高的 Pod 将获得对 PersistentVolumeClaim 的访问权限,任何优先级较低的 Pod 将从节点中被抢占,并且无法访问 PersistentVolumeClaim。

如何了解更多?

有关 ReadWriteOncePod 访问模式和 CSI 规范更改动机的更多详细信息,请参阅 KEP-2485

如何参与?

Kubernetes #csi Slack 频道 和任何 标准 SIG Storage 通信频道 都是联系 SIG Storage 和 CSI 团队的好方法。

特别感谢以下人员的深刻见解和设计考虑

  • Abdullah Gharaibeh (ahg-g)
  • Aldo Culquicondor (alculquicondor)
  • Ben Swartzlander (bswartz)
  • Deep Debroy (ddebroy)
  • Hemant Kumar (gnufied)
  • Humble Devassy Chirammal (humblec)
  • James DeFelice (jdef)
  • Jan Šafránek (jsafrane)
  • Jing Xu (jingxu97)
  • Jordan Liggitt (liggitt)
  • Michelle Au (msau42)
  • Saad Ali (saad-ali)
  • Tim Hockin (thockin)
  • Xing Yang (xing-yang)

如果您有兴趣参与 CSI 或 Kubernetes 存储系统的任何部分的设计和开发,请加入 Kubernetes 存储特别兴趣小组 (SIG)。我们正在快速发展,并且始终欢迎新的贡献者。