k8s持久化状态存储原理

PV和PVC概念

     PVC描述的则是Pod所希望使用的持久化存储的属性.比如Volume 存储的大小、可读写权限等等
     PVC对象通常由开发人员创建或者以PVC模板的方式成为StatefulSet的一部分,然后由StatefulSet控制器负责创建带编号的PVC

     PVC要真正被容器使用起来就必须先和某个符合条件的PV进行绑定两者实现绑定要满足的两个条件

        1.当然是PV和PVC的spec字段.比如PV的存储(storage)大小,就必须满足PVC的要求
        2.PV和PVC的storageClassName字段必须一样

     PVC和PV进行绑定之后Pod就能够像使用hostPath等常规类型的Volume一样
     创建Pod的时候系统里并没有合适的PV跟它定义的PVC绑定,也就是说此时容器想要使用的Volume不存在的时候Pod的启动就会报错

架构设计

        Kubernetes中实际上存在着一个专门处理持久化存储的控制器,叫作Volume Controller.这个Volume Controller 维护着多个控制循环,其中有一个循环扮演的就是撮合PV和PVC的角色.它的名字叫作 PersistentVolumeController.

       PersistentVolumeController会不断地查看当前每一个PVC是不是已经处于 Bound(已绑定)状态.如果不是,那它就会遍历所有的、可用的PV,并尝试将其与这个PVC进行绑定.这样Kubernetes就可以保证用户提交的每一个PVC只要有合适的PV 出现它就能够很快进入绑定状态

       PV和PVC绑定的原理
         将这个PV对象的名字填在了PVC对象的spec.volumeName字段上.所以接下来Kubernetes只要获取到这个PVC对象就能够找到它所绑定的PV

PV持久化存储原理

    容器的Volume其实就是将一个宿主机上的目录跟一个容器里的目录绑定挂载在了一起所谓的“持久化Volume”,指的就是这个宿主机上的目录,具备“持久性”.即:这个目录里面的内容,既不会因为容器的删除而被清理掉,也不会跟当前的宿主机绑定.这样,当容器被重启或者在其他节点上重建出来之后,它仍然能够通过pv编号挂载这个Volume

    Kubernetes需要做的工作,就是使用这些存储服务,来为容器准备一个持久化的宿主机目录,以供将来进行绑定挂载时使用.而所谓“持久化”,指的是容器在这个目录里写入的文件,都会保存在远程存储中,从而使得这个目录具备了“持久性”

   持久化Volume的实现,往往依赖于一个远程存储服务

   挂载目录的实现

      1.远程文件存储(比如,NFS、GlusterFS)
         远程文件存储服务相当于直接提供存储目录 直接可以挂载使用
         mount -t nfs <NFS服务器地址>:/var/lib/kubelet/pods/pod_id/volumes/kubernetes.io~volume类型/volume名字

        通过这个挂载操作Volume的宿主机目录就成为了一个远程 NFS目录的挂载点,后面在这个目录里写入的所有文件都会被保存在远程 NFS 服务器上.所以我们也就完成了对这个 Volume 宿主机目录的“持久化"
      2.远程块存储(比如,公有云提供的远程磁盘)
        相当于一块磁盘 磁盘在第一次使用之前必须先对磁盘进行格式化,否则无法写入文件
       1.先把远程磁盘挂载到Pod所在的宿主机上
         gcloud compute instances attach-disk <虚拟机名字> --disk <远程磁盘名字>
       2.格式化磁盘设备创建挂载目录
         # 通过lsblk命令获取磁盘设备ID
         $ lsblk
         # 格式化成ext4格式
        $ mkfs.ext4 -m 0 -F -E lazy_itable_init=0,lazy_journal_init=0,discard /dev/<磁盘设备ID>
        # 把格式化后的磁盘挂载到volume目录
           mkdir -p  /var/lib/kubelet/pods/pod_id/volumes/kubernetes.io~volume类型/volume名字

        Kubernetes需要做的工作,就是使用这些存储服务,来为容器准备一个持久化的宿主机目录,以供将来进行绑定挂载时使用.而所谓“持久化”,指的是容器在这个目录里写入的文件,都会保存在远程存储中,从而使得这个目录具备了“持久性”

创建持久化宿主机目录

        当一个Pod调度到一个节点上之后kubelet就要负责为这个Pod创建它的Volume 目录.默认情况下,kubelet为Volume创建的目录是如下所示的一个宿主机上的路径/var/lib/kubelet/pods/pod_id/volumes/kubernetes.io~volume类型/volume名字

把持久化目录挂载到容器中

       经过了attach和mount两阶段我们就得到了一个“持久化”的Volume 宿主机目录.所以接下来kubelet只要把这个Volume目录通过CRI里的Mounts参数,传递给Docker然后就可以为Pod里的容器挂载这个“持久化”的Volume 了.其实,这一步相当于执行了如下所示的命令:docker run -v /var/lib/kubelet/pods/pod_id/volumes/kubernetes.io~volume类型/volume名字:/<容器内的目标目录>  我的镜像...

StorageClass动态创建PV

    需要后台存储插件支持Dynamic Provisioning机制 如果不支持就不能用StorageClass动态创建pv.StorageClass并不是专门为了Dynamic Provisioning而设计的
    可以通过设置storageClassName来控制pv和pvc的绑定关系. storageClassName可以是任何一个字符串

   集群已经开启名叫DefaultStorageClass的Admission Plugin,它就会为PVC和PV自动添加一个默认的StorageClass;否则PVC的storageClassName 的值就是" "这也意味着它只能够跟storageClassName也是" "的PV进行绑定

   PVC 描述的是Pod想要使用的持久化存储的属性,比如存储的大小、读写权限等
   PV 描述的则是一个具体的Volume的属性,比如Volume的类型、挂载目录、远程存储服务器
   StorageClass的作用则是充当PV的模板.并且只有同属于一个StorageClass的PV和PVC才可以绑定在一起

   StorageClass的另一个重要作用,是指定PV的 Provisioner(存储插件).这时候,如果存储插件支持Dynamic Provisioning 的话k8s就可以自动为你创建PV

Local Persistent Volume设计

     希望Kubernetes能够直接使用宿主机上的本地磁盘目录,而不依赖于远程存储服务,来提供“持久化”的容器Volume

     这样做的好处很明显由于这个Volume直接使用的是本地磁盘尤其是SSD盘,它的读写性能相比于大多数远程存储来说,要好得多

     这个需求对本地物理服务器部署的私有Kubernetes集群来说  非常常见 

     常规PVC和Local PV的区别:

       对于常规的PV来说Kubernetes都是先调度Pod到某个节点上,然后再通过“两阶段处理”来“持久化”这台机器上的Volume 目录,进而完成Volume目录与容器的绑定挂载

       对于Local PV来说,节点上可供使用的磁盘(或者块设备)必须是运维人员提前准备好的.它们在不同节点上的挂载情况可以完全不同,甚至有的节点可以没这种磁盘

       这时候调度器就必须能够知道所有节点与Local Persistent Volume对应的磁盘的关联关系,然后根据这个信息来调度Pod

    延迟绑定机制:

        默认情况下 用户在提交PV和PVC的YAML 文件之后,Kubernetes 就会根据它们俩的属性,以及它们指定的StorageClass来进行绑定.只有绑定成功后Pod才能通过声明这个 PVC 来使用对应的PV

       PVC和PV的绑定是由独立运行的控制循环来执行的 相当于是实时的 Volume检测循环和Pod的调度循环是异步的 PV和PVC绑定完成后 调用该PV的Pod可能还没有被调度

       延迟绑定机制就是确保PVC和PV的绑定操作推迟到使用该PV的Pod进行调度的时候 这样可以让调度器综合考虑所有的调度规则同时也包含了PV所在的节点位置来统一决定这个Pod声明的PVC具体和哪个PV进行绑定

      通过这个延迟绑定机制,原本实时发生的PVC和PV的绑定过程,就被延迟到了 Pod 第一次调度的时候在调度器中进行,从而保证了这个绑定结果不会影响Pod的正常调度