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