写点什么

ceph-csi 源码分析(1)- 组件介绍与部署 yaml 分析

用户头像
良凯尔
关注
发布于: 2021 年 04 月 24 日
ceph-csi源码分析(1)-组件介绍与部署yaml分析

kubernetes ceph-csi 分析 - 目录导航https://xie.infoq.cn/article/4b1d3e32f124307a49cd9c1e3

ceph-csi 组件源码分析(1)-组件介绍与部署 yaml 分析

基于 tag v3.0.0


https://github.com/ceph/ceph-csi/releases/tag/v3.0.0

概述

ceph-csi 扩展各种存储类型的卷的管理能力,实现第三方存储 ceph 的各种操作能力与 k8s 存储系统的结合。调用第三方存储 ceph 的接口或命令,从而提供 ceph 数据卷的创建/删除、挂载/解除挂载的具体操作实现。前面分析组件中的对于数据卷的创建/删除、挂载/解除挂载操作,全是调用 ceph-csi,然后由 ceph-csi 调用 ceph 提供的命令或接口来完成最终的操作。


ceph-csi 组件的源码分析分为五部分:(1)组件介绍与部署 yaml 分析;


(2)组件启动参数分析;


(3)rbd driver 分析;


(4)cephfs driver 分析;


(5)liveness driver 分析。


本节先进行组件介绍与部署 yaml 分析。

ceph-csi 组件-作用介绍

(1)create pvc 时,external-provisioner 组件监听到 pvc 创建事件后,负责拼接请求,然后调用 ceph-csi 的 CreateVolume 方法来创建存储;


(2)delete pvc 时,pv 对象状态由 bound 变为 release,external-provisioner 监听到 pv 更新事件后,负责拼接请求,调用 ceph-csi 的 DeleteVolume 方法来删除存储。


(3)create pod cliam pvc 时,kubelet 会调用 ceph-csi 组件将创建好的存储从 ceph 集群挂载到 pod 所在的 node 上,然后再挂载到 pod 相应的目录上;


(4)delete pod cliam pvc 时,kubelet 会调用 ceph-csi 组件相应方法,解除存储在 pod 目录上的挂载,再解除存储在 node 上的挂载。

ceph-csi 组件-服务组成

ceph-csi 含有 rbdType、cephfsType、livenessType 三大类型服务,可以通过启动参数指定一种服务来进行启动。


而 rbdType、cephfsType 类型的服务可以继续细分,包括了 NodeServer、ControllerServer 与 IdentityServer 三种具体的服务,其中 NodeServer 与 ControllerServer 只能选其一进行启动,IdentityServer 会伴随着 NodeServer 或 ControllerServer 的启动而启动。



后面会详细分析每一种服务中的方法。


rbdType

该类型服务包含了 rbd 的相关操作。

cephfsType

该类型服务包含了 cephfs 的相关操作。

livenessType

该类型服务主要是定时向 csi endpoint 探测 csi 组件的存活(向指定的 socket 地址发送 probe 请求),然后统计到 prometheus 指标中。

三种具体服务

NodeServer


部署在 k8s 中的每个 node 上,主要负责 cephfs、rbd 在 node 节点上相关的操作,如将存储挂载到 node 上,解除 node 上存储挂载等操作。


ControllerServer


主要负责创建、删除 cephfs/rbd 存储等操作。


IdentityServer


主要是返回自身服务的相关信息,如返回服务身份信息(名称与版本等信息)、返回服务具备的能力、暴露存活探测接口(用于给别的组件/服务探测该服务是否存活)等。

ceph-csi 组件源码分析

该组件的源码分析将按照以下顺序进行:


(1)ceph-csi 及相关组件部署 yaml 分析


(2)main 函数分析


(3)rbdType/cephfsType/livenessType


(4)NodeServer/ControllerServer/IdentityServer


本文先进行(1)ceph-csi 及相关组件部署 yaml 分析与(2)main 函数的分析。

1.ceph-csi 及相关组件部署 yaml 分析

下面对部署 yaml 的分析,以 rbd 为例进行分析,cephfs 与 rbd 类似。


部署 yaml 请参考:


https://github.com/ceph/ceph-csi/blob/devel/deploy/rbd/kubernetes/csi-rbdplugin-provisioner.yaml


https://github.com/ceph/ceph-csi/blob/devel/deploy/rbd/kubernetes/csi-rbdplugin.yaml


其中csi-rbdplugin-provisioner.yaml包含了名称为csi-rbdplugin-provisioner的 deployment,csi-rbdplugin.yaml包含了名称为csi-rbdplugin的 daemonset。


deployment:csi-rbdplugin-provisioner


包含了csi-provisionercsi-snapshottercsi-attachercsi-resizercsi-rbdpluginliveness-prometheus 5 个容器,作用分别如下:


(1)csi-provisioner:实际上是external-provisioner组件,前面已经做过详细介绍,这里再来简单回顾一下。create pvc 时,csi-provisioner参与存储资源与 pv 对象的创建。csi-provisioner组件监听到 pvc 创建事件后,负责拼接请求,调用ceph-csi组件(即 csi-rbdplugin 容器)的CreateVolume方法来创建存储,创建存储成功后,创建 pv 对象;delete pvc 时,csi-provisioner参与存储资源与 pv 对象的删除。当 pvc 被删除时,pv controller 会将其绑定的 pv 对象状态由 bound 更新为 release,csi-provisioner监听到 pv 更新事件后,调用ceph-csi组件(即 csi-rbdplugin 容器)的DeleteVolume方法来删除存储,并删除 pv 对象。


(2)csi-snapshotter:实际上是external-snapshotter组件,负责处理存储快照相关的操作,后面再做详细介绍。


(3)csi-attacher:实际上是external-attacher组件,只负责操作 VolumeAttachment 对象,实际上并没有操作存储,后面再做详细介绍。


(4)csi-resizer:实际上是external-resizer组件,负责处理存储扩容相关的操作,后面再做详细介绍。


(5)csi-rbdplugin:实际上是ceph-csi组件,rbdType-ControllerServer/IdentityServer 类型的服务。create pvc 时,external-provisioner组件(即 csi-provisioner 容器)监听到 pvc 创建事件后,负责拼接请求,然后调用csi-rbdplugin容器的CreateVolume方法来创建存储;delete pvc 时,pv 对象状态由 bound 变为 release,external-provisioner组件(即 csi-provisioner 容器)监听到 pv 更新事件后,负责拼接请求,调用csi-rbdplugin容器的DeleteVolume方法来删除存储。


(6)liveness-prometheus:实际上是ceph-csi组件,livenessType 类型的服务。负责探测并上报 csi-rbdplugin 服务的存活情况。


daemonset:csi-rbdplugin


包含了 driver-registrar、csi-rbdplugin、liveness-prometheus 3 个容器,作用分别如下:


(1)driver-registrar:向 kubelet 传入csi-rbdplugin容器提供服务的 socket 地址、版本信息和驱动名称(如 rbd.csi.ceph.com)等,将csi-rbdplugin容器服务注册给 kubelet,后面再做详细介绍。


(2)csi-rbdplugin:实际上是ceph-csi组件,rbdType-NoderServer/IdentityServer 类型的服务。create pod cliam pvc 时,kubelet 会调用csi-rbdplugin容器将创建好的存储从 ceph 集群挂载到 pod 所在的 node 上,然后再挂载到 pod 相应的目录上;delete pod cliam pvc 时,kubelet 会调用csi-rbdplugin容器的相应方法,解除存储在 pod 目录上的挂载,再解除存储在 node 上的挂载。


(3)liveness-prometheus:实际上是ceph-csi组件,livenessType 类型的服务。负责探测并上报 csi-rbdplugin 服务的存活情况。

2.main 函数的分析

主要逻辑:


(1)判断--version 参数是否为 true,是则输出版本信息并退出;


(2)校验 driver type 是否指定;


(3)获取 driver 名称并校验;


(4)PidLimit 相关设置;


(5)当 driver type 为 liveness 或者开启 Metrics 时,设置 pod ip 并校验 Metrics url;


(6)根据不同的 driver type(rbdType/cephfsType/livenessType)调用不同类型的服务的 run 方法,来启动不同类型的服务。


func main() {    // --version参数输出  if conf.Version {    fmt.Println("Cephcsi Version:", util.DriverVersion)    fmt.Println("Git Commit:", util.GitCommit)    fmt.Println("Go Version:", runtime.Version())    fmt.Println("Compiler:", runtime.Compiler)    fmt.Printf("Platform: %s/%s\n", runtime.GOOS, runtime.GOARCH)    if kv, err := util.GetKernelVersion(); err == nil {      fmt.Println("Kernel:", kv)    }    os.Exit(0)  }  util.DefaultLog("Driver version: %s and Git version: %s", util.DriverVersion, util.GitCommit)        // 校验driver type是否指定  if conf.Vtype == "" {    klog.Fatalln("driver type not specified")  }        // 获取driver名称并校验  dname := getDriverName()  err := util.ValidateDriverName(dname)  if err != nil {    klog.Fatalln(err) // calls exit  }        // PidLimit相关设置  // the driver may need a higher PID limit for handling all concurrent requests  if conf.PidLimit != 0 {    currentLimit, pidErr := util.GetPIDLimit()    if pidErr != nil {      klog.Errorf("Failed to get the PID limit, can not reconfigure: %v", pidErr)    } else {      util.DefaultLog("Initial PID limit is set to %d", currentLimit)      err = util.SetPIDLimit(conf.PidLimit)      if err != nil {        klog.Errorf("Failed to set new PID limit to %d: %v", conf.PidLimit, err)      } else {        s := ""        if conf.PidLimit == -1 {          s = " (max)"        }        util.DefaultLog("Reconfigured PID limit to %d%s", conf.PidLimit, s)      }    }  }        // 当driver type为liveness或者开启Metrics时,设置pod ip并校验Metrics url  if conf.EnableGRPCMetrics || conf.Vtype == livenessType {    // validate metrics endpoint    conf.MetricsIP = os.Getenv("POD_IP")
if conf.MetricsIP == "" { klog.Warning("missing POD_IP env var defaulting to 0.0.0.0") conf.MetricsIP = "0.0.0.0" } err = util.ValidateURL(&conf) if err != nil { klog.Fatalln(err) } } // 根据不同的driver type调用不同的服务的run方法,来启动不同的服务 util.DefaultLog("Starting driver type: %v with name: %v", conf.Vtype, dname) switch conf.Vtype { case rbdType: validateCloneDepthFlag(&conf) validateMaxSnaphostFlag(&conf) driver := rbd.NewDriver() driver.Run(&conf)
case cephfsType: driver := cephfs.NewDriver() driver.Run(&conf)
case livenessType: liveness.Run(&conf)
default: klog.Fatalln("invalid volume type", conf.Vtype) // calls exit }
os.Exit(0)}
复制代码


getDriverName


当启动参数没有指定 driver 名称时,将根据 driver type 来获取默认的 driver 名称


func getDriverName() string {  // was explicitly passed a driver name  if conf.DriverName != "" {    return conf.DriverName  }  // select driver name based on volume type  switch conf.Vtype {  case rbdType:    return rbdDefaultName  case cephfsType:    return cephfsDefaultName  case livenessType:    return livenessDefaultName  default:    return ""  }}
复制代码


发布于: 2021 年 04 月 24 日阅读数: 28
用户头像

良凯尔

关注

热爱的力量 2020.01.10 加入

kubernetes开发者

评论

发布
暂无评论
ceph-csi源码分析(1)-组件介绍与部署yaml分析