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

Kubernetes 本地持久卷进入 Beta

Kubernetes 1.10 中的 本地持久卷 Beta 功能使得在 StatefulSets 中利用本地磁盘成为可能。你可以将直接连接的本地磁盘指定为 PersistentVolumes,并使用与先前仅支持远程卷类型相同的 PersistentVolumeClaim 对象在 StatefulSets 中使用它们。

持久存储对于运行有状态应用程序至关重要,Kubernetes 通过 StatefulSets、PersistentVolumeClaims 和 PersistentVolumes 支持这些工作负载。这些基本单元很好地支持了远程卷类型,这些卷可以从集群中的任何节点访问,但不支持本地卷,即只能从特定节点访问的卷。随着在 Kubernetes 中运行更多工作负载的需求增加,对在复制的有状态工作负载中使用本地快速 SSD 的需求也随之增加。

解决 hostPath 挑战

以前通过 hostPath 卷访问本地存储的机制存在许多挑战。hostPath 卷在大规模生产环境中难以使用:操作员在使用 hostPath 卷时需要关心本地磁盘管理、拓扑和单个 Pod 的调度,并且无法使用许多 Kubernetes 功能(如 StatefulSets)。现有的使用远程卷的 Helm Chart 无法轻松移植到使用 hostPath 卷。本地持久卷功能旨在解决 hostPath 卷的可移植性、磁盘记账和调度挑战。

免责声明

在深入了解如何使用本地持久卷之前,请注意本地卷不适合大多数应用程序。使用本地存储将应用程序绑定到特定节点,使得应用程序更难调度。如果该节点或本地卷发生故障而无法访问,则该 Pod 也将无法访问。此外,许多云服务提供商对本地存储不提供广泛的数据持久性保证,因此在某些情况下可能会丢失所有数据。

出于这些原因,大多数应用程序应继续使用高可用、远程访问、持久的存储。

合适的工作负载

适合使用本地存储的一些用例包括:

  • 缓存可利用数据引力实现快速处理的数据集
  • 跨多个节点分片或复制数据的分布式存储系统。示例包括分布式数据存储(如 Cassandra)或分布式文件系统(如 Gluster 或 Ceph)。

合适的工作负载能够容忍节点故障、数据不可用和数据丢失。它们为集群的其余部分提供关键的、对延迟敏感的基础设施服务,并且应该相对于其他工作负载以高优先级运行。

启用更智能的调度和卷绑定

管理员必须为本地持久卷启用更智能的调度。在为本地 PersistentVolumes 创建任何 PersistentVolumeClaims 之前,必须创建一个 StorageClass 并将 volumeBindingMode 设置为“WaitForFirstConsumer”。

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

此设置告诉 PersistentVolume 控制器不要立即绑定 PersistentVolumeClaim。相反,系统会等待需要使用卷的 Pod 被调度。然后调度器会选择一个合适的本地 PersistentVolume 进行绑定,同时考虑 Pod 的其他调度约束和策略。这确保了初始卷绑定与 Pod 的任何资源需求、选择器、亲和性/反亲和性策略等兼容。

请注意,Beta 版本不支持动态供给。所有本地 PersistentVolumes 都必须静态创建。

创建本地持久卷

对于此初始 Beta 版本,本地磁盘必须首先由管理员在本地节点上预先分区、格式化并挂载。共享文件系统上的目录也受支持,但也必须在使用前创建。

设置好本地卷后,可以为其创建一个 PersistentVolume。在此示例中,本地卷挂载在节点“my-node”的“/mnt/disks/vol1”路径下。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-local-pv
spec:
  capacity:
    storage: 500Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: local-storage
  local:
    path: /mnt/disks/vol1
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - my-node

请注意 PersistentVolume 对象中有一个新的 nodeAffinity 字段:Kubernetes 调度器就是通过它来理解此 PersistentVolume 绑定到特定节点。nodeAffinity 是本地 PersistentVolumes 的必需字段。

当像这样手动创建本地卷时,唯一支持的 persistentVolumeReclaimPolicy 是“Retain”。当 PersistentVolume 从 PersistentVolumeClaim 中释放后,管理员必须手动清理并重新设置本地卷以供重用。

自动化本地卷创建和删除

手动创建和清理本地卷是一项巨大的管理负担,因此我们编写了一个简单的本地卷管理器来自动化其中一些部分。它可在 external-storage 仓库中作为可选程序部署在集群中,其中包含如何运行它的说明和示例部署 Spec。

要使用它,本地卷仍然必须首先由管理员在本地节点上设置并挂载。管理员需要将本地卷挂载到本地卷管理器识别的可配置的“发现目录”中。共享文件系统上的目录受支持,但必须绑定挂载到发现目录中。

此本地卷管理器监视发现目录,寻找任何新的挂载点。管理器会为检测到的任何新挂载点创建一个 PersistentVolume 对象,其中包含相应的 storageClassName、path、nodeAffinity 和 capacity。这些 PersistentVolume 对象最终可以被 PersistentVolumeClaims 申请,然后挂载到 Pod 中。

在 Pod 使用完卷并删除其 PersistentVolumeClaim 后,本地卷管理器通过删除其中的所有文件来清理本地挂载,然后删除 PersistentVolume 对象。这会触发发现周期:为该卷创建一个新的 PersistentVolume,并可以被新的 PersistentVolumeClaim 重用。

一旦管理员最初设置了本地卷挂载,此本地卷管理器将接管 PersistentVolume 生命周期的其余部分,无需进一步的管理员干预。

在 Pod 中使用本地卷

经过所有这些管理员工作之后,用户如何才能真正将本地卷挂载到他们的 Pod 中呢?幸运的是,从用户的角度来看,可以通过完全相同的方式请求本地卷,就像请求任何其他 PersistentVolume 类型一样:通过 PersistentVolumeClaim。只需在 PersistentVolumeClaim 对象中指定适用于本地卷的相应 StorageClassName,系统就会处理其余的事情!

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: example-local-claim
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: local-storage
  resources:
    requests:
      storage: 500Gi

或在 StatefulSet 中作为 volumeClaimTemplate 使用

kind: StatefulSet
...
 volumeClaimTemplates:
  - metadata:
      name: example-local-claim
    spec:
      accessModes:
      - ReadWriteOnce
      storageClassName: local-storage
      resources:
        requests:
          storage: 500Gi

文档

Kubernetes 网站提供了有关 本地持久卷的完整文档。

未来增强

本地持久卷 Beta 功能远未完成。一些正在开发中的显著增强包括:

  • 从 1.10 版本开始,本地裸块卷作为 Alpha 功能可用。这对于需要直接访问块设备并管理自己的数据格式的工作负载非常有用。
  • 使用 LVM 进行本地卷的动态供给正在设计中,Alpha 实现将在未来版本中跟进。这将消除管理员预先分区、格式化和挂载本地卷的现有需求,只要工作负载的性能需求能够容忍共享磁盘。

补充功能

Pod 优先级和抢占 是另一个与本地持久卷互补的 Kubernetes 功能。当你的应用程序使用本地存储时,它必须被调度到本地卷所在的特定节点上。你可以为本地存储工作负载设置高优先级,这样如果该节点没有足够的空间运行你的工作负载,Kubernetes 可以抢占优先级较低的工作负载为其腾出空间。

Pod 中断预算 对于那些必须维持多数仲裁的工作负载也非常重要。为你的工作负载设置中断预算可以确保它不会因自愿中断事件(如升级期间的节点排空)而低于多数仲裁。

Pod 亲和性与反亲和性 确保你的工作负载要么并置在同一故障域,要么分散在不同故障域。如果单个节点上有多个本地持久卷可用,最好指定 Pod 反亲和性策略以将工作负载分散到不同节点。请注意,如果你希望多个 Pod 共享同一个本地持久卷,则无需指定 Pod 亲和性策略。调度器理解本地持久卷的位置限制,并将你的 Pod 调度到正确的节点。

参与其中

如果你对这个功能有反馈或者有兴趣参与设计和开发,请加入 Kubernetes 存储特别兴趣小组 (SIG)。我们正在快速发展,随时欢迎新的贡献者。

特别感谢来自多家公司、帮助将此功能引入 Beta 的所有贡献者,包括 Cheng Xing (verult)、David Zhu (davidz627)、Deyuan Deng (ddysher)、Dhiraj Hedge (dhirajh)、Ian Chakeres (ianchakeres)、Jan Šafránek (jsafrane)、Matthew Wong (wongma7)、Michelle Au (msau42)、Serguei Bezverkhi (sbezverk) 和 Yuquan Ren (nickrenren)。