《深入剖析kubernetes》学习笔记(4)——容器持久化存储

28. PV、PVC、StorageClass

  • 基本概念

    • PVC是存储需求的接口化描述,比如持久化存储的大小、读写权限等
    • PV是实际部署的持久化存储数据卷的实现描述,比如数据卷的类型、挂载目录、远程服务器地址等
    • PVC和PV的设计思想是面向对象的接口和实现。
  • PV和PVC绑定的条件

    • PV的spec字段中的存储描述(存储类型、容量storage等)满足PVC的要求
    • PV和PVC的storageCalssName字段必须一致
  • “红娘”控制器PersistentVolumeController:

    • 目的:在Pod启动前完成PVC和PV的绑定;避免POD启动时,PVC还没有匹配到PV,导致启动报错。
    • 工作机制:不断检查每一个PVC,看它是不是已经处于绑定(Bound)状态。如果不是,遍历所有可用的PV,尝试与该PVC绑定。所谓绑定,就是将PV的名字,填写到PVC的spec.volumeName字段上。
  • PV如何与持久化硬盘绑定?

    • 持久化,意味着挂载目录里的内容不会因容器的删除而删除;也不与具体宿主机绑定,因为容器可能重启在另一台宿主机上
    • 因此,持久化 Volume 的实现,往往依赖于一个远程存储服务
  • “两阶段处理”实现宿主机目录的持久化

    • 第一阶段:Attach: 为虚拟机挂载远程磁盘
      • kubernetes提供的参数是nodeName,宿主机的名字
      • AttachDetachController负责维护该操作,作用是检查每一个Pod对应的PV,与该Pod所在宿主机之间的挂载情况。决定是否对该PV进行Attach或者Dettach操作。
      • AttachDetachController运行在Master节点上,是kube-controller-manager的一部分
      • 只需要调用公有云或者具体存储项目的 API,并不需要在具体的宿主机上执行操作
    • 第二阶段:Mount: 磁盘格式化并挂载到宿主机具体的挂载点上
      • kubernetes提供的参数是dir,宿主机的目录
      • 由VolumeManagerReconciler负责维护,是kubelet的一部分,是独立于kubelet主循环的一个goroutine,避免主控制循环被block
      • 该操作必须发生在具体的宿主机上
  • 关于StorageClass

    • 主要:集群中PVC规模可能十分巨大,完全由人工创建、更新对应的PV不现实。因此,k8s提供了一套自动创建PV的机制——Dynamic Provisioning,该机制核心依赖StorageClass对象(就是创建PV的模板
    • 使用StorageClass时需要定义如下两部分信息:
      • PV属性,如存储类型,容量大小等
      • 创建PV所需的存储系统插件(Provisioner),如Ceph等
    • 根据上述信息,K8s根据用户的PVC,找到对应Storageclass,根据该Storageclass创建所需PV。
    • 补充:StorageClass也并不是专门为了PV的动态配置而设计,在PV静态配置(Static Provisioning)时,PVC和PV的storageClassName也要一致才行。
  • PVC、PV、StorageClass工作的大致流程【个人理解】

    • 1> 用户定义一个PVC
    • 2> 若无则根据PVC找到StorageClass
    • 3> 根据StorageClass创建PV,并完成PV和PVC绑定
    • 4> 进行Attach和mount操作与宿主机目录绑定,实现某个宿主机目录的“持久化”,
    • 5> 通过CRI将挂载操作的参数传递给容器,使容器挂载“持久化”了的宿主机目录

29. PV、PVC机制是否过度设计?以本地持久化卷为例

  • 作为面向开源社区的产品,其使用需要具有更多的“可扩展性”,PV/PVC机制的设计就是为了能够支持各种第三方存储系统,并尽可能地对用户屏蔽这些系统间的差异。
  • 本地持久化卷——Local Persistent Volume,两个注意点:
    • (1)不能用宿主机目录作为PV使用,因为有可能写满磁盘造成宕机,因此本地存储卷应是一块额外挂载在宿主机上的磁盘/设备
    • (2)调度(调度是指Pod和宿主机的绑定)时要考虑PV的分布,因此使用本地存储卷之前,应在集群中提前配置好所需磁盘/设备
  • 为什么使用Local PV时,要在调度时考虑PV的分布
    • 在常规PV中,kubernetes先完成Pod的调度,再经过“两阶段处理”来持久化宿主机的某个目录,再完成容器挂载这个持久化了的目录
    • 但是Local PV在不同节点上的挂载情况可能完全不同,有的节点甚至没有对应的PV
    • 因此,调度器需要提前知道Local PV和磁盘的关联关系
  • PV和PVC的延迟绑定
    • 本地持久化卷使用的StorageClass定义中,需指定volumeBindingMode为WaitForFirstConsumer,即采用“延迟绑定”的方法完成PV和PVC的绑定。
    • 一般的动态绑定中,往往在Pod被调度到具体宿主机上之前,其所用的PVC已经绑定到了某个具体PV上,但使用本地持久化卷时,Pod的调度必须考虑PV的分布故PVC和PV的绑定应当在Pod出现在调度器上时,由调度器综合考虑所有的调度规则(包括PV的节点位置),决定PV和PVC的绑定
    • 也就是避免Pod调度时发现,其对应PVC已经绑定到了一个Local PV,而该Local PV位于一个不能运行该Pod的Node上,从而引起调度失败

30. 自定义存储插件——FlexVolume与CSI

  • FlexVolume和CSI都是编写自定义存储插件的方法
  • CSI插件示意图:

img

  • **External Components **组件也是外部组件,但是由K8S社区负责开发维护,分为三个部分:
    • Driver Registrar:请求CSI的Identity服务,将插件信息注册到kubelet中
    • External Provisioner:负责Provision阶段,监听PVC对象,每当有PVC被创建,则调用CSI Controller的CreateVolume方法,以创建对应的Volume
    • External Attacher:负责Attach阶段,监听VolumeAttachment变化,一旦产生该对象,则调用CSI Controller的ControllerPublish方法,完成Volume的Attach。(Volume的Mount阶段,直接由kubelet调用CSI Node提供的服务完成)
  • External Components 作为 sidecar 容器和 CSI 插件放置在同一个 Pod 中。
  • 最右侧是需要编码实现的CSI插件,以grpc方式对外提供三个服务:
    • CSI Identity 服务,负责对外暴露这个插件本身的信息
    • CSI Controller 服务,定义的则是对 CSI Volume(对应 Kubernetes 里的 PV)的管理接口
    • CSI Node 服务, 发起调用 NodePublishVolume 方法的请求,完成Mount操作
  • 具体的实现中,这个“Mount 阶段”的处理其实被细分成了 NodeStageVolume 和 NodePublishVolume 这两个接口。在 kubelet 的 VolumeManagerReconciler 控制循环中,这两步操作分别叫作MountDevice 和 SetUp。MountDevice就是格式化 Volume 在宿主机上对应的存储设备,然后挂载到一个临时目录(Staging 目录)上。SetUp 操作则将 Staging 目录,绑定挂载到 Volume 对应的宿主机目录上。

31. 编写CSI

  • 部署自定义CSI的原则:

    (1)以DaemonSet方式在每个节点上启动CSI插件,同时以sideCar的方式运行着driver-reigstrar。两个目的:

    • 1>为kubelet提供CSI Node服务;
    • 2>通过dirver-reigistrar访问CSI的Identity服务,向kubelet注册该CSI插件

    (2)以StatefulSet方式在任意一个节点上启动一个CSI插件,为外部组件提供CSI Controller服务,同时External Provisioner 和 External Attacher,就需要以 sidecar 的方式和该 CSI 插件定义在同一个 Pod 里。采用StatefulSet而不是Deployment的原因:若replica设置为1,则可以严格确保集群中只有一个CSI插件。

  • 采用CSI的持久化存储体系完全流程:

    • 1.PVC和PV的创建
      • 1>用户创建PVC
      • 2>External Provisioner监听到该PVC的创建,则调用CSI Controller 服务的 CreateVolume 方法,创建对应的网络磁盘,以及相应的PV("Provision"阶段
    • 2.PVC和PV的绑定
      • Master节点上的VolumeController通过PersistentVolumeController,根据storageClass信息绑定这一对PV和PVC, PVC进入"Bound"状态
    • 3.“Attach”阶段
      • 1>用户创建使用该PVC的Pod,该Pod被调度到某宿主机上。
      • 2>Master节点上的Volume Controller 的 AttachDetachController,发现该Pod需要将对应的PVC绑定的PV挂载到该宿主机上,则创建一个VolumeAttachment对象,携带宿主机和Volume的名字
      • 3>External Attacher监听到VolumeAttachment的创建,利用其中的信息,调用CSI Controller的ControllerPublishVolume方法,完成“Attach”
    • 4."Mount"阶段
      • 宿主机上的kubelet通过VolumeManagerReconciler发现宿主机上Attach了一个Volume,则调用CSI Node的NodeStageVolume和NodePublishVolume方法,完成“Mount”
posted @ 2021-02-03 09:43  lwjj  阅读(405)  评论(0编辑  收藏  举报