概述

Kubernetes存储体系是围绕着PV/PVC资源打造的,支持各种主流的存储卷

通过下面命令可以看到支持的卷

kubectl explain pod.spec.volumes

另外也提供插件机制,允许其他类型的存储服务接入到 Kubernetes 系统中来

Kubernetes存储插件有两种模式:In-TreeOut-Of-TreeIn-Tree 就是在 Kubernetes 源码内部实现的,和 Kubernetes 一起发布、管理的,但是更新迭代慢、灵活性比较差,Out-Of-Tree 是独立于 Kubernetes 的,目前主要有 CSIFlexVolume 两种机制,

PV、PVC、StorageClass

这一套,基本上是Kubernetes最基本的存储用法

┌─────────────┐                        
│     Pod     │                        
└─────────────┘                        
       │                               
       ▼                               
┌─────────────┐                        
│     PVC     │────Check───────┐       
└─────────────┘                ▼       
       │                ┌─────────────┐
       │                │StorageClass │
     Bind               ├─────────────┤
       │                │ Provisioner │
       ▼                └─────────────┘
┌─────────────┐                │       
│     PV      │◀───Provision───┘       
└─────────────┘                        
  • PVC 描述的,是 Pod 想要使用的持久化存储的属性,比如存储的大小、读写权限等。

  • PV 描述的,则是一个具体的 Volume 的属性,比如 Volume 的类型、挂载目录、远程存储 服务器地址等。

  • 而 StorageClass 的作用,则是充当 PV 的模板。并且,只有同属于一个 StorageClass 的 PV 和 PVC,才可以绑定在一起。当然不用StorageClass也是可以的,但是生产上如果集群有成千上万PVC的时候,不可能手动去创建PV。

FlexVolume

flexvolume是一个二进制或者shell脚本,放在每个节点上,来实现 FlexVolume 的相关接口,其操作参数和执行参数都是固定的。

默认存储插件的存放路径为/usr/libexec/kubernetes/kubelet-plugins/volume/exec/<vendor~driver>/<driver>VolumePlugins 组件会不断 watch 这个目录来实现插件的添加、删除等功能。

其中 vendor~driver 的名字需要和 Pod 中flexVolume.driver 的字段名字匹配

并不一定所有接口都需要实现,比如NFS这样的存储就没必要实现 attach/detach 这些接口了,因为不需要,只需要实现 init/mount/umount 3个接口即可,官方提供了一个简单的示例:https://github.com/kubernetes/examples/blob/master/staging/volumes/flexvolume/nfs

flexvolume的本质是相当于就是一个普通的 shell 命令,类似于平时我们在 Linux 下面执行的 ls 命令一样,只是返回的信息是 JSON 格式的数据,并不是我们通常认为的一个常驻内存的进程

因为其本质,决定了flexvolume即不能Dynamic Provisioning(为每个 PVC 自动创建 PV 和对应的 Volume),又不能保存挂载信息等,所以有了CSI这种更完善的存储插件体系

CSI

Kubernetes内置的存储插件和Flexvolume,仅仅是去操作存储卷,而Dynamic Provisioning这样的功能,需要去监控Kubernetes里面存储事件变化,如PVC创建,来做下一步的逻辑,这部分功能原来是Kubernetes存储管理的一部分。

CSI的设计思想就是把这个 Provision 阶段,以及 Kubernetes 里的一部分存储管理功能,从主干代码里剥离出来,做成了几个单独的组件。把插件的职责从“两阶段处理”,扩展成了 Provision、Attach 和 Mount 三个阶段。其中,Provision 等价于“创建磁盘”,Attach 等价 于“挂载磁盘到虚拟机”,Mount 等价于“将该磁盘格式化后,挂载在 Volume 的宿主机目录上”。

                                ┌─────────────────────────────────────────────────┐     
                                │                                                 │     
                                ▼                                                 │     
                     ┌────────────────────┐         ┌───────────────┐        ┌─────────┐
                     │  Driver Registrar  │────────▶│ CSI Identity  │        │kubelete │
                     └────────────────────┘         └───────────────┘        └─────────┘
                                                                                  │     
                                                                                  │     
┌──────┐             ┌────────────────────┐         ┌───────────────┐             │     
│      │      ┌─────▶│External Provisioner│────┬───▶│CSI Controller │             │     
│      │    PVC      └────────────────────┘    │    └───────────────┘             │     
│ API  │      │                                │                                  │     
│Server│──────┤                                │                                  │     
│      │ VolumeAtta                            │                                  │     
│      │   chment    ┌────────────────────┐    │    ┌───────────────┐             │     
└──────┘      └─────▶│ External Attacher  │────┘    │   CSI Node    │◀────────────┘     
                     └────────────────────┘         └───────────────┘                   
                                                            │                           
                                                            │                           
                                                            ▼                           
                                                    ┌───────────────┐                   
                                                    │AWS/NFS/Ceph...│                   
                                                    └───────────────┘                   

CSI插件可以是一个二进制或者容器,提供三个服务:CSI Identity,CSI Controller 和 CSI Node

  • Identity:对外暴露这个插件本身的信息,确保插件的健康状态
  • Controller:实现 Volume 管理流程当中的 Provision 和 Attach 阶段
  • Node:控制 Kubernetes 节点上的 Volume 操作

这套存储插件体系多了三个独立的外部组件(External Components),即: Driver Registrar、External Provisioner 和 External Attacher,对应的正是从 Kubernetes 项 目里面剥离出来的那部分存储管理功能。

  • Driver Registrar:负责将插件注册到 kubelet 里面,实际需要请求 CSI 插件的 Identity 服务来

    获取插件信息

  • External Provisioner:负责 Provision 阶段,监听(Watch)了 APIServer 里的 PVC 对象。当一个 PVC 被创建时,它就会调用 CSI Controller 的 CreateVolume 方法,为你创建对应 PV

  • External Attacher:负责Attach 阶段。它监听了 APIServer 里 VolumeAttachment 对象的变化并调用 CSI 的 ControllerPublish 和 ControllerUnpublish

官方建议了部署方式:见图

CSI Controller + Identity部分以 StatefulSet 或者 Deployment 方式部署,Sidecar加上Provisioner和Attacher

CSI Node + Identity部分以 DaemonSet 方式部署,Sidecar加上Driver Registrar