• kubelet存储插件初入


    前言

    In-tree与Out-tree

    最初的存储插件都需要集成到k8s内部去使用,也就是编译并随核心 kubernetes 二进制文件一起提供。这意味着,如果他们希望添加对新存储系统的支持,则需要存储提供商将其签入核心 k8s 代码库。
    为了对其进行解耦,所以采用Out-tree模式开发了Flexvolume

    Flexvolume

    基于插件的解决方案 flex-volume 试图通过为外部插件公开基于 exec 的 API 来解决这个问题。尽管它也尝试处理与 k8s 二进制分离的类似概念,但这种方法存在几个主要问题。Flexvolume 是在 host 空间一个二进制文件,执行 Flexvolum 时相当于执行了本地的一个 shell 命令,这使得我们在安装 Flexvolume 的时候需要同时安装某些依赖,而这些依赖可能会对客户的应用产生一些影响。因此在安全性上、环境依赖上,就会有一个不好的影响。同时对于丰富插件功能这一点,我们在 Kubernetes 生态中实现 operator 的时候,经常会通过RBAC 这种方式去调用 Kubernetes 的一些接口来实现某些功能,而这些功能必须要在容器内部实现,因此像 Flexvolume 这种环境,由于它是 host 空间中的二进制程序,就没法实现这些功能。
    CSI 这种容器化部署的方式,可以通过 RBAC 的方式来实现这些功能。

    CSI

    (Container Storage Interface), 旨在能为容器编排引擎和存储系统间建立一套标准的存储调用接口,通过该接口能为容器编排引擎提供存储服务。
    CSI 采用的 grpc 调用,grpc 调用的一个优势就是可以将 grpc 服务运行在 socket 上,这样服务端就可以运行在 socket 端点的任何地方,换句话说就是可以被隔离单独运行,这样就可以实现扩展,然后通过标准 rpc 接口,完成本地原生模式的控制。CSI 提供了一套标准的接口集成在 k8s 的源码(kube-controller-manager,kubelet)中,第三方存储插件只需要实现这些接口并注册就可以调用对应的函数进行 pv 和 pvc 的自动创建,提供了可扩展的机会。

    k8s容器卷创建流程

    容器卷的创建有两种情况,一种是静态pv的创建,一种是动态pv的创建

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: pv001
      labels:
        name: pv001
    spec:
      nfs:
        path: /data/volumes/v1
        server: nfs
      accessModes: ["ReadWriteMany", "ReadWriteOnce"]
      capacity:
        storage: 2Gi
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: mypvc
    spec:
      accessModes: ["ReadWriteMany"]
      volumeName: pv001
      resources:
        requests:
          storage: 1Gi
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: pv-pvc
    spec:
      containers:
      - name: myapp
        image: nginx
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
      - name: html
        persistentVolumeClaim:
          claimName: mypvc
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    静态pv创建

    1. 创建pv,pvc资源后会缓存到PVControllerManager中,PVControllerManager首选判断pvc指定了pv,会获取到pv,然后将其进行绑定,然后更新状态。
    2. 创建pod,会先触发调度器,调度器选好node后,kubelet的pleg组件通过监听select,nodename = 当前节点的名称,获取到pod。
    3. kubelet会处理pod的容器卷,根据使用的存储插件的类型进行Attach操作(这里有些插件是不会指定Attach 比如hostpath)。Attach操作主要是将远程文件系统中的pv目录挂载到本地的全局目录当中。
    4. 既然已经挂载到了全局目录中,下一步SetUp就是将全局目录挂载到pod目录指定目录中
    5. 总结就是,先创建,再拉取(从远端挂载到本地),然后再挂载(从本地的全局目录挂载到pod目录中)

    动态创建

    1. 创建pvc资源后会缓存到PVControllerManager中,PVControllerManager首选判断pvc没有指定pv,那么会去volumeManager中查找有没有符合条件(主要通过AccessModes,容量不是精确匹配)的pv与其进行绑定,如果没有则查看有没有指定StorageClass,指定了StorageClass那么通过StorageClassName获取插件,然后进行Provisioner创建相对应的pv以及在文件系统中创建相应的pv目录。这里存在历史代码残留问题,对于能够Provisioner的插件只有完全集成到k8s中的插件,而至于csi则不再其中。也就是说在PVControllerManager调用Provisioner时由于我们指定了csi插件那么会报插件没找到错误。对于csi的处理下面CSI架构中会讲到。
    2. 既然创建完成pv(也在文件系统中创建了相应的目录),下面的流程与上面基本一致。

    CSI架构

    基本上的容器卷的创建逻辑已经清晰,下面我们看看k8s是如何对存储插件从in -> out的!
    ![image.png](https://img-blog.csdnimg.cn/img_convert/9c17021ccd268bac0196072736e5b3b9.png#clientId=u3f1b6d4d-bb2d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=468&id=u504b92e0&margin=[object Object]&name=image.png&originHeight=585&originWidth=1086&originalType=binary&ratio=1&rotation=0&showTitle=false&size=296304&status=done&style=none&taskId=u7a4a63b8-c9b1-4d0f-9787-00007294b17&title=&width=868.8)
    CSI有以下几个组件

    • CSI Plugin(包括Controller,nodeserver,identity server)
      • controller主要用于管理文件系统中相对应的pv目录,比如创建一个pv则会创建一个相对目录,删除pv的时候也会删除相应的目录。
      • nodeserver 主要用于将全局容器卷挂载到pod当中
      • identity server提供了健康探测,Driver身份信息。
    • External Provsioner 主要用于监控pvc,如果有创建则会调用controller里的createvolume()方法。
    • External Attacher 主要用于将节点上的全局目录 与文件目录进行绑定(挂载)
    • External Resizer 扩容
    • External Snapshotter 快照管理

    这里面的组件有些不是必须的,k8s因为兼容性以及历史遗留的问题,对于一些组件已经实现了相应的逻辑,比如External Attacher,所以即使我们不部署External Attacher也可以实现
    csi核心组件有三个

    • controller 它是一个deplyoment主要对系统执行createvolume 操作。也就是动态创建pv以及管理这个pv的操作。
    • External Attacher 它是一个deplyoment 一般与Controller存在一个pod中,它的作用是由Controller在远端文件系统创建的pv目录挂载到指定的节点的全局目录上。(kubelet也实现了这种方式,优先级是External Attacher )
    • nodeserver 它是一个daemonsets 主要将全局目录挂载到pod中。

    让我们看一下它的接口规范
    ![image.png](https://img-blog.csdnimg.cn/img_convert/cf8c845c7b489f79ab926be8eabff0f1.png#clientId=u8df7a34c-e292-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=489&id=ubbdec7ca&margin=[object Object]&name=image.png&originHeight=611&originWidth=1097&originalType=binary&ratio=1&rotation=0&showTitle=false&size=456364&status=done&style=none&taskId=u663382ac-2101-4a4c-9f70-7ef82de3382&title=&width=877.6)
    与csi对应的有三个资源,这三个资源都有自己的功能
    ![image.png](https://img-blog.csdnimg.cn/img_convert/2b5ddcc66ffa07ca4dd0061e96c00553.png#clientId=u72ebae72-a037-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=374&id=u6105c6d1&margin=[object Object]&name=image.png&originHeight=467&originWidth=1093&originalType=binary&ratio=1&rotation=0&showTitle=false&size=548283&status=done&style=none&taskId=u323011ee-68ac-4397-8c34-b2c8fb920fa&title=&width=874.4)

    参考文献

    https://blog.csdn.net/qq_34556414/article/details/120004267
    https://blog.csdn.net/chenhongloves/article/details/124670842

  • 相关阅读:
    一文轻松掌握深度学习框架中的einsum
    算法----组合总和(Kotlin)-面试真题
    腾讯云Java工程师一面 + 被捞一面 + 二面面经(附答案)
    评测回顾 | 天空卫士以人为本的数据防泄露系统
    netty系列之:在netty中使用native传输协议
    【入门-09】队列SPI(QSPI)
    基于Python医学院校二手书管理毕业设计-附源码201704
    Java开发二面被疯狂问JVM相关,被整懵了!!
    jQuery学习:内置动画 淡出/淡入 展开/收缩 显示/隐藏
    自研ORM 子查询&嵌套查询
  • 原文地址:https://blog.csdn.net/a1023934860/article/details/128150856