Pod挂载LocalStoragePv过程理解

 1处的控制循环Control Loop应该是:VolumeManagerReconciler

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Local Persistent Volume: 利用pv&pvc这种松耦合机制来实现直接使用宿主机上的本地磁盘目录,而不依赖于远程存储服务,来提供“持久化”的容器 Volume

设计lpv过程需要考虑的两个问题:

1. 如何把本地磁盘抽象成 PV(一个 PV 一块盘):pv对应的目录所挂载的磁盘不应该是宿主机根目录使用的硬盘,因为一旦pv不使用独立的磁盘,将会变成完全不可控,比如磁盘很容易被其他进程应用写满,甚至造成整个宿主机宕机。而且同一个磁盘的不同的目录之间也缺乏最基础的 I/O 隔离机制.

2.  Pod 能被正确地调度到lpv 对应节点上(延迟绑定):常规的pv记录的是与节点无关的远程共享存储,而lpv则与某些节点关联在一起.

考虑这样的场景:

假设我的集群中有3个节点,分别是node1、node2、node3,其中node1和node2具有diskType=ssd的标签,且node1和node2已经使用独立的磁盘挂载到/mnt/disks/volA目录,node3使用独立的磁盘挂载到/mnt/disks/volB目录

假设我的集群已经创建好了两个pv,分别是pvA和pvB

pvA.yaml如下。字段nodeAffinity表明想要使用这个pv的pod只能被调度到带diskType=ssd标签的节点上,也就是node1、node2

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pvA
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  local: #local字段表明这是一个Local Persistent Volume的pv
    path: /mnt/disks/volA
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: diskType
          operator: In
          values:
          - ssd

 pvB.yaml如下。字段nodeAffinity表明想要使用这个pv的pod只能被调度到带node3

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pvB
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  local: local字段表明这是一个Local Persistent Volume的pv
    path: /mnt/disks/volB
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node3

 

pvc.yaml文件如下

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: example-local-claim
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: local-storage

 

创建一个pod声明使用example-local-claim这个pvc,如果按照常规pv的处理模式来说,当pvc一旦创建,就会被volumeController的PersistentVolumeController控制循环检测到,并尝试寻找合适的pv进行绑定。Kubernetes将先调度 Pod 到某个节点上,然后,根据pv上定义的信息,通过“两阶段处理”来“持久化”这台机器上的 Volume 目录,进而完成 Volume 目录与容器的绑定挂载(将一个目录挂载到挂载点目录,而不是将一个设备挂载到挂载点目录)。在lpv上就不能通过这种方式处理了,因为如果pvc一经创建就选择一个pv绑定,在上面的例子中,如果pvc和pvB绑定,那么使用这个pvc的pod也就被限制在node3节点,如果pod这边又通过NodeAffinity节点亲和性或nodeSelector强制pod调度到节点node2,此时就会出现冲突,这个pod也就会一直pending了。

k8s的lpv是通过pvc和pv的延迟绑定来解决这个冲突的:创建一个storageClass,配置volumeBindingMode为WaitForFirstConsumer,且在pvA和pvB中声明使用这个storageClass

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

 WaitForFirstConsumer表示第一个使用这个pvc的pod在调度过程中才决策合适的pv进行绑定。这样一来,k8s就可以综合考虑pod对Node的要求和pv对Node的要求,最终pvc选择和pvA进行绑定。

参考资料:

当前k8s支持的存储插件:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes

posted @ 2019-12-11 21:01  JL_Zhou  阅读(1598)  评论(0编辑  收藏  举报