kubernetes_PV_PVC

Kubernetes PV & PVC


概念

PV: Persistent Volume,持久化存儲數據卷,Pod想要使用的持久化存儲的屬性,比如存儲的大小、讀寫權限等

PVC: Persistent Volume Claim,是一個具體的Volume的屬性,比如Volume類型、掛載目錄、遠程存儲服務器地址等


爲什麼需要Persistent Volume

所謂容器的Volume,就是將一個宿主機上的目錄,跟一個容器裏的目錄綁定掛載在一起。而所謂的“持久化Volume”,指的就是這個宿主機上的目錄,具備“持久性”。就是這個目錄裏面的內容,既不會因爲容器的刪除而被清理掉,也不會跟當前的宿主機綁定。這樣,當容器被重啓或者在其他節點上重建出來之後,它仍然能夠通過掛載這個Volume,訪問到這些內容。而僅僅通過hostPath和emptyDir類型的Volume無法達到持久化,因爲他們既有可能被kubelet清理掉,也不能被“遷移”到其他節點上。因此,大多數情況下,持久化Volume的實現,往往依賴於一個遠程存儲服務。


爲什麼還需要Persistent Volume Claim

場景:開發人員想使用Volume但是不知道有什麼類型的Volume可以用。

更具體說,作爲一個應用開發者,我可能對持久化存儲項目一竅不通,也不知道公司的kubernetes集羣裏到底是怎麼搭建的,自然也不會編寫它們對應的Volume定義文件。這些關於Volume的管理和遠程持久化存儲的知識,不僅超越了開發者的知識儲備,還會暴露公司基礎設施祕密的風險。

apiVersion: v1
kind: Pod
metadata:
	name: rbd
spec:
	containers:
	- image: kubernetes/pause
	  name: rbd-rw
	  volumeMounts:
	  - name: rbdpd
	    mountPath: /mnt/rbd
	volumes:
	- name: rbdpd
	  rbd:
	  monitors:
	  - '10.16.154.78:6789'
	  - '10.16.154.82:6789'
	  - '10.16.154.83:6789'
	  pool: kube
	  image: foo
	  fsType: ext4
	  readOnly: true
	  user: admin
	  keyring: /etc/ceph/keyring
	  imageformat: "2"
	  imagefeatures: "layering"

例如上面這個Ceph RBD類型Volume的Pod。如果不懂得Ceph RBD的使用方法,volumes裏面絕大部分參數都是不清楚在幹嘛的。另外這個RBD對應的存儲服務器的地址、用戶名、授權文件的位置,也都被輕易地暴露給了全公司的所有開發人員,“過渡暴露”。

因此,爲了降低開發人員使用Volume的門檻,及避免“過渡暴露”,kubernetes提出了PVC,來解耦聲明volume和使用volume的動作。


使用PV和PVC

通過分別聲明PV和PVC,然後在Pod的yaml聲明要用的PVC,完成volume掛載。

PV yaml

聲明一個類型爲nfs的PV,一個PV yaml定義,主要是定義存儲大小,讀寫權限及存儲方式的參數。這裏nfs,就是要指定服務器地址,磁盤位置。

PV一般由運維人員聲明。

apiVersion: v1
kind: PersistentVolume
metadata:
	name: nfs
spec:
	storageClassName: manual
	capacity:
		storage: 1Gi
		accessModes:
		- ReadWriteMany
	nfs:
		server: 10.244.1.4
		path: "/"
PVC yaml

首先,定義一個PVC,PVC yaml文件主要聲明要使用的volume的需求是什麼,比如存儲空間大小,可讀寫權限等。

PVC一般由開發人員聲明。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
	name: nfs
spec:
	accessModes:
	- ReadWriteMany
	storageClassName: manual
	resources:
		requests:
			storage: 1Gi

然後,Pod聲明使用PVC,在volumes裏申明要使用PVC的名字,即persistentVolumeClaim。等這個Pod創建之後,kubelet就會把這個PVC對應的PV,掛載在這個Pod容器內的目錄上。

apiVersion: v1
kind: Pod
metadata:
	labels:
	role: web-frontend
spec:
	containers:
	- name: web
	  image: nginx
	  ports:
	  - name: web
	    containerPort: 80
	  volumeMounts:
	  - name: nfs
 	    mountPath: "/usr/share/nginx/html"
	volumes:
	- name: nfs
	  persistentVolumeClaim:
	  	claimName: nfs

PV不滿足PVC

在上面的例子中,我們先聲明瞭一個PV,然後再聲明一個PVC,這種情況下PVC一定會會找到對應的PV來綁定。然後,有種情況是,開發人員先聲明瞭PVC,創建Pod的時候報錯表示沒有符合的PV。很明顯,運維人員還沒有聲明PV。

持久化存儲控制器

運維人員發現後馬上創建一個符合開發人員需求的PV,此時kubernetes會完成PVC和PV的綁定操作,然後啓動Pod。

kubernetes能夠馬上把PVC和PV綁定在一起,是因爲在kubernetes中,存在着⼀個專⻔處理持久化存儲的控制器,叫作Volume Controller。這個Volume Controller維護着多個控制循環,其中有⼀個循環,扮演的就是撮合PV和PVC的“紅娘”的⻆⾊。它的名字叫作PersistentVolumeController。

PersistentVolumeController會不斷地查看當前每⼀個PVC,是不是已經處於Bound(已綁定)狀態。如果不是,那它就會遍歷所有的、可⽤的PV,並嘗試將其與這個“單身”的PVC進⾏綁定。這樣,Kubernetes就可以保證⽤戶提交的每⼀個PVC,只要有合適的PV出現,它就能夠很快進⼊綁定狀態,從⽽結束“單身”之旅。

StorageClass

在上面的例子中,我們運維人員發現了有PVC不被滿足,所以馬上創建了一個滿足需求的PV。然後,在一個Kubernetes中可能有成千上萬的PVC,對運維人員來說是一個很大的工作量。kubernetes提供了一個自動創建PV的機制,爲Dynamic Provisioning。相比之前的,則被稱爲Static Provisioning。

Dynamic Provisioning機制的核心是StorageClass。StorageClass的目的主要是創建PV模版。

storage class yaml文件主要定義PV的屬性,比如存儲類型,Volume大小等。然後創建PV需要再用到存儲插件。比如Ceph等。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
	name: block-service
provisioner: kubernetes.io/gce-pd
parameters:
	type: pd-ssd

PVC指定要使用的StorageClass,相比前面的PVC yaml的storageClassName爲manul,下面的PVC yaml指定了storageClassName。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
	name: claim1
spec:
	accessModes:
	- ReadWriteOnce
	storageClassName: block-service
	resources:
		requests:
			storage: 30Gi

在PVC創建之後,kubernetes就會通過存儲插件創建一個PV,並且這個PV的StorageClass值和PVC的StorageClass的值相同,就是storageClassName相同。


PV持久化實現

kubernetes需要做的就是,使用這些存儲服務,來爲容器準備一個持久化的宿主機目錄,以供將來進行綁定掛載時使用。而所謂“持久化”,指的是容器在這個目錄裏面寫入的文件,都會保存在遠程存儲中,從而使得這個目錄具備了“持久性”。

這個準備“持久化”宿主機目錄的過程,分爲兩步,Attach和Mount。

Attach

這一步主要是爲虛擬機掛載遠程磁盤。

這一步主要針對Volume類型爲遠程塊存儲,比如Google Cloud的Persistent Disk,那麼kubelet就需要先調用Google Cloud的API,將它所提供的Persistent Disk掛載到Pod所在的宿主機上。如果Volume類型爲遠程文件存儲,例如NFS,那就會跳過這一步,因爲遠程文件存儲並沒有一個“存儲設備”需要掛載在宿主機上。

kubernetes中通過AttachDetachController執行Attach操作,不斷地檢查每一個Pod對應的PV,和這個Pod所在宿主機之間掛載情況。從而決定是否需要對這個PV進行Attach(或者Dettach)操作。這個Controller運行在master節點上。

Mount

Attach完成後,kubelet需要格式化磁盤設備,然後將它掛載到宿主機指定的掛載點上。

kubernetes中通過VolumeManagerReconciler執行Mount操作,是kubelet組件的一部分。它獨立運行於kubelet主循環的Goroutine。

相當於執行:

# 通過lsblk命令獲取磁盤設備ID
$ sudo lsblk
# 格式化成ext4格式
$ sudo mkfs.ext4 -m 0 -F -E lazy_itable_init=0,lazy_journal_init=0,discard /dev/<磁盤設備ID>
# 掛載到掛載點
$ sudo mkdir -p /var/lib/kubelet/pods/<Pod的ID>/volumes/kubernetes.io~<Volume類型>/<Volume名字>

總結

⽤戶提交請求創建pod,Kubernetes發現這個pod聲明使⽤了PVC,那就靠PersistentVolumeController幫它找⼀個PV配對。
沒有現成的PV,就去找對應的StorageClass幫它新創建⼀個PV或讓運維人員創建一個,然後和PVC完成綁定。
新創建的PV,還只是⼀個API 對象,需要經過“兩階段處理”變成宿主機上的“持久化 Volume”才真正有用:
第⼀階段由運⾏在master上的AttachDetachController負責,爲這個PV完成 Attach 操作,爲宿主機掛載遠程磁盤;
第⼆階段是運⾏在每個節點上kubelet組件的內部,把第⼀步attach的遠程磁盤 mount 到宿主機⽬錄。這個控制循環叫VolumeManagerReconciler,運⾏在獨⽴的Goroutine,不會阻塞kubelet主循環。
完成這兩步,PV對應的“持久化 Volume”就準備好了,POD可以正常啓動,將“持久化 Volume”掛載在容器內指定的路徑。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章