K8s-存储原理说明

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

前言

K8s存储主要是封装了对存储组件的细节让我们可以通过pvcpv操控就可以对存储进行管理。下面我们开始分析在k8s中是如何实现存储组件处理逻辑的。

容器挂载原理

我们知道容器是以OverlayFS的形式存储在系统中每一个容器都有它独有的目录而容器的存储挂载就是将远端文件目录挂载到容器目录当中。我们可以使用mount查看当前系统上的挂载点从这些信息中我们就可以找到每个容器合并呈现后的目录。
OverlayFS详细讲解请参考
https://zhuanlan.zhihu.com/p/436450556

K8s存储历史

http://www.c4a15wh.cn/index.php/archives/50/
总结一句话就是 一开始是in-tree形式这种形式难以扩容现在envoy也是这种方式苦恼然后是FlexVolume这种模式这种模式与cni机制一致都是通过调用二进制或者脚本文件来完成功能。最后就是现在推荐的方式CSI这种方式会在下文详细讲解。

K8s存储逻辑的处理

存储逻辑大致流程为下面三步

  1. 在远端存储介质上分配出一块空间
  2. 如果是块存储需要进行attach操作文件系统可以忽略此步
  3. mount挂载操作如果是块操作需要先挂载到kubelet全局存储目录当中因为块设备只能挂载一次所以以全局目录作为一个中转站再挂载到pod内部。文件系统直接挂载到pod内部就行。

k8s的存储逻辑可以分为两个部分一个是对pvcpv的处理比如pvc与pv的连接这一部分由controller manager进行管理。另一部分就是pod与存储目录的挂载操作这一部分由kubelet去进行实现。
下面我们列出他们的处理流程

Controller Manager

  1. 监听pvc当pvc被创建后触发下面逻辑。由PersistentVolumeController控制管理
  2. 判断pvc 是否指定了pv如果指定了则获取pv然后进行绑定将pvc的状态修改为Bound
  3. 如果没有指定pv首先会查询所有pv是否有符合绑定的条件符合则进行绑定条件是 访问权限大于或者等于容量大于或者等于。
  4. 如果没有匹配到适合的pv则判断是否指定了StorageClassName如果指定了则根据name获取相应的存储插件后面会讲到 存储插件的注册机制会调用 Provision() 方法创建pv。
  5. 因为历史的缘故之前的in-tree存储插件还保留了下来所以对于一些组件的操作是需要 第 4 步而对于现在的nfs 还是csi来说他们的逻辑是在 自己的控制器中处理的就拿csi举例它通过external-provisioner 控制器监听pvc判断当前pvc中的StorageClassName是否是自己注册的name下面会将到csi的注册方式。如果是则创建pv而controller manager一直在监听pv当pv创建后会触发bind方法对当前pvc建立绑定关系。这里需要注意controller manager 会定时刷新所有的pvcpv 更新其状态也会监听两个资源更新状态。
  6. 等待调度器设置pod的nodename然后ADcontroller manager会定期查询pvc所绑定的pod是否有nodename如果有则开始获取pv所使用的存储组件然后判断是否可以进行attach方法调用的是CanAttach。如果可以attach操作那么就执行attach方法。AD Cotroller与kubelet中的volume manager逻辑相似都可以做Attach/Detach操作但是kube-controller-manager与kubelet中只会有一个组件做Attach/Detach操作通过kubelet启动参数–enable-controller-attach-detach设置。设置为 true 表示启用kube-controller-manager的AD controller来做Attach/Detach操作同时禁用 kubelet 执行 Attach/Detach 操作默认值为 true。controller manager 通过volumes.kubernetes.io/controller-managed-attach-detach 这个注解来判断是否用kubelet ad controller manager

kubelet

  1. volume manager 监听当前节点的pod触发后获取pvc以及pv
  2. 开始调用waitForVolumeAttach 方法如果开启了kubelet adcontroller 则开始进行attach操作。对于csi来说就是创建volumeAttachments资源然后触发 external attacher 组件进行attach操作。判断是csi是否有attach功能是通过volumePluginMgr 获取csiCSIDriver资源的attachRequired属性来判断的。
  3. 运行mountAttachedVolumes 判断当前是否进行了attach操作如果是则等待attach完成。然后挂载到全局目录然后调用SetUp() 挂载到pod中。

存储插件注册

上面我们讲解了存储组件从attach到mount的操作。下面我们将讲解一下 存储组件是如何注册到kubelet。本文重点讲解csi注册的方式。

  1. 通过getPluginsRegistrationDir() 方法获取插件注册目录然后监听里面的sock文件调用RegisterPlugin方法将插件注册进去 具体逻辑在GenerateRegisterPluginFunc 中
  2. 比如csinode driver registrar会在该目录创建一个socker然后监听NodeGetInfo 接口。
  3. kubelet调用首先调用NodeGetInfo 获取当前csi插件的信息。ndrnode driver registrar会返回Driver name以及CSI-Plugin的监听地址。
  4. 然后调用RegisterPlugin将当前信息注册到csi插件队列当中。然后创建CSInode 资源。
  5. 在使用的时候首先根据pv下面指定的插件类型 假设csi去csi map中查找当前csi驱动然后调用nodepushlishVolume 将目录挂载到pod中。

CSI组件

上面是对k8s存储机制进行了分析下面开始对csi机制进行分析。
CSI完美的诠释了什么CRD开发它将in-tree的逻辑进行拆分出来通过out-tree部署方式对资源进行监听触发的形式完成所有的存储功能。
比如attach操作原本是由kubelet或者controller manager来完成的在csi中是由 external Attacher 组件来完成的。
下面我们将介绍一下这几个组件有什么功能以及它的一个原理。

  • external Attacher 提供attach 与dettach操作它会监听volumeattachment资源然后在相应的节点上执行attach方法该资源是由controller manager 的 ad controller manager 进行创建的。
  • external Provisoner 存储制备器它监听pvc资源然后判断pvc是否指定了当前csi组件的sc 然后根据sc设置的 远程存储服务器的地址以及参数创建相应的存储空间然后创建pv
  • external resizer 它会监听pvc当发现pvc.Spec.Resources.Requests.storgage比pvc.Status.Capacity.storgage大时进行底层存储系统的扩容。
  • external snapshotter 拥有独有的资源VolumeSnapshot 根据它来对存储快照进行操作创建删除等等。
  • node driver registrar 通过unix 与kubeletcsi plugin 建立连接主要用来将csi 插件注册到kubelet中上面有说注册流程。
  • csi plugin 它实现了csi介绍里面的所有接口上面的这些组件最终都会调用该插件的方法所以我们只需要实现它就可完成一个存储组件的适配工作。上面的组件都是通过grpc的形式进行连接而地址默认为套接字的形式所以一般将他们部署在同一个pod上。

参考文献

https://blog.csdn.net/weixin_39722563/article/details/111686325
https://blog.csdn.net/kyle18826138721/article/details/118873959 扩容

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: k8s