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

Kubernetes 容器存储接口 (CSI) 正式可用

Kubernetes Logo CSI Logo

Kubernetes 实现的 容器存储接口 (CSI) 已在 Kubernetes v1.13 版本中晋升为 GA (正式可用)。对 CSI 的支持最初在 Kubernetes v1.9 版本中以 alpha 版本引入,并在 Kubernetes v1.10 版本中晋升为 beta 版本

达到 GA 里程碑意味着 Kubernetes 用户可以依赖该功能及其 API,无需担心未来因向后不兼容的更改而导致回退问题。GA 功能受 Kubernetes 弃用策略保护。

为什么选择 CSI?

虽然在 CSI 之前 Kubernetes 提供了强大的卷插件系统,但在 Kubernetes 中添加新的卷插件支持却充满挑战:卷插件是“in-tree”(内置)的,这意味着它们的代码是核心 Kubernetes 代码的一部分,并随核心 Kubernetes 二进制文件一起发布——希望将自己的存储系统支持添加到 Kubernetes(甚至修复现有卷插件中的 bug)的供应商,不得不与 Kubernetes 发布流程保持一致。此外,第三方存储代码可能导致核心 Kubernetes 二进制文件出现可靠性和安全性问题,并且 Kubernetes 维护者往往很难(在某些情况下甚至不可能)对其代码进行测试和维护。

CSI 的开发旨在成为一种标准,用于将任意块存储和文件存储系统暴露给 Kubernetes 等容器编排系统 (COs) 上的容器化工作负载。随着容器存储接口的采用,Kubernetes 卷层变得真正可扩展。通过使用 CSI,第三方存储提供商可以编写和部署插件,在 Kubernetes 中暴露新的存储系统,而无需触碰核心 Kubernetes 代码。这为 Kubernetes 用户提供了更多存储选项,并使系统更加安全可靠。

有什么新特性?

晋升为 GA 后,Kubernetes 实现的 CSI 引入了以下变更

  • Kubernetes 现在兼容 CSI 规范的 v1.0v0.3 版本(而非 CSI 规范 v0.2 版本)。
    • CSI 规范 v0.3.0 和 v1.0.0 之间存在破坏性变更 (breaking changes),但 Kubernetes v1.13 支持这两个版本,因此任一版本都可以在 Kubernetes v1.13 中使用。
    • 请注意,随着 CSI 1.0 API 的发布,对使用 CSI API 0.3 及更旧版本的 CSI 驱动程序的支持已被弃用,并计划在 Kubernetes v1.15 中移除。
    • CSI 规范 v0.2 和 v0.3 之间没有破坏性变更 (breaking changes),因此 v0.2 驱动程序也应该可以在 Kubernetes v1.10.0+ 中使用。
    • CSI 规范 v0.1 和 v0.2 之间存在破坏性变更 (breaking changes),因此实现 CSI 0.1 的非常旧的驱动程序在使用 Kubernetes v1.10.0+ 之前,必须更新至至少兼容 0.2 版本。
  • Kubernetes VolumeAttachment 对象(在 v1.9 版本中引入,属于 storage v1alpha1 组;在 v1.10 版本中添加到 v1beta1 组)已在 v1.13 版本中添加到 storage v1 组。
  • Kubernetes CSIPersistentVolumeSource 卷类型已晋升为 GA (正式可用)。
  • Kubelet 设备插件注册机制,即 kubelet 发现新 CSI 驱动程序的方式,已在 Kubernetes v1.13 中晋升为 GA (正式可用)。

如何部署 CSI 驱动程序?

对如何在 Kubernetes 上部署或管理现有 CSI 驱动程序感兴趣的 Kubernetes 用户,应查阅 CSI 驱动程序作者提供的文档。

如何使用 CSI 卷?

假设 CSI 存储插件已部署在 Kubernetes 集群上,用户可以通过熟悉的 Kubernetes 存储 API 对象使用 CSI 卷:PersistentVolumeClaimsPersistentVolumesStorageClasses。相关文档可参阅此处

尽管 Kubernetes 对 CSI 的实现是 Kubernetes v1.13 中的 GA 功能,但可能需要以下标志

  • API 服务器二进制文件和 kubelet 二进制文件
    • --allow-privileged=true
      • 大多数 CSI 插件需要双向挂载传播 (mount propagation),这只能为特权 Pod (privileged pods) 启用。仅当集群中此标志设置为 true 时(在 GCE、GKE 和 kubeadm 等某些环境中这是默认值),才允许使用特权 Pod。

动态供应

通过创建指向 CSI 插件的 StorageClass,您可以为支持动态供应的 CSI 存储插件启用卷的自动创建/删除功能。

例如,以下 StorageClass 允许名为 “csi-driver.example.com” 的 CSI 卷插件动态创建 “fast-storage” 卷。

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: fast-storage
provisioner: csi-driver.example.com
parameters:
  type: pd-ssd
  csi.storage.k8s.io/provisioner-secret-name: mysecret
  csi.storage.k8s.io/provisioner-secret-namespace: mynamespace

GA 新特性:CSI external-provisioner (v1.0.1+) 保留以 csi.storage.k8s.io/ 为前缀的参数键。如果这些键不对应已知键集,则值会被忽略(且不传递给 CSI 驱动程序)。较旧的 secret 参数键 (csiProvisionerSecretName, csiProvisionerSecretNamespace 等) 也受 CSI external-provisioner v1.0.1 支持,但已被弃用,并在未来版本的 CSI external-provisioner 中移除。

动态供应由创建 PersistentVolumeClaim 对象触发。例如,以下 PersistentVolumeClaim 使用上述 StorageClass 触发动态供应。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-request-for-storage
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: fast-storage

当调用卷供应时,参数类型:pd-ssd 和任何引用的 secret(s) 将通过 CreateVolume 调用传递给 CSI 插件 csi-driver.example.com。作为响应,外部卷插件会配置一个新卷,然后自动创建一个 PersistentVolume 对象来表示该新卷。Kubernetes 随后将新的 PersistentVolume 对象绑定到 PersistentVolumeClaim,使其可供使用。

如果 fast-storage StorageClass 被标记为“default”,则无需在 PersistentVolumeClaim 中包含 storageClassName,它将默认使用。

预配置卷

您始终可以通过手动创建一个 PersistentVolume 对象来代表现有卷,从而在 Kubernetes 中暴露一个预先存在的卷。例如,以下 PersistentVolume 暴露了一个名为 “existingVolumeName” 的卷,该卷属于名为 “csi-driver.example.com” 的 CSI 存储插件。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-manually-created-pv
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  csi:
    driver: csi-driver.example.com
    volumeHandle: existingVolumeName
    readOnly: false
    fsType: ext4
    volumeAttributes:
      foo: bar
    controllerPublishSecretRef:
      name: mysecret1
      namespace: mynamespace
    nodeStageSecretRef:
      name: mysecret2
      namespace: mynamespace
    nodePublishSecretRef
      name: mysecret3
      namespace: mynamespace

附加和挂载

您可以在任何 Pod 或 Pod 模板中引用绑定到 CSI 卷的 PersistentVolumeClaim

kind: Pod
apiVersion: v1
metadata:
  name: my-pod
spec:
  containers:
    - name: my-frontend
      image: nginx
      volumeMounts:
      - mountPath: "/var/www/html"
        name: my-csi-volume
  volumes:
    - name: my-csi-volume
      persistentVolumeClaim:
        claimName: my-request-for-storage

当引用 CSI 卷的 Pod 被调度时,Kubernetes 将触发针对外部 CSI 插件的相应操作 (ControllerPublishVolume, NodeStageVolume, NodePublishVolume 等),以确保指定的卷被附加、挂载并可供 Pod 中的容器使用。

更多详情请参阅 CSI 实现的设计文档文档

如何编写 CSI 驱动程序?

kubernetes-csi 网站详细介绍了如何在 Kubernetes 上开发、部署和测试 CSI 驱动程序。一般来说,CSI 驱动程序应与以下 sidecar (辅助) 容器一起部署在 Kubernetes 上:

存储厂商可以使用这些组件为其插件构建 Kubernetes 部署,而他们的 CSI 驱动程序完全无需感知 Kubernetes。

CSI 驱动程序列表

CSI 驱动程序由第三方开发和维护。您可以在此处找到非详尽的 CSI 驱动程序列表。

内置 (in-tree) 卷插件呢?

有一个计划将大多数持久性、远程内置 (in-tree) 卷插件迁移到 CSI。更多详情请参阅设计文档

GA 的限制

CSI 的 GA 实现存在以下限制

  • 临时本地卷 (Ephemeral local volumes) 必须创建 PVC(不支持 Pod 内联引用 (pod inline referencing) CSI 卷)。

下一步是什么?

  • 将仍处于 alpha 阶段的 Kubernetes CSI 功能推向 beta 阶段的工作
    • 裸块设备卷
    • 拓扑感知(Kubernetes 理解并影响 CSI 卷配置位置(zone, regions 等)的能力)。
    • 依赖于 CSI CRD 的功能(例如:“Skip attach” 和 “Pod info on mount”)。
    • 卷快照
  • 完成对本地临时卷的支持工作。
  • 将远程持久性内置 (in-tree) 卷插件迁移到 CSI 的工作。

如何参与?

Kubernetes Slack 频道 wg-csi 和 Google 群组 kubernetes-sig-storage-wg-csi,以及任何标准的SIG Storage 通信渠道,都是联系 SIG Storage 团队的好方式。

与其他所有 Kubernetes 项目一样,该项目是众多来自不同背景的贡献者共同努力的成果。我们衷心感谢本季度挺身而出帮助项目达到 GA 阶段的新贡献者:

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