写点什么

k8s 通过 ceph-csi 接入存储的概要分析

用户头像
良凯尔
关注
发布于: 2021 年 04 月 17 日
k8s通过ceph-csi接入存储的概要分析

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

概述

下面的分析是 k8s 通过 ceph-csi(csi plugin)接入 ceph 存储(csi 相关组件的分析以 rbd 为例进行分析),对 csi 系统结构、所涉及的 k8s 对象与组件进行了简单的介绍,以及对存储进行操作的流程分析,存储相关操作包括了存储创建、存储扩容、存储挂载、解除存储挂载以及存储删除操作。


csi 系统结构

这是一张 k8s csi 的系统架构图,图中所画的组件以及 k8s 对象,接下来会一一进行分析。


csi 简介

CSI 是 Container Storage Interface(容器存储接口)的简写。


CSI 的目的是定义行业标准“容器存储接口”,使存储供应商(SP)能够开发一个符合 CSI 标准的插件并使其可以在多个容器编排(CO)系统中工作。CO 包括 Cloud Foundry, Kubernetes, Mesos 等。


CSI 一般采用容器化部署,减少了环境依赖。

涉及 k8s 对象

1. PersistentVolume

持久存储卷,集群级别资源,代表了存储卷资源,记录了该存储卷资源的相关信息。


回收策略


(1)retain:保留策略,当删除 PVC 的时候,PV 与外部存储资源仍然存在。


(2)delete:删除策略,当与 pv 绑定的 pvc 被删除的时候,会从 k8s 集群中删除 PV 对象,并执行外部存储资源的删除操作。


(3)resycle(已废弃)


pv 状态迁移


available --> bound --> released

2. PersistentVolumeClaim

持久存储卷声明,namespace 级别资源,代表了用户对于存储卷的使用需求声明。


pvc 状态迁移


pending --> bound


示例:


apiVersion: v1kind: PersistentVolumeClaimmetadata:  name: test  namespace: zjl-testspec:  accessModes:  - ReadWriteMany  resources:    requests:      storage: 10Gi  storageClassName: csi-cephfs-sc-1091-10088  volumeMode: Filesystem
复制代码

3. StorageClass

定义了创建 pv 的模板信息,集群级别资源,用于动态创建 pv。


示例:


apiVersion: storage.k8s.io/v1kind: StorageClassmetadata:  name: csi-rbd-scparameters:  clusterID: 0advesae9-0a1c-41db-a619-263dse220161e  csi.storage.k8s.io/fstype: xfs  imageFeatures: layering  imageFormat: "2"  mounter: rbd-nbd  pool: kubernetesprovisioner: rbd.csi.ceph.comreclaimPolicy: DeletevolumeBindingMode: Immediate
复制代码


4. VolumeAttachment

VolumeAttachment 记录了 pv 的相关挂载信息,如挂载到哪个 node 节点,由哪个 volume plugin 来挂载等。


AD Controller 创建一个 VolumeAttachment,而 External-attacher 则通过观察该 VolumeAttachment,根据其状态属性来进行存储的挂载和卸载操作。


示例:


apiVersion: storage.k8s.io/v1kind: VolumeAttachmentmetadata:  name: csi-a98e283998805e19c1dcebc6078a5a973671bd6925348f08d56098a223a6d14cspec:  attacher: cephfs.csi.ceph.com  nodeName: 10.248.34.10  source:    persistentVolumeName: pvc-14ec35d1-0533-44c9-a9e5-1db60b0f6800status:  attached: true
复制代码

5. CSINode

CSINode 记录了 csi plugin 的相关信息(如 nodeId、driverName、拓扑信息等)。


当 Node Driver Registrar 向 kubelet 注册一个 csi plugin 后,会创建(或更新)一个 CSINode 对象,记录 csi plugin 的相关信息。


示例:


apiVersion: storage.k8s.io/v1kind: CSINodemetadata:  name: 10.10.10.10spec:  drivers:  - name: cephfs.csi.ceph.com    nodeID: 10.10.10.10    topologyKeys: null  - name: rbd.csi.ceph.com    nodeID: 10.10.10.10    topologyKeys: null
复制代码

涉及组件与作用

下面先简单介绍下涉及的组件与作用,后面会有单独详细的介绍各个组件的作用。

1. volume plugin

扩展各种存储类型的卷的管理能力,实现第三方存储的各种操作能力与 k8s 存储系统的结合。调用第三方存储的接口或命令,从而提供数据卷的创建/删除、attach/detach、mount/umount 的具体操作实现,可以认为是第三方存储的代理人。前面分析组件中的对于数据卷的创建/删除、attach/detach、mount/umount 操作,全是调用 volume plugin 来完成。


后续对 volume plugin 的详细分析,以通过 ceph-csi 操作 rbd 为例进行分析。


根据源码所在位置,volume plugin 分为 in-tree 与 out-of-tree。


in-tree


在 k8s 源码内部实现,和 k8s 一起发布、管理,更新迭代慢、灵活性差。


out-of-tree


代码独立于 k8s,由存储厂商实现,有 csi、flexvolume 两种实现。


本次的分析为 k8s 通过 ceph-csi 来使用 ceph 存储。本次分析中的 volume plugin 是指 ceph-csi 及其相关组件,包括 ceph-csi、external-provisioner、external-attacher、external-resizer 等。


csi plugin

本次的分析为 k8s 通过 ceph-csi 来使用 ceph 存储,ceph-csi 属于 csi plugin。csi plugin 分为 ControllerServer 与 NodeServer,各负责不同的存储操作。

external plugin

external plugin 包括了 external-provisioner、external-attacher、external-resizer、external-snapshotter 等,external plugin 辅助 csi plugin 组件,共同完成了存储相关操作。external plugin 负责 watch pvc、volumeAttachment 等对象,然后调用 volume plugin 来完成存储的相关操作。如 external-provisioner watch pvc 对象,然后调用 csi plugin 来创建存储,最后创建 pv 对象;external-attacher watch volumeAttachment 对象,然后调用 csi plugin 来做 attach/dettach 操作;external-resizer watch pvc 对象,然后调用 csi plugin 来做存储的扩容操作等。

Node-Driver-Registrar

Node-Driver-Registrar 组件负责实现 csi plugin(NodeServer)的注册,让 kubelet 感知 csi plugin 的存在。

组件部署方式

csi plugin controllerServer 与 external plugin 作为容器,使用 deployment 部署,多副本可实现高可用;而 csi plugin NodeServer 与 Node-Driver-Registrar 作为容器,使用 daemonset 部署,即每个 node 节点都有。


2. kube-controller-manager

PV controller

负责 pv、pvc 的绑定与生命周期管理(如创建/删除底层存储,创建/删除 pv 对象,pv 与 pvc 对象的状态变更)。


创建/删除底层存储、创建/删除 pv 对象的操作,由 PV controller 调用 volume plugin(in-tree)来完成。本次分析的是 k8s 通过 ceph-csi 来使用 ceph 存储,volume plugin 为 ceph-csi,属于 out-tree,所以创建/删除底层存储、创建/删除 pv 对象的操作由 external-provisioner 来完成。

AD controller

AD Cotroller 全称 Attachment/Detachment 控制器,主要负责创建、删除 VolumeAttachment 对象,并调用 volume plugin 来做存储设备的 Attach/Detach 操作(将数据卷挂载到特定 node 节点上/从特定 node 节点上解除挂载),以及更新 node.Status.VolumesAttached 等。


不同的 volume plugin 的 Attach/Detach 操作逻辑有所不同,如通过 ceph-csi(out-tree volume plugin)来使用 ceph 存储,则的 Attach/Detach 操作只是修改 VolumeAttachment 对象的状态,而不会真正的将数据卷挂载到节点/从节点上解除挂载。

3. kubelet

volume manager

主要是管理卷的 Attach/Detach(与 AD controller 作用相同,通过 kubelet 启动参数控制哪个组件来做该操作,后续会详细介绍)、mount/umount 等操作。

本次的分析为 k8s 通过 ceph-csi 来使用 ceph 存储。本次分析中,volume manager 的 Attach/Detach 操作只创建/删除 VolumeAttachment 对象,而不会真正的将数据卷挂载到节点/从节点上解除挂载;csi-attacer 组件也不会做挂载/解除挂载操作,只是更新 VolumeAttachment 对象,真正的节点挂载/解除挂载操作由 kubelet 中 volume manager 调用 rc.operationExecutor.MountVolume/rc.operationExecutor.UnmountDevice 方法时,调用 ceph-csi 来完成。


kubernetes 创建与挂载 volume(in-tree volume plugin)

先来看下 kubernetes 通过 in-tree volume plugin 来创建与挂载 volume 的流程



(1)用户创建 pvc;


(2)PV controller watch 到 pvc 的创建,寻找合适的 pv 与之绑定。


(3)(4)当找不到合适的 pv 时,将调用 volume plugin 来创建 volume,并创建 pv 对象,之后该 pv 对象与 pvc 对象绑定。


(5)用户创建挂载 pvc 的 pod;


(6)kube-scheduler watch 到 pod 的创建,为其寻找合适的 node 调度。


(7)(8)pod 调度完成后,AD controller/volume manager watch 到 pod 声明的 volume 没有进行 attach 操作,将调用 volume plugin 来做 attach 操作。


(9)volume plugin 进行 attach 操作,将 volume 挂载到 pod 所在 node 节点,成为如/dev/vdb 的设备。


(10)(11)attach 操作完成后,volume manager watch 到 pod 声明的 volume 没有进行 mount 操作,将调用 volume plugin 来做 mount 操作。


(12)volume plugin 进行 mount 操作,将 node 节点上的第(9)步得到的/dev/vdb 设备挂载到指定目录。


kubernetes 创建与挂载 volume(out-of-tree volume plugin)

再来看下 kubernetes 通过 out-of-tree volume plugin 来创建与挂载 volume 的流程,以 csi-plugin 为例。



(1)用户创建 pvc;


(2)PV controller watch 到 pvc 的创建,寻找合适的 pv 与之绑定。当寻找不到合适的 pv 时,将更新 pvc 对象,添加 annotation:volume.beta.kubernetes.io/storage-provisioner,让 external-provisioner 组件开始开始创建存储与 pv 对象的操作。


(3)external-provisioner 组件 watch 到 pvc 的创建,判断 annotation:volume.beta.kubernetes.io/storage-provisioner的值,即判断是否是自己来负责做创建操作,是则调用 csi-plugin ControllerServer 来创建存储,并创建 pv 对象。


(4)PV controller watch 到 pvc,寻找合适的 pv(上一步中创建)与之绑定。


(5)用户创建挂载 pvc 的 pod;


(6)kube-scheduler watch 到 pod 的创建,为其寻找合适的 node 调度。


(7)(8)pod 调度完成后,AD controller/volume manager watch 到 pod 声明的 volume 没有进行 attach 操作,将调用 csi-attacher 来做 attach 操作(实际上只是创建 volumeAttachement 对象)。


(9)external-attacher 组件 watch 到 volumeAttachment 对象的新建,调用 csi-plugin 进行 attach 操作(如果 volume plugin 是 ceph-csi,external-attacher 组件 watch 到 volumeAttachment 对象的新建后,只是修改该对象的状态属性,不会做 attach 操作,真正的 attach 操作由 kubelet 中的 volume manager 调用 volume plugin ceph-csi 来完成)。


(10)csi-plugin ControllerServer 进行 attach 操作,将 volume 挂载到 pod 所在 node 节点,成为如/dev/vdb 的设备。


(11)(12)attach 操作完成后,volume manager watch 到 pod 声明的 volume 没有进行 mount 操作,将调用 csi-mounter 来做 mount 操作。


(13)csi-mounter 调用 csi-plugin NodeServer 进行 mount 操作,将 node 节点上的第(10)步得到的/dev/vdb 设备挂载到指定目录。


kubernetes 存储相关操作流程具体分析(out-of-tree volume plugin,以 ceph-csi 为例)

下面来看下 kubernetes 通过 out-of-tree volume plugin 来创建/删除、挂载/解除挂载 volume 的流程。

下面先对每个操作的整体流程进行分析,后面会对涉及的每个组件进行源码分析。

1. 存储创建

流程图



流程分析


(1)用户创建 pvc 对象;


(2)pv controller 监听 pvc 对象,寻找现存的合适的 pv 对象,与 pvc 对象绑定。当找不到现存合适的 pv 对象时,将更新 pvc 对象,添加 annotation:```volume.beta.kubernetes.io/storage-provisioner```,让 external-provisioner 组件开始开始创建存储与 pv 对象的操作;当找到时,将 pvc 与 pv 绑定,结束操作。

(3)external-provisioner 组件监听到 pvc 的新增事件,判断 pvc 的 annotation:```volume.beta.kubernetes.io/storage-provisioner```的值,即判断是否是自己来负责做创建操作,是则调用 ceph-csi 组件进行存储的创建;


(4)ceph-csi 组件调用 ceph 创建底层存储;


(5)底层存储创建完成后,external-provisioner 根据存储信息,拼接 pv 对象,创建 pv 对象;


(6)pv controller 监听 pvc 对象,寻找合适的 pv 对象,与 pvc 对象绑定。

2. 存储扩容

流程图



流程分析


(1)修改 pvc 对象,修改申请存储大小;


(2)修改成功后,external-resizer 监听到该 pvc 的 update 事件,发现 pvc.Spec.Resources.Requests.storgage 比 pvc.Status.Capacity.storgage 大,于是调 csi controller 端扩容,进行底层存储扩容,扩容完毕后更新 pv 对象的.Spec.Capacity.storgage;


(3)kubelet 的 volume manager 在 reconcile()调谐过程中发现 pv.Spec.Capacity.storage 大于 pvc.Status.Capacity.storage,于是调 csi node 端扩容,对 dnode 上存储对应的文件系统扩容,成功后 kubelet 更新 pvc.Status.Capacity.storage。

3. 存储挂载

流程图


kubelet 启动参数--enable-controller-attach-detach,该启动参数设置为 true 表示启用 Attach/Detach controller 进行 Attach/Detach 操作,同时禁用 kubelet 执行 Attach/Detach 操作(默认值为 true)。实际上 Attach/Detach 操作就是创建/删除 VolumeAttachment 对象。


(1)kubelet 启动参数--enable-controller-attach-detach=true,Attach/Detach controller 进行 Attach/Detach 操作



(2)kubelet 启动参数--enable-controller-attach-detach=false,kubelet 端 volume manager 进行 Attach/Detach 操作



流程分析


(1)用户创建一个挂载了 pvc 的 pod;


(2)AD controller 或 volume manager 中的 reconcile()发现有 volume 未执行 attach 操作,于是进行 attach 操作,即创建 VolumeAttachment 对象;


(3)external-attacher 组件 list/watch VolumeAttachement 对象,更新 VolumeAttachment.status.attached=true;


(4)AD controller 更新 node 对象的.Status.VolumesAttached 属性值,将该 volume 记为 attached;


(5)kubelet 中的 volume manager 获取 node.Status.VolumesAttached 属性值,发现 volume 已被标记为 attached;


(6)于是 volume manager 中的 reconcile()调用 ceph-csi 组件的 NodeStageVolume 与 NodePublishVolume 完成挂载。

4. 解除存储挂载

流程图


(1)AD controller



(2)volume manager



流程分析


(1)用户删除声明了 pvc 的 pod;


(2)AD controller 或 volume manager 中的 reconcile()发现有 volume 未执行 dettach 操作,于是进行 dettach 操作,即删除 VolumeAttachment 对象;


(3)AD controller 或 volume manager 等待 VolumeAttachment 对象删除成功;


(4)AD controller 更新新 node 对象的.Status.VolumesAttached 属性值,将标记为 attached 的该 volume 从属性值中去除;


(5)kubelet 中的 volume manager 获取 node.Status.VolumesAttached 属性值,找不到相关的 volume 信息;


(6)于是 volume manager 中的 reconcile()调用 ceph-csi 组件的 NodeUnpublishVolume 与 NodeUnstageVolume 完成解除挂载。

5. 删除存储

流程图



流程分析


(1)用户删除 pvc 对象;


(2)pv controller 发现与 pv 绑定的 pvc 对象被删除,于是更新 pv 的状态为 released;


(3)external-provisioner watch 到 pv 更新事件,并检查 pv 的状态是否为 released,以及回收策略是否为 delete;


(4)接下来 external-provisioner 组件会调用 ceph-csi 的 DeleteVolume 来删除存储;


(5)ceph-csi 组件的 DeleteVolume 方法,调用 ceph 集群命令,删除底层存储;


(6)external-provisioner 组件删除 pv 对象。

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

良凯尔

关注

热爱的力量 2020.01.10 加入

kubernetes开发者

评论

发布
暂无评论
k8s通过ceph-csi接入存储的概要分析