文件系统小册(FusePosixK8s csi)【3 K8s csi】

文件系统小册(Fuse&Posix&K8s csi)【3 K8s csi】

往期文章:

  • 文件系统小册(Fuse&Posix&K8s csi)【1 Fuse】
  • 文件系统小册(Fuse&Posix&K8s csi)【2 Posix标准】

0 核心知识点速递(csi plugin)

  1. CSI(Container Storage Interface):k8s提供接口,各第三方存储厂商实现接口,k8s通过rpc调用接口实现对第三方存储的操控(创建、删除等)。
  2. CSI核心组件:
  • (1) csi plugin:controller server+node server+External plugin
    • controller server:csi插件的控制面组件,负责存储卷生命周期等,不涉及节点上的具体挂载和卸载。
      • 创建删除存储卷(Volume)
      • 创建删除卷快照(Snapshot)
      • 验证卷配置(validateVolumeCapabilites)
      • 扩展卷大小(ControllerExpandVolume)
      • 将卷与Pod绑定(ControllerPublishVolume)
      • 解绑(ControllerUnPublishVolume)
    • node server:csi插件的节点面组件。在k8s节点执行实际的存储操作,这些操作实际影响到pod的运行
      • 准备卷(NodeStageVolume):对卷进行格式化等,将卷挂载到宿主机【远端存储挂宿主机】
      • 卸载卷(NodeUnstageVolume):从宿主机卸载卷
      • 挂载卷(NodePublishVolume):将卷挂载到Pod运行路径,使pod可以访问【宿主机挂pod】
      • 卸载卷(NodeUnPublishVolume):从pod运行路径卸载卷【从pod挂载点卸载卷】
      • 获取节点信息(NodeGetInfo):提供节点信息,如节点ID
      • 获取节点的存储能力(NodeGetCapabilities)和状态(NodeGetVolumeStats)
    • External plugin:调用csi plugin做系列操作,完成对存储的操控
      • external provisioner:监听pvc创建,调用csi plugin创建远程存储,进而创建pv
      • external attacher:监听volumeAttachment(记录了pv的挂载信息,如挂载到哪个node节点,由哪个csi plugin来挂载等),调用csi plugin做Attach/Dettach
      • external resizer:监听pvc,当pvc声明的容量(spec.resources.requests.storage)变化时,做对应的扩容操作。
      • node driver Registrar:实现csi plugin中NodeServer的注册,让kubelet感知csi plugin的存在。
  • (2)node driver registrar:注册csi插件
    • 注册csi插件:将csi插件注册到kubelet上。这样 Kubelet 就能够识别并使用该 CSI 插件来管理存储卷。它通过监听 Kubelet 的插件注册机制,创建必要的插件目录结构和 socket 文件,确保 Kubelet 能够发现并调用 CSI 插件提供的服务。不属于csi plugin的组成部分。
    • 维护插件信息:定期更新节点上的插件信息,包括插件的健康状况、版本等,确保 Kubelet 能够实时了解 CSI 插件的状态
    • 简化部署和管理:通过使用 Node-Driver-Registrar,CSI 插件的部署和管理变得更加简单。开发者或存储供应商只需关注 CSI 插件的核心逻辑,而不必关心如何将其正确注册到每个节点上,降低了集成的复杂度
  1. csi plugin各组件部署方式:
  • csi plugin的controller server与External plugin作为容器,可使用Deployment部署
  • csi plugin的node server与node driver registrar作为容器,使用Daemonset部署(每个节点都有)
  1. 流程:
    ①k8s创建与挂载volume(ceph csi plugin为例)::

    • 用户创建pvc,pv controller监听到pvc创建,寻找合适的pv与之绑定。若无合适pv,则添加annotation:volume.beta.kubernetes.io/storage-provisioner,让external-provisioner创建存储与pv对象
    • external-provisioner watch到pvc创建或更新事件,根据annotation判断是否是自己负责创建操作,如果是则调用csi-plugin ControllerServer创建存储并创建pv对象。
    • pv controller将创建成功pv与pvc绑定。
    • 用户创建挂载pvc的pod
    • kube-scheduler watch到pod的创建,为其寻找合适的node调度。pod调度完成后,AD controller/volume manager监听到pod声明的Volume没有进行Attach操作,调用csi attacher来做attach操作(实际上只是创建volumeAttachement对象)。
    • external attacher监听到VolumeAttachment对象创建,调用csi plugin进行attach操作(如:Volume plugin是ceph csi,external attacher组件watch到VolumeAttachment对象创建后,只修改该对象的状态属性,但真正的attach操作让kubelet中的Volume manager调用Volume plugin,即:ceph csi来完成)
    • csi plugin controller server进行attach操作,将Volume挂载到pod所在节点,成为如/dev/vdb的设备
    • attach完后,Volume manager监听到pod声明的Volume没有进行mount操作,将调用csi mounter来进行mount操作
    • csi mounter调用csi plugin node server进行mount操作,将node节点attach得到的如/dev/vdb设备挂载到指定目录

    ②csi实现存储创建过程(ceph csi plugin为例):

    • 用户建pvc
    • pv controller监听pvc对象,找合适pv,若没有则给pvc对象添加annotation(让external Provisioner知道这个pvc对应的pv由自己来创建)
    • external Provisioner监听到pvc新增,找到对应的annotation:volume.beta.kubernetes.io/storage-provisioner,如果有则自己来调用ceph csi组件创建远程存储
    • ceph底层存储创建完后,external Provisioner根据存储信息,创建对应的pv对象(这里的pv对象使用了提前绑定特性,将pvc信息填入了pv对象的spec.claimRef属性)。
    • pv controller监听pvc对象,将external Provisioner创建出的pv与pvc绑定

    ③csi实现存储扩容(ceph csi plugin为例):

    • 修改pvc对象(修改申请存储大小pvc.spec.resources.requests.storage的值)
    • external resizer监听到pvc的update事件,发现pvc.Spec.Resources.Requests.storgage比pvc.Status.Capacity.storgage大(预期的容量比当前的容量大),于是调ceph-csi组件进行 controller端扩容
    • ceph csi组件调ceph存储,进行底层存储扩容
    • 底层扩容完后,external resizer更新pv对象的.Spec.Capacity.storgage为扩容后的存储大小
    • kubelet的volume manager在reconcile()调谐过程中发现pv.Spec.Capacity.storage大于pvc.Status.Capacity.storage,于是调ceph csi组件进行 node端扩容
    • ceph csi组件对node上存储对应的文件系统扩容
    • 扩容完成后,kubelet更新pvc.Status.Capacity.storage值为扩容后大小

    ④存储挂载mount(ceph csi plugin为例):

    • 用户创建一个挂载了pvc的pod
    • AD controller或Volume manager中的reconcile发现有volume未执行Attach操作,便创建VolumeAttachment对象执行attach操作
    • external-attacher组件list/watch VolumeAttachement对象,更新VolumeAttachment.status.attached=true
    • AD controller更新node对象的.Status.VolumesAttached属性值,将该volume记为attached
    • kubelet中的volume manager获取node.Status.VolumesAttached属性值,发现volume已被标记为attached
    • volume manager中的reconcile()调用ceph-csi组件的NodeStageVolume与NodePublishVolume完成存储的挂载

    ⑤解除存储挂载umount(ceph csi plugin为例):

    • 用户删除了声明pvc的pod
    • AD controller或volume manager中的reconcile()发现有volume未执行dettach操作,于是进行dettach操作,即删除VolumeAttachment对象
    • AD controller或volume manager等待VolumeAttachment对象删除成功
    • AD controller更新node对象的.Status.VolumesAttached属性值,将标记为attached的该volume从属性值中去除
    • kubelet中的volume manager获取node.Status.VolumesAttached属性值,找不到相关的volume信息
    • volume manager中的reconcile()调用ceph-csi组件的NodeUnpublishVolume与NodeUnstageVolume完成存储的解除挂载操作

    ⑥删除存储(ceph csi plugin为例):

    • 用户删除pvc对象
    • pv controller发现pv绑定的pvc对象被删除,更新pv状态为released
    • external-provisioner watch到pv更新事件,并检查pv的状态是否为released,以及回收策略是否为delete
    • 确认了pv对象的状态以及回收策略之后,接下来external-provisioner组件会调用ceph-csi的DeleteVolume来删除存储;
    • ceph-csi组件的DeleteVolume方法,调用ceph集群命令,删除底层存储
    • 删除底层存储后,external-provisioner组件删除pv对象

1 概念

1. CSI是什么:容器存储接口

kubernetes的设计初衷是支持可插拔架构,从而利于扩展kubernetes的功能。在此架构思想下,kubernetes提供了3个特定功能的接口,分别是容器网络接口CNI、容器运行时接口CRI和容器存储接口CSI(Container Storage Interface)。kubernetes通过调用这几个接口,来完成相应的功能。

  • CSI的目的是定义行业标准“容器存储接口”,使存储供应商(SP)能够开发一个符合CSI标准的插件并使其可以在多个容器编排(CO)系统中工作。CO包括Cloud Foundry, Kubernetes, Mesos等。
  • kubernetes将通过CSI接口来跟第三方存储厂商进行通信,来操作存储,从而提供容器存储服务。

2. 为什么要CSI:定义规范,其他存储厂商实现。易于开发和维护

其实在没有CSI之前kubernetes就已经提供了强大的存储卷插件系统,但是这些插件系统实现是kubernetes代码的一部分,需要随kubernetes组件二进制文件一起发布,这样就会存在一些问题。

  1. 如果第三方存储厂商发现有问题需要修复或者优化,即使修复后也不能单独发布,需要与kubernetes一起发布,对于k8s本身而言,不仅要考虑自身的正常迭代发版,还需要考虑到第三方存储厂商的迭代发版,这里就存在双方互相依赖、制约的问题,不利于双方快速迭代;
  2. 另外第三方厂商的代码跟kubernetes代码耦合在一起,还会引起安全性、可靠性问题,还增加了kubernetes代码的复杂度以及后期的维护成本等等。
  • 基于以上问题,kubernetes将存储体系抽象出了外部存储组件接口即CSI,kubernetes通过grpc接口与第三方存储厂商的存储卷插件系统进行通信。(类似Java JDBC,定义一套规则,其他厂商来实现)
  • 这样一来,对于第三方存储厂商来说,既可以单独发布和部署自己的存储插件,进行正常迭代,而又无需接触kubernetes核心代码,降低了开发的复杂度。同时,对于kubernetes来说,这样不仅降低了自身的维护成本,还能为用户提供更多的存储选项。

3. CSI架构:kubernetes通过grpc接口与第三方存储厂商的存储卷插件系统进行通信,来操作存储

在这里插入图片描述

2 涉及到的K8s相关组件

官网:https://kubernetes.io/zh-cn/docs/concepts/storage/persistent-volumes/

1. PV(PersistentVolume):持久化卷,相当于一块盘

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

  • 回收策略
    (1)retain:保留策略,当删除pvc的时候,保留pv与外部存储资源。
    (2)delete:删除策略,当与pv绑定的pvc被删除的时候,会从k8s集群中删除pv对象,并执行外部存储资源的删除操作。
    (3)resycle(已废弃)
  • pv状态迁移:available --> bound --> released

2. PVC(PersistentVolumeClaim):声明,告诉k8s你要多大的"盘"

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

  • pvc状态迁移:pending --> bound
  • accessModes:
    • ReadWriteOnce:卷可以被一个节点以读写方式挂载。 ReadWriteOnce 访问模式仍然可以在同一节点上运行的多个 Pod 访问该卷。 对于单个 Pod 的访问,请参考 ReadWriteOncePod 访问模式。
    • ReadOnlyMany:卷可以被多个节点以只读方式挂载
    • ReadWriteMany:卷可以被多个节点以读写方式挂载
    • ReadWriteOncePod:整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用 ReadWriteOncePod 访问模式

pvc.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: testnamespace: test
spec:accessModes:- ReadWriteMany # 卷可以被多个节点以读写方式挂载resources:requests:storage: 10GistorageClassName: csi-cephfs-sc # sc名称volumeMode: Filesystem

3. SC(StorageClass):定义PV模板,动态创建PV

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

  • 如果我们想要新增PV只有通过yaml方式去一个一个apply yaml手动的话,对于运维成本太过巨大。因此k8s提供了SC(StorageClass)允许我们动态创建pv。sc中定义pv模板,比如回收策略等。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: csi-rbd-sc
parameters:clusterID: ceph01imageFeatures: layeringimageFormat: "2"mounter: rbdpool: kubernetes
provisioner: rbd.csi.ceph.com
reclaimPolicy: Delete
volumeBindingMode: Immediate

4. VolumeAttachment:记录PV挂载信息

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

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

va.yaml

apiVersion: storage.k8s.io/v1
kind: VolumeAttachment
metadata:name: csi-123456
spec:attacher: cephfs.csi.ceph.comnodeName: 192.168.1.10source:persistentVolumeName: pvc-123456
status:attached: true

5. CSINode:记录CSI Plugin信息,nodeId、drivername等

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

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

csiNode.yaml:

apiVersion: storage.k8s.io/v1
kind: CSINode
metadata:name: 192.168.1.10
spec:drivers:- name: cephfs.csi.ceph.comnodeID: 192.168.1.10topologyKeys: null- name: rbd.csi.ceph.comnodeID: 192.168.1.10topologyKeys: null

查看节点的csi node

# 查看csi node详细信息
kubectl get csinodes.storage.k8s.io worker01  -o yaml

在这里插入图片描述

3 各组件作用

CSI架构图:
在这里插入图片描述

1. volume plugin:k8s内部插件、csi plugin、flexvolume等

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

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

in-tree:在k8s源码内部实现,和k8s一起发布、管理,更新迭代慢、灵活性差。
out-of-tree:代码独立于k8s,由存储厂商实现,有csi、flexvolume两种实现。

①CSI Plugin:ControllerServer+NodeServer+(External Plugins)

一个完整的CSI插件通常由Controller Server和Node Server组成,它们各自负责一部分存储操作,共同实现Kubernetes与存储系统的全面集成。此外,还有其他辅助组件,如上述的External Plugins,它们与Controller Server和Node Server配合,提供更高级的功能,如动态卷供应、快照管理和扩缩容等。

csi plugin:分为ControllerServer与NodeServer,各负责不同的存储操作

  • Controller Server:
    功能: Controller Server 是 CSI 插件的控制面组件,它处理与存储卷生命周期管理相关的操作,这些操作通常在集群级别执行,不直接涉及节点上的具体挂载和卸载。这些操作包括:
    • 创建、删除存储卷(Volume)。
    • 创建、删除卷快照(Snapshot)。
    • 验证卷配置(ValidateVolumeCapabilities)。
    • 扩展卷大小(ControllerExpandVolume)。
    • 将卷与Pod绑定(ControllerPublishVolume)、解绑(ControllerUnpublishVolume)。
  • Node Server:
    功能: Node Server 是 CSI 插件的节点面组件,它负责在Kubernetes节点上执行实际的存储操作,这些操作直接影响到Pod的运行。Node Server 的主要任务包括:
    • 准备卷(NodeStageVolume):在节点上准备存储卷,使其可用于Pod。
    • 卸载卷(NodeUnstageVolume):从节点上解除卷的准备状态。
    • 挂载卷(NodePublishVolume):将准备好的卷挂载到Pod的运行路径,使Pod可以访问。
    • 卸载卷(NodeUnpublishVolume):从Pod的运行路径上卸载卷。
    • 获取节点信息(NodeGetInfo):提供关于节点的信息,如节点ID等。
    • 获取节点的存储能力(NodeGetCapabilities)和状态(NodeGetVolumeStats)。

ControllerServer 与NodeServer联系:

  • 协作:Controller Server 和 Node Server 通过Kubernetes的API和CSI接口相互协作。Controller Server 处理集群级别的操作,如创建卷,然后通知Node Server在适当节点上执行实际的挂载和准备操作。Node Server则根据Controller Server的指示来处理节点级别的存储操作。
  • 通信:Controller Server 和 Node Server 之间的通信通常通过Kubernetes API和CSI定义的gRPC接口进行。

②external plugin:external-provisioner、external-attacher、external-resizer等(辅助CSI 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:实现csi plugin(node server)的注册,让kubelet感知csi plugin存储

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

  1. 注册 CSI 插件: Node-Driver-Registrar 负责将 CSI 插件注册到节点的 Kubelet 上,这样 Kubelet 就能够识别并使用该 CSI 插件来管理存储卷。它通过监听 Kubelet 的插件注册机制,创建必要的插件目录结构和 socket 文件,确保 Kubelet 能够发现并调用 CSI 插件提供的服务。
  2. 维护插件信息: Node-Driver-Registrar 会定期更新节点上的插件信息,包括插件的健康状况、版本等,确保 Kubelet 能够实时了解 CSI 插件的状态。
  3. 简化部署和管理: 通过使用 Node-Driver-Registrar,CSI 插件的部署和管理变得更加简单。开发者或存储供应商只需关注 CSI 插件的核心逻辑,而不必关心如何将其正确注册到每个节点上,降低了集成的复杂度。

与 CSI Plugin 的关系:

  • 互补角色:Node-Driver-Registrar 与 CSI 插件是互补的,它不是 CSI 插件的一部分,而是作为一个辅助容器与 CSI 插件一同部署在每个节点上。CSI 插件负责实际的存储操作(如创建、挂载、卸载卷等),而 Node-Driver-Registrar 则负责确保这些插件能够被 Kubelet 正确识别和使用。
  • 协同工作:在实际操作中,Node-Driver-Registrar 通过读取 CSI 插件提供的元数据(如插件名称、版本等),并利用这些信息与 Kubelet 交互,确保 CSI 插件能够无缝集成到 Kubernetes 存储框架中。没有 Node-Driver-Registrar,CSI 插件虽然可以部署,但在节点层面可能无法被 Kubelet 自动发现和使用,从而影响到存储卷的正常生命周期管理。

④组件化部署:Deployment+Daemonset

  • csi plugin controllerServer与external plugin作为容器,使用deployment部署,多副本可实现高可用;
  • 而csi plugin NodeServer与Node-Driver-Registrar(csi plugin的注册,让kubelet感知csi plugin存在)作为容器,使用daemonset部署,即每个node节点都有。

2. kube-controller-manager

①PV controller:创建/删除底层存储,创建/删除pv对象,pv与pvc对象的状态变更【in-tree、out-tree CSI】

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

(1)in-tree:创建/删除底层存储、创建/删除pv对象的操作,由PV controller调用volume plugin(in-tree)来完成。

(2)out-tree CSI:创建/删除底层存储、创建/删除pv对象的操作由external-provisioner与csi plugin共同来完成。

②AD controller:Attachment/Detachment 控制器

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

不同的volume plugin的Attach/Detach操作逻辑有所不同

  • 对于csi plugin(out-tree volume plugin)来说,AD controller的Attach/Detach操作只是修改VolumeAttachment对象的状态,而不会真正的将数据卷挂载到节点/从节点上解除挂载,真正的节点存储挂载/解除挂载操作由kubelet中volume manager调用csi plugin来完成。

3. kubelet

①volume manager

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

  • 对于csi来说,volume manager的Attach/Detach操作只创建/删除VolumeAttachment对象,而不会真正的将数据卷挂载到节点/从节点上解除挂载;
  • csi-attacher组件也不会做挂载/解除挂载操作,只是更新VolumeAttachment对象,真正的节点存储挂载/解除挂载操作由kubelet中volume manager调用调用csi plugin来完成。

②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,csi-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对象(这里的pv对象使用了提前绑定特性,将pvc信息填入了pv对象的spec.claimRef属性)。
  • (4)PV controller将上一步创建的pv与pvc绑定。
  • (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设备挂载到指定目录。

4 k8s CSI存储流程具体分析(csi plugin:ceph-csi)

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

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对象(这里的pv对象使用了提前绑定特性,将pvc信息填入了pv对象的spec.claimRef属性);
  • (6)pv controller监听pvc对象,将第(5)步创建的pv对象,与pvc对象绑定。

2. 存储扩容

在这里插入图片描述

  • (1)修改pvc对象,修改申请存储大小(pvc.spec.resources.requests.storage);
  • (2)修改成功后,external-resizer监听到该pvc的update事件,发现pvc.Spec.Resources.Requests.storgage比pvc.Status.Capacity.storgage大,于是调ceph-csi组件进行 controller端扩容;
  • (3)ceph-csi组件调用ceph存储,进行底层存储扩容;
  • (4)底层存储扩容完成后,external-resizer组件更新pv对象的.Spec.Capacity.storgage的值为扩容后的存储大小;
  • (5)kubelet的volume manager在reconcile()调谐过程中发现pv.Spec.Capacity.storage大于pvc.Status.Capacity.storage,于是调ceph-csi组件进行 node端扩容;
  • (6)ceph-csi组件对node上存储对应的文件系统扩容;
  • (7)扩容完成后,kubelet更新pvc.Status.Capacity.storage的值为扩容后的存储大小。

3. 存储挂载(mount)

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. 解除存储挂载(umount)

流程图:
(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未执行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)确认了pv对象的状态以及回收策略之后,接下来external-provisioner组件会调用ceph-csi的DeleteVolume来删除存储;
  • (5)ceph-csi组件的DeleteVolume方法,调用ceph集群命令,删除底层存储;
  • (6)删除底层存储后,external-provisioner组件删除pv对象。

5 实战(对象挂载到本地文件k8s-csi-s3)

官网地址:

  • https://github.com/yandex-cloud/k8s-csi-s3
  • https://github.com/yandex-cloud/geesefs
  • 基于Go实现的高性能将S3挂载为本地文件系统的工具

5.1 Dockerfile

FROM golang:1.19-alpine as gobuildWORKDIR /build
ADD go.mod go.sum /build/
RUN go mod download -x
ADD cmd /build/cmd
ADD pkg /build/pkg
RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o ./s3driver ./cmd/s3driverFROM alpine:3.17
LABEL maintainers="Vitaliy Filippov <vitalif@yourcmc.ru>"
LABEL description="csi-s3 slim image"RUN apk add --no-cache fuse mailcap rclone
RUN apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/community s3fs-fuseADD https://github.com/yandex-cloud/geesefs/releases/latest/download/geesefs-linux-amd64 /usr/bin/geesefs
RUN chmod 755 /usr/bin/geesefsCOPY --from=gobuild /build/s3driver /s3driver
ENTRYPOINT ["/s3driver"]

5.2 Makefile

# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
.PHONY: test build container push cleanREGISTRY_NAME=cr.yandex/crp9ftr22d26age3hulg
REGISTRY_NAME2=cr.il.nebius.cloud/crll7us9n6i5j3v4n92m
IMAGE_NAME=csi-s3
IMAGE_NAME2=yandex-cloud/csi-s3/csi-s3-driver
VERSION ?= 0.41.0
IMAGE_TAG=$(REGISTRY_NAME)/$(IMAGE_NAME):$(VERSION)
TEST_IMAGE_TAG=$(IMAGE_NAME):testbuild:CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o _output/s3driver ./cmd/s3driver
test:docker build -t $(TEST_IMAGE_TAG) -f test/Dockerfile .docker run --rm --privileged -v $(PWD):/build --device /dev/fuse $(TEST_IMAGE_TAG)
container:docker build -t $(IMAGE_TAG) .
push: containerdocker tag $(IMAGE_TAG) $(REGISTRY_NAME)/$(IMAGE_NAME):latestdocker tag $(IMAGE_TAG) $(REGISTRY_NAME)/$(IMAGE_NAME2):$(VERSION)docker tag $(IMAGE_TAG) $(REGISTRY_NAME)/$(IMAGE_NAME2):latestdocker push $(IMAGE_TAG)docker push $(REGISTRY_NAME)/$(IMAGE_NAME)docker push $(REGISTRY_NAME)/$(IMAGE_NAME2)docker push $(REGISTRY_NAME)/$(IMAGE_NAME2):$(VERSION)
clean:go clean -r -x-rm -rf _output

5.3 helm/values.yml

---
images:# Source: quay.io/k8scsi/csi-node-driver-registrar:v1.2.0registrar: cr.yandex/crp9ftr22d26age3hulg/yandex-cloud/csi-s3/csi-node-driver-registrar:v1.2.0# Source: quay.io/k8scsi/csi-provisioner:v2.1.0provisioner: cr.yandex/crp9ftr22d26age3hulg/yandex-cloud/csi-s3/csi-provisioner:v2.1.0# Main imagecsi: cr.yandex/crp9ftr22d26age3hulg/yandex-cloud/csi-s3/csi-s3-driver:0.41.0storageClass:# Specifies whether the storage class should be createdcreate: true# Namename: csi-s3# Use a single bucket for all dynamically provisioned persistent volumessingleBucket: ""# mounter to use - either geesefs, s3fs or rclone (default geesefs)mounter: geesefs# GeeseFS mount optionsmountOptions: "--memory-limit 1000 --dir-mode 0777 --file-mode 0666"# Volume reclaim policyreclaimPolicy: Delete# Annotations for the storage class# Example:# annotations:#   storageclass.kubernetes.io/is-default-class: "true"annotations: {}secret:# Specifies whether the secret should be createdcreate: true# Name of the secretname: csi-s3-secret# S3 Access KeyaccessKey: ""# S3 Secret KeysecretKey: ""# Endpointendpoint: https://storage.yandexcloud.net# Regionregion: ""tolerations:all: falsenode: []controller: []nodeSelector: {}kubeletPath: /var/lib/kubelet

部署:感受csi部署过程

  • 详细部署流程可参考官网:https://github.com/yandex-cloud/k8s-csi-s3
  • node server:csi插件的节点面组件。在k8s节点执行实际的存储操作,这些操作实际影响到pod的运行。
    • 准备卷(NodeStageVolume):对卷进行格式化等,将卷挂载到宿主机【远端存储挂宿主机】
    • 卸载卷(NodeUnstageVolume):从宿主机卸载卷
    • 挂载卷(NodePublishVolume):将卷挂载到Pod运行路径,使pod可以访问【宿主机挂pod】
    • 卸载卷(NodeUnPublishVolume):从pod运行路径卸载卷【从pod挂载点卸载卷】
    • 获取节点信息(NodeGetInfo):提供节点信息,如节点ID
    • 获取节点的存储能力(NodeGetCapabilities)和状态(NodeGetVolumeStats)

在这里插入图片描述
在这里插入图片描述

通过helm部署成功后会有对应的几个pod:

  1. csi-provisioner:pod里包含两个container,csi-provisioner、csi-s3
    • csi-provisioner:负责处理存储卷的创建、删除请求。它会根据PVC的存储类找到相应的CSI驱动,并调用该驱动的CreateVolume接口在后端存储系统中创建卷。当PVC不再需要时,它也会调用DeleteVolume来清理存储资源。
    • 针对S3兼容存储服务的CSI插件,它与csi-provisioner协同工作,实现与S3存储的交互。它可能包含实现特定于S3的逻辑,比如认证、卷创建和删除的细节处理,以响应csi-provisioner的调用。
  2. csi-s3-xxx():pod里包含两个container,driver-registrar、csi-s3
    • driver-registrar:在每个节点上注册CSI驱动。它负责将CSI插件的节点信息注册到Kubernetes API服务器,使得Kubernetes可以识别并使用该节点上的CSI插件。这包括向Kubernetes注册节点的服务端点,以便于Kubernetes在需要挂载或卸载卷时能找到正确的节点和插件。
    • csi-s3:在每个节点上运行,负责执行实际的卷挂载和卸载操作。当Kubernetes需要在某个节点上挂载或卸载一个卷时,它会通过gRPC调用此容器中的CSI插件逻辑。csi-s3容器会执行NodeStageVolume、NodePublishVolume、NodeUnstageVolume、NodeUnpublishVolume等操作,确保卷正确地挂载到Pod的指定目录下,或在不再需要时正确卸载和清理。对于特定于S3的存储,它还会处理与S3存储系统的直接交互,如认证、数据路径操作等。
      在这里插入图片描述
      在这里插入图片描述

总结

为了解决第三方存储厂商的存储卷插件代码集成到kubernetes代码中所带来的各种问题,kubernetes将存储体系抽象出了外部存储组件接口即CSI。

  • kubernetes通过grpc接口与第三方存储厂商的存储卷插件系统进行通信,来操作存储,从而提供容器存储服务。

这样一来,对于第三方存储厂商来说,既可以单独发布和部署自己的存储插件,进行正常迭代,而又无需接触kubernetes核心代码,降低了开发的复杂度。同时,对于kubernetes来说,这样不仅降低了自身的维护成本,还能为用户提供更多的存储选项。

K8s CSI架构图:
在这里插入图片描述

参考文章:https://www.cnblogs.com/lianngkyle/p/15055552.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/27879.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

liunx常见指令

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 二、安装环境 1.租借服务器 2.下载安装 XShell 3.使用xshll登录服务器 三、Linux基础命令 一、文件和命令 ​编辑1、cd 命令 2、pwd 命令 3、ls 命令 4、cp 命令 …

邮件钓鱼--前置-攻击防范 7 看

目录 1、什么是 SPF&#xff1a; 2、如何判断 SPF&#xff1a; 3.邮件钓鱼防范&#xff1a;7 看 1、什么是 SPF&#xff1a; SPF 记录&#xff1a;原理、语法及配置方法简介 (zhetao.com) SPF记录详解_spf写法-CSDN博客 发件人策略框架&#xff08;Sender Policy Frame…

【多线程】Thread类及其基本用法

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. Java中多线程编程1.1 操作系统线程与Java线程1.2 简单使用多线程1.2.1 初步创建新线程代码1.2.2 理解每个…

springboot与flowable(8):候选人

一、流程绘制和部署 创建流程图 绘制如下流程图 给人事审批添加候选人 给经理审批添加两个候选人 保存导出流程图 部署流程定义 Testvoid contextLoads() {DeploymentBuilder deployment repositoryService.createDeployment();deployment.addClasspathResource("process…

《大道平渊》· 拾肆 —— 不要为不属于你负责的事情负责

《平渊》 拾肆 "客观世界如是观照&#xff0c;控制自己&#xff0c;不要介入因果。" 美国开国总统华盛顿说过, 不要干涉欧洲事务。 可是他的后任都不听, 于是纷纷卷入了无穷的麻烦之中。 不要为不属于你负责的事情负责。 别人的行为和你有什么关系&#xff1f; 就…

Linux-Https协议

文章目录 前言一、Https协议二、常见的加密方式对称加密非对称加密数据摘要&&数据指纹中间人攻击 三、Https的加密历程方案1-只使用对称加密方案2-只使用非对称加密方案3-双方都使用非对称加密方案4-非对称加密对称加密 前言 之前我们学习了Http协议&#xff0c;也试着…

官方文档 搬运 MAXMIND IP定位 mysql导入 简单使用

官方文档地址&#xff1a; 官方文档 文件下载 1. 导入mysql可能报错 Error Code: 1290. The MySQL server is running with the --secure-file-priv option so it cannot execute this statement 查看配置 SHOW GLOBAL VARIABLES LIKE %secure%;secure_file_priv 原来…

laravel版本≥ 8.1

laravel10 php ≥ 8.1 且 ≤ 8.3&#xff1f; 8.1 < php < 8.3PHP版本要求在 8.1 到 8.3 之间&#xff0c;包括这两个版本。具体来说&#xff1a;"≥ 8.1" 表示 PHP 的版本至少是 8.1&#xff0c;也就是说 8.1 及以上的版本都可以。 "≤ 8.3" 表示 P…

计算机组成原理学习 Part 1

计算机系统 组成 计算机系统 { 硬件 计算机的实体&#xff0c;如主机、外设等 软件 由具有各类特殊功能的信息&#xff08;程序&#xff09;组成 计算机系统 \begin{cases} 硬件 &\text 计算机的实体&#xff0c;如主机、外设等\\ 软件 &\text 由具有各类特殊功能的信…

【报错】无法找到模块“element-plus/es/locale/index.mjs”的声明文件。

报错&#xff1a; 无法找到模块“element-plus/es/locale/index.mjs”的声明文件。“E:/codeAll/work/test1/test2/HealinLikeMe-ui/node_modules/.pnpm/element-plus2.7.3_vue3.4.27_typescript5.4.5_/node_modules/element-plus/es/locale/index.mjs”隐式拥有 "any&quo…

Linux笔记--vi编辑器

vi编辑器 基本操作 对于vi编辑器有这几种模式 移动 当编辑一个过大的文件时通过方向键移动光标过慢所以可以使用快捷键进行移动 编辑 dw指令只能在单词第一个字母处使用 D指令删除的是当前行 查找替换 pattern指代想要搜索的内容

056、PyCharm 快速代码重构的方法

在实际的编程过程中&#xff0c;如果有一段代码需要在多个地方重复使用&#xff0c;我们应该将这段代码封装成一个函数。这样可以提高代码的可重用性和可维护性。 在PyCharm编辑器里&#xff0c;可以使用以下操作对代码块进行快速的重构。 &#xff08;1&#xff09;、选中一…

【Photoshop】PS修改文字内容

Photoshop(PS)修改图片上文字内容&#xff0c;网上教材不少&#xff0c;本人整理实践过的方法&#xff0c;分享给各位。本人实践方法&#xff1a; 内容识别填充&#xff1a;适用于背景色复杂的图片内容修补工具&#xff1a;适用于背景色为纯色的图片 方式一&#xff1a;内容识…

java入门-文件与IO流

File类 提供一些方法(api)来操纵文件和获取文件的信息 File常用API 属性 获取系统分隔符 不同操作系统的分隔符 windows的目录分割符号是用向右的斜线&#xff0c;java中\ 表示转义字符&#xff0c;所以向右的斜线需要写两个 \; linux目录分割符号是向左的斜线: / private st…

Cocos2d-x 4.0 工程首次建立与编译(Mac m1)

Mac m1芯片下将cocos2d-x升级至4.0版本后&#xff0c;官方剔除了不同平台的工程以及变更了编译方式&#xff0c;直接使用cmake构建&#xff0c;需要做一些前置的准备工作。 环境准备&#xff1a; 项 版本 备注 MacOS10.3 or laterpython2.7.16(建议>2.7.10)cmake3.29.3Do…

自动驾驶场景下TCP协议参数优化调整案例分享

RTT 往返时间&#xff0c;从tcp协议栈决定发包&#xff0c;到收到回包的时间。 包含本地驱动&#xff0c;网卡硬件&#xff0c;网线&#xff0c;交换机&#xff0c;收包方处理的耗时。需注意如果开了delayed ack&#xff0c;协议栈未做特殊处理&#xff08;默认没做&#xff…

探索交互的本质:从指令到界面的演进与Linux基础指令的深入剖析

目录 1.指令 vs 界面//选读 1.1交互的需求 满足需求的第一阶段-指令 满足需求的第二阶段-界面 1.2 指令 和 界面交互 区别 2.操作系统介绍 2.1 举例说明 驱动软件层 2.2 为什么要有操作系统&#xff1f; 0x03 为什么要进行指令操作&#xff1f; 3.Linux基本指令 l…

模型量化 剪枝bevfusion

量化 剪枝 shared mem 只在block内共享&#xff0c;device glob mem能够所有线程共享

从多线程设计模式到对 CompletableFuture 的应用

大家好&#xff0c;我是 方圆。最近在开发 延保服务 频道页时&#xff0c;为了提高查询效率&#xff0c;使用到了多线程技术。为了对多线程方案设计有更加充分的了解&#xff0c;在业余时间读完了《图解 Java 多线程设计模式》这本书&#xff0c;觉得收获良多。本篇文章将介绍其…

重塑IT审计的未来:数智化审计赋能平台的创新与实践

重塑IT审计的未来&#xff1a;数智化审计赋能平台的创新与实践 一、当前企业开展IT审计面临的挑战 随着信息技术的快速发展、企业数字化转型的持续深入&#xff0c;以及网络安全合规要求的不断增强&#xff0c;企业开展新型IT审计重要性越来越突出&#xff0c;但实施难度却越来…