临时卷

本文档介绍了 Kubernetes 中的*临时卷*。建议熟悉,特别是 PersistentVolumeClaim 和 PersistentVolume。

某些应用程序需要额外的存储空间,但不关心这些数据是否在重启后持久存储。例如,缓存服务通常受内存大小的限制,并且可以将不常用的数据移动到比内存慢的存储中,而对整体性能的影响很小。

其他应用程序希望某些只读输入数据(如配置数据或密钥)存在于文件中。

*临时卷*就是为这些用例而设计的。因为卷遵循 Pod 的生命周期,并随 Pod 一起创建和删除,所以 Pod 可以停止和重启,而不受限于某些持久卷的可用性。

临时卷在 Pod 规范中*内联*指定,这简化了应用程序的部署和管理。

临时卷的类型

Kubernetes 支持几种不同类型的临时卷,用于不同的目的

emptyDirconfigMapdownwardAPIsecret 作为本地临时存储提供。它们由每个节点上的 kubelet 管理。

CSI 临时卷*必须*由第三方 CSI 存储驱动程序提供。

通用临时卷*可以*由第三方 CSI 存储驱动程序提供,也可以由任何其他支持动态配置的存储驱动程序提供。某些 CSI 驱动程序是专门为 CSI 临时卷编写的,不支持动态配置:这些驱动程序不能用于通用临时卷。

使用第三方驱动程序的优势在于,它们可以提供 Kubernetes 本身不支持的功能,例如,与 kubelet 管理的磁盘相比,性能特征不同的存储,或者注入不同的数据。

CSI 临时卷

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

从概念上讲,CSI 临时卷类似于 configMapdownwardAPIsecret 卷类型:存储在每个节点上本地管理,并在 Pod 被调度到节点后与其他本地资源一起创建。在此阶段,Kubernetes 不再有重新调度 Pod 的概念。卷创建必须不太可能失败,否则 Pod 启动会卡住。特别是,这些卷*不*支持存储容量感知 Pod 调度。它们目前也不受 Pod 存储资源使用限制的约束,因为这是 kubelet 只能对其自身管理的存储实施的限制。

下面是一个使用 CSI 临时存储的 Pod 的示例清单

kind: Pod
apiVersion: v1
metadata:
  name: my-csi-app
spec:
  containers:
    - name: my-frontend
      image: busybox:1.28
      volumeMounts:
      - mountPath: "/data"
        name: my-csi-inline-vol
      command: [ "sleep", "1000000" ]
  volumes:
    - name: my-csi-inline-vol
      csi:
        driver: inline.storage.kubernetes.io
        volumeAttributes:
          foo: bar

volumeAttributes 确定驱动程序准备什么卷。这些属性特定于每个驱动程序,没有标准化。有关进一步说明,请参阅每个 CSI 驱动程序的文档。

CSI 驱动程序限制

CSI 临时卷允许用户作为 Pod 规范的一部分,将 volumeAttributes 直接提供给 CSI 驱动程序。允许通常仅限管理员使用的 volumeAttributes 的 CSI 驱动程序*不*适合在内联临时卷中使用。例如,通常在 StorageClass 中定义的参数不应通过使用内联临时卷暴露给用户。

需要限制允许在 Pod 规范中用作内联卷的 CSI 驱动程序的集群管理员可以通过以下方式实现

  • 从 CSIDriver 规范中的 volumeLifecycleModes 中删除 Ephemeral,这可以防止该驱动程序用作内联临时卷。
  • 使用准入 Webhook来限制该驱动程序的使用方式。

通用临时卷

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

通用临时卷类似于 emptyDir 卷,因为它们为临时数据提供了一个 Pod 专用目录,该目录在配置后通常为空。但它们也可能具有其他功能

  • 存储可以是本地的,也可以是网络连接的。
  • 卷可以具有固定大小,Pod 不能超过该大小。
  • 卷可能有一些初始数据,具体取决于驱动程序和参数。
  • 假设驱动程序支持,则支持对卷的典型操作,包括快照克隆调整大小存储容量跟踪

示例

kind: Pod
apiVersion: v1
metadata:
  name: my-app
spec:
  containers:
    - name: my-frontend
      image: busybox:1.28
      volumeMounts:
      - mountPath: "/scratch"
        name: scratch-volume
      command: [ "sleep", "1000000" ]
  volumes:
    - name: scratch-volume
      ephemeral:
        volumeClaimTemplate:
          metadata:
            labels:
              type: my-frontend-volume
          spec:
            accessModes: [ "ReadWriteOnce" ]
            storageClassName: "scratch-storage-class"
            resources:
              requests:
                storage: 1Gi

生命周期和 PersistentVolumeClaim

关键的设计理念是,允许在 Pod 的卷源内部使用卷声明的参数。支持标签、注释和 PersistentVolumeClaim 的整套字段。创建此类 Pod 时,临时卷控制器会在与 Pod 相同的命名空间中创建一个实际的 PersistentVolumeClaim 对象,并确保在删除 Pod 时删除 PersistentVolumeClaim。

这会触发卷绑定和/或配置,如果StorageClass使用立即卷绑定,则会立即触发;如果在 Pod 暂时调度到节点上时(WaitForFirstConsumer 卷绑定模式),则会触发。建议对通用临时卷使用后者,因为这样调度器就可以自由地为 Pod 选择合适的节点。使用立即绑定,一旦卷可用,调度器就被迫选择一个可以访问该卷的节点。

资源所有权方面,具有通用临时存储的 Pod 是提供该临时存储的 PersistentVolumeClaim 的所有者。删除 Pod 时,Kubernetes 垃圾收集器会删除 PVC,这通常会触发删除卷,因为存储类的默认回收策略是删除卷。您可以使用回收策略为 retain 的 StorageClass 创建准临时本地存储:存储的生命周期超过 Pod,在这种情况下,您需要确保单独执行卷清理。

虽然这些 PVC 存在,但它们可以像任何其他 PVC 一样使用。特别是,它们可以在卷克隆或快照中作为数据源被引用。PVC 对象还保存卷的当前状态。

PersistentVolumeClaim 命名

自动创建的 PVC 的命名是确定性的:名称是 Pod 名称和卷名称的组合,中间用连字符 (-) 连接。在上面的例子中,PVC 名称将是 my-app-scratch-volume。这种确定性命名使得与 PVC 交互更容易,因为一旦知道 Pod 名称和卷名称,就不必再搜索它。

确定性命名也会在不同的 Pod(一个 Pod "pod-a" 的卷名为 "scratch",另一个 Pod 的名称为 "pod",卷名为 "a-scratch",最终都会得到相同的 PVC 名称 "pod-a-scratch")以及 Pod 和手动创建的 PVC 之间引入潜在的冲突。

此类冲突会被检测到:只有当 PVC 是为 Pod 创建的,它才会被用于临时卷。此检查基于所有权关系。现有的 PVC 不会被覆盖或修改。但这并不能解决冲突,因为如果没有正确的 PVC,Pod 就无法启动。

安全

使用通用临时卷允许用户在可以创建 Pod 的情况下间接创建 PVC,即使他们没有直接创建 PVC 的权限。集群管理员必须意识到这一点。如果这不符合他们的安全模型,他们应该使用一个 准入 Webhook 来拒绝具有通用临时卷的对象(如 Pod)。

正常的 PVC 命名空间配额 仍然适用,因此即使允许用户使用这种新机制,他们也不能使用它来绕过其他策略。

下一步

由 kubelet 管理的临时卷

请参阅 本地临时存储

CSI 临时卷

通用临时卷

上次修改时间:2024 年 2 月 26 日上午 12:05 PST:修复 ephemeral-volumes.md 中的拼写错误 (cf5a8f86dc)