永久性卷和动态预配


本页面简要介绍了 Kubernetes 中的永久性卷和声明,及其在 Google Kubernetes Engine (GKE) 中的用法。本页面重点介绍由 Compute Engine 永久性磁盘支持的存储。

PersistentVolume

PersistentVolume 资源用于管理集群中的持久性存储。在 GKE 中,PersistentVolume 通常由永久性磁盘支持。您还可以使用其他存储解决方案,例如 NFS。Filestore 是 Google Cloud 上的 NFS 解决方案。如需了解如何将 Filestore 实例设置为 GKE 集群的 NFS PV 解决方案,请参阅 Filestore 文档中的访问使用 Filestore CSI 驱动程序的 Filestore 实例

另一个存储选项是 Cloud Volumes Service。此产品是一项全托管式云端数据存储服务,可提供高级数据管理功能和高度可伸缩的性能。

PersistentVolume 生命周期由 Kubernetes 管理。PersistentVolume 可以动态预配;您不必手动创建和删除备份存储。

PersistentVolume 是独立于 Pods 存在的集群资源。 这意味着在集群更改时以及在删除并重新创建 Pod 时,PersistentVolume 表示的磁盘和数据将继续存在。PersistentVolume 资源可以通过 PersistentVolumeClaims 动态预配,也可以由集群管理员明确创建。

如需详细了解 PersistentVolume 资源,请参阅 Kubernetes 永久性卷文档Persistent Volumes API 参考文档

PersistentVolumeClaims

PersistentVolumeClaim 表示针对 PersistentVolume 资源的请求和声明。PersistentVolumeClaim 对象会针对 PersistentVolume 请求特定大小、访问模式和 StorageClass。如果存在满足请求的 PersistentVolume 或者可以预配,则 PersistentVolumeClaim 会绑定到该 PersistentVolume

Pod 将声明用作卷。集群会检查声明以找到绑定的卷并为 Pod 装载该卷。

可移植性是使用 PersistentVolumesPersistentVolumeClaims 的另一个优点。您可以在不同集群和环境中轻松使用相同的 Pod 规范,因为 PersistentVolume 是实际后备存储的接口。

StorageClass

诸如 Compute Engine 永久性磁盘容器存储接口 (CSI) 驱动程序等卷实现是通过 StorageClass 资源配置的。

GKE 会为您创建一个使用均衡永久性磁盘类型 (ext4) 的默认 StorageClass。当 PersistentVolumeClaim 未指定 StorageClassName 时,将使用默认的 StorageClass。您可以将提供的默认 StorageClass 替换为您自己的。有关说明,请参阅更改默认 StorageClass

您可以创建自己的 StorageClass 资源来说明不同类别的存储。例如,类可能与服务质量等级或备份政策相对应。在其他存储系统中,此概念有时称为“配置文件”。

如果您使用的是具有 Windows 节点池的集群,则必须创建 StorageClass 并在 PersistentVolumeClaim 中指定 StorageClassName,因为默认 fstype (ext4) 不受 Windows 支持。如果您使用的是 Compute Engine 永久性磁盘,则必须使用 NTFS 作为文件存储类型。

定义 StorageClass 时,您必须列出预配工具。在 GKE 上,我们建议您使用以下预配工具之一:

动态预配 PersistentVolume

在大多数情况下,您不需要直接配置 PersistentVolume 对象或创建 Compute Engine 永久性磁盘。您可以改为创建 PersistentVolumeClaim,Kubernetes 会自动为您预配永久性磁盘。

以下清单描述了对具有 30 吉比字节 (GiB) 存储空间的磁盘的请求,该磁盘的访问模式允许单个节点以读写方式装载磁盘。此外,该清单还会创建一个将 PersistentVolumeClaim 用作卷的 Pod。

# pvc-pod-demo.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-demo
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 30Gi
  storageClassName: standard-rwo
---
kind: Pod
apiVersion: v1
metadata:
  name: pod-demo
spec:
  volumes:
    - name: pvc-demo-vol
      persistentVolumeClaim:
       claimName: pvc-demo
  containers:
    - name: pod-demo
      image: nginx
      resources:
        limits:
          cpu: 10m
          memory: 80Mi
        requests:
          cpu: 10m
          memory: 80Mi
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: pvc-demo-vol

在您使用 kubectl apply -f pvc-pod-demo.yaml 创建此 PersistentVolumeClaim 对象时,Kubernetes 会动态创建相应的 PersistentVolume 对象。

由于存储类别 standard-rwo 使用卷绑定模式 WaitForFirstConsumer,因此在安排 Pod 使用该卷之前,不会创建 PersistentVolume

以下示例展示了已创建的 PersistentVolume

apiVersion: v1
kind: PersistentVolume
metadata:
  annotations:
    pv.kubernetes.io/provisioned-by: pd.csi.storage.gke.io
  finalizers:
  - kubernetes.io/pv-protection
  - external-attacher/pd-csi-storage-gke-io
  name: pvc-c9a44c07-cffa-4cd8-b92b-15bac9a9b984
  uid: d52af557-edf5-4f96-8e89-42a3008209e6
spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 30Gi
  claimRef:
    apiVersion: v1
    kind: PersistentVolumeClaim
    name: pvc-demo
    namespace: default
    uid: c9a44c07-cffa-4cd8-b92b-15bac9a9b984
  csi:
    driver: pd.csi.storage.gke.io
    csi.storage.k8s.io/fstype: ext4
    volumeAttributes:
      storage.kubernetes.io/csiProvisionerIdentity: 1660085000920-8081-pd.csi.storage.gke.io
    volumeHandle: projects/xxx/zones/us-central1-c/disks/pvc-c9a44c07-cffa-4cd8-b92b-15bac9a9b984
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: topology.gke.io/zone
          operator: In
          values:
          - us-central1-c
  persistentVolumeReclaimPolicy: Delete
  storageClassName: standard-rwo
  volumeMode: Filesystem
status:
  phase: Bound

假设您尚未替换存储类别 standard-rwo,则此 PersistentVolume 会由一个新的空 Compute Engine 永久性磁盘支持。

删除永久性存储

默认情况下,删除动态预配的卷(如 Compute Engine 永久性磁盘)的 PersistentVolumeClaim 会同时删除 PersistentVolume 对象和实际备份磁盘。此行为由 StorageClass 和 PersistentVolume 中的收回政策控制,可设置为默认值 DeleteRetain。如需了解详情,请参阅有关收回的 Kubernetes 文档。

在集群删除期间管理永久性存储

删除 GKE 集群后,GKE 将使用 DeleteRetain 收回政策保留 PersistentVolume 资源。

如需在删除集群时移除 PersistentVolume 资源,您可以手动删除 PersistentVolumeClaim 资源的命名空间,这会触发删除具有 Delete 政策的 PersistentVolume 对象。或者,您可以删除单个 PersistentVolumeClaim 资源。但是,GKE 不会等待这些删除活动完成后再开始删除集群。因此,如果您删除命名空间并立即删除集群,则系统可能不会删除具有 Delete 政策的 PersistentVolume 资源。

删除集群后,您可以在 Google Cloud 控制台中查看剩余的 PersistentVolume 资源。

如需查看任何未使用的资源(例如未使用的 PersistentVolume 资源),您可以查看针对空闲资源的建议

访问模式

PersistentVolume 资源支持以下访问模式

  • ReadWriteOnce:卷可以由单个节点以读写方式装载。
  • ReadOnlyMany:卷可以由多个节点以只读方式装载。
  • ReadWriteMany:卷可以由多个节点以读写方式装载。 由 Compute Engine 永久性磁盘支持的 PersistentVolume 资源不支持此访问模式。

以 ReadOnlyMany 方式使用 Compute Engine 永久性磁盘

ReadWriteOnce 是永久性磁盘最常见的使用场景,用作大多数应用的默认访问模式。Compute Engine 永久性磁盘也支持 ReadOnlyMany 模式,以便多个应用或同一应用的多个副本可以同时使用同一磁盘。一个示例使用场景是跨多个副本传送静态内容。

如需了解相关说明,请参阅将永久性磁盘与多个读取器结合使用

将预先存在的永久性磁盘用作 PersistentVolume

动态预配的 PersistentVolume 在创建时是空的。如果您已经有一个填充了数据的现存 Compute Engine 永久性磁盘,您可以通过手动创建对应的 PersistentVolume 资源将该磁盘引入您的集群。永久性磁盘必须与集群节点位于同一可用区中。

请参阅如何创建由预先存在的永久性磁盘支持的永久性卷的相关示例

Deployment 与 StatefulSet

您可以在更高级层的控制器(如 DeploymentStatefulSet)中分别使用 PersistentVolumeClaimVolumeClaim 模板。

Deployment 是专为无状态应用设计的,因此 Deployment 的所有副本共用同一个 PersistentVolumeClaim。由于创建的副本 Pod 彼此相同,因此只有具有 ReadWriteMany 模式的卷才能适用于此设置。

即使是具有一个使用 ReadWriteOnce 卷的副本的 Deployment,也不建议采用。这是因为默认 Deployment 策略会在重新创建时先创建第二个 Pod,然后再关闭第一个 Pod。第二个 Pod 无法启动时,Deployment 可能会因死锁而失败,这是因为 ReadWriteOnce 卷已在使用中,而第一个 Pod 由于第二个 Pod 尚未启动而无法移除。应改为针对 ReadWriteOnce 卷使用 StatefulSet。

建议使用 StatefulSet 部署有状态应用,这些应用需要每个副本具有唯一卷。通过将 StatefulSet 与 PersistentVolumeClaim 模板结合使用,您的应用可以随与每个副本 Pod 关联的唯一 PersistentVolumesClaim 自动纵向扩容。

区域永久性磁盘

区域永久性磁盘是多可用区资源,在同一区域中的两个可用区之间复制数据,并且使用方式与可用区永久性磁盘类似。如果发生可用区中断,或者某个可用区的集群节点无法安排,Kubernetes 可进行故障切换,将使用该卷的工作负载分配到其他可用区。您可以使用区域永久性磁盘为 GKE 上的有状态工作负载构建高可用性解决方案。您必须确保主要可用区和故障切换可用区都配置了足够的资源容量来运行工作负载。

区域 SSD 永久性磁盘是应用(例如同时要求高可用性和高性能的数据库)的一个选项。如需了解详情,请参阅块存储性能比较

与可用区永久性磁盘一样,区域永久性磁盘可以根据需要动态预配,也可以由集群管理员提前预配。如需了解如何添加区域永久性磁盘,请参阅预配区域永久性磁盘

永久性磁盘中的可用区

可用区永久性磁盘是可用区级资源,而区域永久性磁盘是多可用区资源。在向集群添加永久性存储时,除非指定了可用区,否则 GKE 会将磁盘分配给单个可用区。GKE 会随机选择可用区。预配永久性磁盘后,任何引用磁盘的 Pod 都将被安排到磁盘所在的区域。

卷绑定模式 WaitForFirstConsumer

如果您在集群中动态预配永久性磁盘,我们建议您在 StorageClass 上设置 WaitForFirstConsumer 卷绑定模式。此设置指示 Kubernetes 在与 Pod 调度到的相同可用区中预配永久性磁盘。它遵循 Pod 调度限制条件,例如反亲和性与节点选择器。可用区上的反亲和性允许将 StatefulSet Pod 以及对应的磁盘分布在各个可用区中。

以下是用于预配可用区永久性磁盘且设置 WaitForFirstConsumer 的示例 StorageClass

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: slow
provisioner: pd.csi.storage.gke.io
parameters:
  type: pd-balanced
  csi.storage.k8s.io/fstype: ext4
volumeBindingMode: WaitForFirstConsumer

如需查看使用区域永久性磁盘的示例,请参阅预配区域永久性磁盘

后续步骤