Kubernetes 容器存储接口(CSI)Alpha 简介






Kubernetes 与众不同的一点是,Volume Plugin System(存储卷插件系统)(注 1),这一系统让多种不同类型的存储系统可以:

  1. 按需自动创建存储。
  2. 让被调度在任何节点的容器都有存储可用。
  3. 自动删除无用存储。

然而为 Kubernetes 添加新的存储系统支持却是个富于挑战的事情。

Kubernetes 1.9 引入了 容器存储接口(CSI)的 Alpha 实现(注 2),这一功能让安装新的存储卷插件像部署 Pod 一样简单。同时给第三方存储提供商无需加入 Kubernetes 核心代码,即可开发存储的接入方案。

这一特性在 1.9 中还处于 Alpha 阶段,因此必须显式启用。虽说 Alpha 功能不推荐在生产环境中使用,但这是对项目方向的一个指引(CSI 来说,就是倡导一个更加易于扩展且更标准化的 Kubernetes 存储生态)。

Kubernetes 为什么需要 CSI ?

Kubernetes 的存储卷插件目前是内置的,也就是说这些内容是和 Kubernetes 核心一起连接、编译、构建和发布的。向 Kubernetes 中加入一种新的存储系统的支持(也就是一个存储卷插件),需要将代码 Check in 到 Kubernetes 仓库之中。但是对于很多插件开发者来说,跟随 Kubernetes 的发布流程是很痛苦的事情。

现有的 Flex Volume Plugin(注 3)尝试通过向外部卷插件暴露基于exec的 API 的方式来解决这一问题。虽然他让第三方存储供应商避开了写入 Kubernetes 核心代码的风险,但是这一技术却需要访问节点和 Master 的 root 文件系统。

除了上述问题之外,Flex 没能解决插件依赖问题:卷插件经常需要很多外部需求(例如 mount 和文件系统工具等)。插件经常假设这些依赖已经安装在宿主机操作系统中了,但是很可惜,经常没有(安装这些依赖也是需要对节点的 root 文件系统进行访问的)。

CSI 解决了所有问题,他允许在 Kubernetes 核心代码之外进行开发,使用标准的 Kubernetes 原语进行容器化部署,用户可以用熟知的 Kubernetes 存储原语(PV、PVC、StorageClass)来进行使用。

CSI 是什么?

CSI 的目标是为容器编排系统(COs)发布一种标准化的机制,用于向容器化的工作负载暴露任意存储。CSI 规范由众多社区成员合作起草,其中包括容器编排系统(COs)—— Kubernetes、Mesos、Docker 以及 Cloud Foundry。这一规范的开发是独立于 Kubernetes 的,在 https://github.com/container-storage-interface/spec/blob/master/spec.md 进行管理。

Kubernetes v1.9 提供了 CSI 规范的 Alpha 实现,允许 CSI 兼容卷在 Kubernetes 上的部署,并可以被 Kubernetes 负载进行消费。

如何在 Kubernetes 集群上部署 CSI 驱动?

CSI 插件作者提供了各自的介绍,用于在 Kubernetes 上部署他们的插件。

如何使用 CSI 卷?

如果 CSI 存储插件已经在你的集群上部署成功,就可以使用熟悉的 Kubernets Storage 原语进行操作:PersistentVolumeClaims、PersistentVolumes 还有 StorageClasses。

CSI 在 Kubernetes v1.9 中还是 Alpha 阶段,需要用如下方式进行启用:

API server:
--feature-gates=CSIPersistentVolume=true
--runtime-config=storage.k8s.io/v1alpha1=true
API server 和 kubelet:
--feature-gates=MountPropagation=true
--allow-privileged=true

动态供给

可以为 CSI 存储插件创建StorageClass,令其支持存储卷的自动创建和删除。

例如下面的StorageClass,为一个名为com.example.team/csi-driver的 CSI 存储卷插件创建了一个fast-storage StorageClass,从而启用了动态创建功能。

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

创建PersistentVolumeClaim对象就会触发动态供给功能。下面的PersistentVolumeClaim就会触发前面创建的StorageClass的动态供给能力:

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

当卷供给被调用时,会通过一个CreateVolume的调用,把参数type: pd-ssd传递给 CSI 插件com.example.team/csi-driver。外部卷插件响应这一请求,分配新的卷,并自动创建PersistentVolume对象,对应前面的 PVC 要求。Kubernetes 将新的PersistentVolume绑定到PersistentVolumeClaim上,存储分配完成就绪。

预分配卷

在 Kubernetes 中,当然还可以通过创建PersistentVolume对象的方式来创建预先分配的存储卷。举个例子,下面的PersistentVolume提供了一个叫做existingVolumeName的卷,这个卷属于 CSI 插件com.example.team/csi-driver

apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-manually-created-pv
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  csi:
    driver: com.example.team/csi-driver
    volumeHandle: existingVolumeName
    readOnly: false

附着和挂载

已经绑定到 CSI 卷的PersistentVolumeClaim对象,就可以在任何的 Pod 或者 Pod Template 中使用了:

kind: Pod
apiVersion: v1
metadata:
  name: my-pod
spec:
  containers:
    - name: my-frontend
      image: dockerfile/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 插件的相应操作(ControllerPublishVolumeNodePublishVolume等)来保证存储卷已经准备就绪可供 Pod 使用。

更多细节可以参考 CSI 实现的设计(注 4)文档(注 5)

如何创建一个 CSI 插件?

Kubernetes 尽可能少的干涉 CSI 卷插件的打包和发布规范。为 Kubernetes 发布 CSI 卷插件的最小需求文档在这里(注 6)

最小需求文档还包含了一节(注 7)概述了在 Kubernetes 上发布任意容器化 CSI 插件的推荐方式。存储提供者可以用这一方式来简单的在 Kubernetes 上部署容器化的 CSI 兼容卷驱动。

作为推荐部署的一部分,Kubernetes 团队提供了下面的 Sidecar(Helper) 容器:

  • external-attacher(注 8)
    • 这一容器可以监控 Kubernetes VolumeAttachment 对象,并触发 CSI 端点的ControllerPublish以及ControllerUnpublish
  • external-provisioner(注 9)
    • 这个 Sidebar 用来监控 Kubernetes 的PersistentVolumeClaim,并触发 CSI 端点的CreateVolumeDeleteVolume操作。
  • driver-registrar(注 10)
    • 用于注册到 kubelet(未来),并把插件的自定义NodeId(从 CSI 插件的GetNodeID方法获取)注解到 Kubernetets Node API 对象上去。

存储厂商可以使用这些素材来构建自己的 CSI 插件,完全无需 Kubernetes 参与。

哪里能找到 CSI 驱动?

CSI 驱动由第三方开发和管理。这里(注 11)有 CSI 示例,但是这只是用于目标说明,没有用于生产的预期。

Flex 怎么办?

Flex Volume 插件(注 12)基于 Exec 的机制,来创建核心之外的卷插件。虽然上面说到有一些不足,但是他会和 CSI 并存,SIG Storage 会持续管理 Flex API,让已经投入生产使用的第三方 Flex 驱动能够继续工作,未来新的功能就只会加入 CSI 之中。

已有的内置卷插件又怎么样呢?

一旦 CSI 达到稳定阶段,我们会把多数内置卷插件迁移到 CSI 之中。请持续关注 CSI 的进展情况。

Alpha 阶段有什么限制?

CSI 在 Alpha 阶段有这样一些限制:

  • CreateVolumeNodePublishVolume以及ControllerPublishVolume调用中的的凭证字段目前不受支持。
  • 不支持块卷,仅支持文件卷。
  • 不支持指定文件系统,缺省为ext4
  • 无论是否实现了ControllerPublishVolume,都必须部署external-attacher
  • Kubernetes 调度的拓扑感知(简单解释一下就是:分享卷供给来源信息(zone/region 等),让 Kubernetes 调度器进行更加精细的调度)不支持 CSI 卷。

下一步?

视乎反馈和接受程度,Kubernetes 团队计划在 1.10 或者 1.11 版本将 CSI 推进到 Beta 阶段。

  1. https://kubernetes.io/docs/concepts/storage/volumes/
  2. https://github.com/kubernetes/features/issues/178
  3. https://github.com/kubernetes/community/blob/master/contributors/devel/flexvolume.md
  4. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/container-storage-interface.md
  5. https://github.com/kubernetes-csi/docs/wiki/Setup
  6. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/container-storage-interface.md#third-party-csi-volume-drivers
  7. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/container-storage-interface.md#recommended-mechanism-for-deploying-csi-drivers-on-kubernetes
  8. https://github.com/kubernetes-csi/external-attacher
  9. https://github.com/kubernetes-csi/external-provisioner
  10. https://github.com/kubernetes-csi/driver-registrar
  11. https://github.com/kubernetes-csi/drivers
  12. https://github.com/kubernetes/community/blob/master/contributors/devel/flexvolume.md