簡介
卷是Pod的一部分,與Pod共享生命週期。它不是獨立的Kubernetes物件,因此不能單獨建立。
卷提供的儲存功能不但可以解決容器重啟後資料丟失的問題,還可以使資料在容器間共享。
一些卷的型別:
- emptyDir:用於儲存臨時資料的空目錄
- hostPath:用於將目錄從工作節點掛載到pod
- gitRepo:通過檢出Git倉庫的內容來初始化的卷
- nfs:掛載到pod中的nfs共享卷
- configMap、secret、downwardAPI:用於將Kubernetes部分資源和叢集資訊公開給pod的特殊型別的卷
- persistentVolumeClaim:一種使用預置或者動態配置的持久儲存型別
單個容器可以同時使用不同型別的多個卷。
emptyDir
emptyDir卷對於在同一個pod中執行的容器之間共享檔案特別有用。但也可以被單個容器用於將資料臨時寫入磁碟。
下面的例子中,Pod包含兩個容器,這個兩個容器分別將卷html掛載到容器內的不同路徑,實現了檔案共享。html-generator每隔一秒寫入當前時間到index.html,web-server提供web服務使index.html可以被訪問。
# volume-share-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-share
spec:
containers:
- image: alpine # 容器映象一
name: html-generator
volumeMounts: # 將名為html的卷掛載到容器的/var/html
- name: html
mountPath: /var/html
command: ["sh","-c","mkdir /var/html; while :; do echo $(date) > /var/html/index.html;sleep 1;done"]
- image: nginx:alpine #容器映象二
name: web-server
volumeMounts: # 與上面相同的卷卷掛載到容器的/usr/share/nginx/html
- name: html
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- containerPort: 80
volumes: # 建立一個名為html的卷
- name: html
emptyDir: {}
建立pod,設定埠轉發
-> [root@kube0.vm] [~] k create -f volume-share-pod.yaml
pod/volume-share created
-> [root@kube0.vm] [~] k port-forward volume-share 80:80
Forwarding from 127.0.0.1:80 -> 80
Forwarding from [::1]:80 -> 80
發出請求
-> [root@kube0.vm] [~] curl http://localhost
Sun May 24 01:14:48 UTC 2020
-> [root@kube0.vm] [~] curl http://localhost
Sun May 24 01:14:49 UTC 2020
如果進行下面的改動,emptyDir的內容會存在記憶體中
volumes:
- name: html
emptyDir:
medium: Memory
gitRepo
gitRepo卷基本上也是一個emptyDir卷,它在容器啟動前從git倉庫檢出填充資料。
當git倉庫內容發生改變時,對已存在的Pod內的gitRepo卷是不可見的。但啟動新的Pod時會檢出最新的。
下面的例子中,該pod建立了一個名為html的gitRepo卷的,建立一個提供web服務的容器web-server,並將卷html掛載到web-server的/usr/share/nginx/html。
# volume-gitrepo-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-gitrepo
spec:
containers:
- image: nginx:alpine
name: web-server
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- containerPort: 80
volumes: # 建立一個名為html的gitRepo卷
- name: html
gitRepo:
repository: https://github.com/orccn/kube-dockerfile.git # 倉庫地址
revision: master # 分支
directory: . # 檢出到卷的根目錄
建立pod,設定埠轉發
-> [root@kube0.vm] [~] k create -f volume-gitrepo-pod.yaml
pod/volume-gitrepo created
-> [root@kube0.vm] [~] k port-forward volume-gitrepo 80:80
Forwarding from 127.0.0.1:80 -> 80
Forwarding from [::1]:80 -> 80
發出請求
-> [root@kube0.vm] [~] curl http://localhost/etcd/Dockerfile
FROM k8s.gcr.io/etcd:3.4.3-0
hostPath
hostPath卷提供的是對映到工作節點本地的持久儲存。所以應僅當需要在工作節點上讀寫檔案時才使用hostPath
下例中,Pod中建立一個名為html的hostPath卷掛載到工作節點的 /tmp/html,容器volume-hostpath將卷html掛載到/var/html,並且向其中寫入檔案。
# volume-hostpath-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-hostpath
spec:
containers:
- image: alpine
name: volume-hostpath
command: ["sh","-c","mkdir /var/html; while :; do echo $(date) > /var/html/index.html;sleep 1;done"]
volumeMounts:
- name: html
mountPath: /var/html
volumes:
- name: html
hostPath:
path: /tmp/html
建立volume-hostpath,檢視其部署在哪個節點。
-> [root@kube0.vm] [~] k create -f volume-hostpath-pod.yaml
pod/volume-hostpath created
-> [root@kube0.vm] [~] k get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volume-hostpath 1/1 Running 0 9m32s 10.244.1.11 kube1.vm <none> <none>
進入節點kube1.vm
-> [root@kube1.vm] [~] cat /tmp/html/index.html
Sun May 24 02:26:14 UTC 2020
PV與PVC
PV(PersistentVolume持久卷)也是一種資源,並且不屬於任何名稱空間。它的功能與卷類似,但是它的生命週期是獨立於Pod的。PV由叢集管理員建立,並被Pod通過PVC(PersistentVolumeClaim,持久卷宣告)使用。
在建立PV時,管理員可以指定其大小和支援的訪問模式:
- ReadWriteOnce(RWO):僅允許單個節點掛載讀寫
- ReadOnlyMany(ROX):允許多個節點掛載只讀
- ReadWriteMany(RWX):允許多個節點掛載讀寫
一個卷不論支援多少種訪問模式,同時只能以一種訪問模式載入。
建立PV
管理員在建立PV時需要指定,PV的大小、訪問模式、實際儲存型別、路徑等。
# pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mypv
spec:
capacity:
storage: 10Mi # 定義大小
accessModes: # 支援單個客戶端掛在為讀寫模式或者多個客戶端只讀模式
- ReadWriteOnce
- ReadOnlyMany
persistentVolumeReclaimPolicy: Retain # 當宣告被釋放後,PV將被保留
hostPath:
path: /tmp/pv
條件有限,所以儲存型別只能先選hostPath用著,接下來建立pv並檢視
-> [root@kube0.vm] [~] k create -f pv.yaml
persistentvolume/volume-pv created
-> [root@kube0.vm] [~] k get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv 10Mi RWO,ROX Retain Available 4s
建立PVC
假設要部署一個需要持久化儲存的Pod,將要用到持久卷,但是不能在Pod中直接使用,需要先宣告一個。
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
spec:
resources:
requests:
storage: 10Mi
accessModes:
- ReadWriteOnce
storageClassName: ""
PVC建立好後,Kubernetes會尋找適當的PV將其繫結到PVC。持久卷必須要足夠大,並且包含宣告中指定的訪問模式。
-> [root@kube0.vm] [~] k create -f pvc.yaml
persistentvolumeclaim/mypvc created
-> [root@kube0.vm] [~] k get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/mypv 10Mi RWO,ROX Retain Bound default/mypvc 7m11s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mypvc Bound mypv 10Mi RWO,ROX 9s
可以看到持久卷被繫結到default/mypvc宣告上,default是mypvc的名稱空間。PV不存在名稱空間的概念,但是PVC只能在特定名稱空間建立。
Pod中使用PVC
# use-pvc-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: use-pvc
spec:
containers: # 這裡的內容與volume-share.yaml的一樣,所以功能不再贅敘,
- image: alpine
name: html-generator
volumeMounts:
- name: html
mountPath: /var/html
command: ["sh","-c","mkdir /var/html; while :; do echo $(date) > /var/html/index.html;sleep 1;done"]
volumes:
- name: html
persistentVolumeClaim: # 這裡使用了PVC型別,制定了PVC的名字
claimName: mypvc
建立Pod
-> [root@kube0.vm] [~] k create -f use-pvc-pod.yaml
pod/use-pvc created
-> [root@kube0.vm] [~] k get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
use-pvc 1/1 Running 0 4m1s 10.244.1.12 kube1.vm <none> <none>
與kube1.vm檢視是否寫入了內容
-> [root@kube1.vm] [~] cat /tmp/pv/index.html
Sun May 24 06:43:02 UTC 2020
回收PV
刪除PVC後,檢視PV,可以看到此時的狀態是Released,而不是之前的Available。
-> [root@kube0.vm] [~] k delete pvc mypvc
persistentvolumeclaim "mypvc" deleted
-> [root@kube0.vm] [~] k get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv 10Mi RWO,ROX Retain Released default/mypvc 35s
這時候在建立PVC,會發現mypvc的狀態一直是Pending,因為沒有可用的PV。所以,persistentVolumeReclaimPolicy設定為Retain
的PV需要手動刪除重建才能恢復可用。
-> [root@kube0.vm] [~] k create -f pvc.yaml
persistentvolumeclaim/mypvc created
-> [root@kube0.vm] [~] k get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc Pending 16s
persistentVolumeReclaimPolicy用來設定回收策略,其他兩種是Recycle和Delete。可以在現有的PV上更改捲回收策略,比如開始設定為Delete,可以改為Retain。
PV與PVC的宣告週期,以及在Pod中的使用
StorageClass
使用PV與PVC可以使開發人員不用關心實際的儲存技術,但是仍然需要叢集管理人員來支援實際的儲存。可以通過建立StorageClass資源解決此問題。
StorageClass的作用是:為引用它的PVC在建立的時候通過置備程式建立一個PV。
工作流程簡介:
- 叢集管理員根據不同效能及特性建立若干個StorageClass
- 開發人員建立一個引用StorageClass的PVC
- Kubernetes查詢引用的StorageClass置備程式,並按照PVC的訪問模式和儲存大小置備新的PV
因為環境問題,下面的例子使用minikube執行。
建立StorageClass
# storageclass-fast.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: k8s.io/minikube-hostpath
parameters:
type: pd-ssd
執行檢視
-> [feifei@ffmac.local] [~/work/k8s] kubectl create -f storageclass-fast.yaml
storageclass.storage.k8s.io/fast created
-> [feifei@ffmac.local] [~/work/k8s] kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
fast k8s.io/minikube-hostpath Delete Immediate false 114m
standard (default) k8s.io/minikube-hostpath Delete Immediate false 117m
建立PVC引用StorageClass
# pvc-storageclass.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-sc
spec:
resources:
requests:
storage: 10Mi
accessModes:
- ReadWriteOnce
storageClassName: fast # 引用了上面名為fast的StorageClass
可以看到,成功建立了一個名為pvc-be95fa9c-0666-4e3b-a2e2-a68c0bbea6f6
的持久卷,繫結的持久卷宣告是default/pvc-sc
。訪問模式與儲存大小與pvc-sc的都一致。
-> [feifei@ffmac.local] [~/work/k8s] kubectl create -f pvc-storageclass.yaml
persistentvolumeclaim/pvc-sc created
-> [feifei@ffmac.local] [~/work/k8s] kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-be95fa9c-0666-4e3b-a2e2-a68c0bbea6f6 10Mi RWO Delete Bound default/pvc-sc fast 3m36s
-> [feifei@ffmac.local] [~/work/k8s] kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-sc Bound pvc-be95fa9c-0666-4e3b-a2e2-a68c0bbea6f6 10Mi RWO fast 3m40s
不指定儲存類的動態配置
如果將PVC配置中的storageClassName設定為空,那麼建立PVC時將優先繫結到預先配置的PV,而不是由StorageClass配置新的PV。
流程圖
小結
- 卷是Pod的一部分,與Pod共享生命週期。它不是獨立的Kubernetes物件,因此不能單獨建立。
- 卷提供的儲存功能不但可以解決容器重啟後資料丟失的問題,還可以使資料在容器間共享。
- gitRepo卷基本上相當於emptyDir,它在容器啟動前從git倉庫檢出填充資料。但git倉庫與gitRepo的內容並不保持同步。
- hostPath卷提供的是對映到工作節點本地的持久儲存
- PV是一種資源,並且不屬於任何名稱空間。它的功能與卷類似,但是它的生命週期是獨立於Pod的。PV由叢集管理員建立,並被Pod通過PVC使用。
- PVC建立好後,Kubernetes會尋找適當的PV將其繫結到PVC。持久卷必須要足夠大,並且包含宣告中指定的訪問模式。
- 可以在現有的PV上更改捲回收策略,比如開始設定為Delete,可以改為Retain。
- StorageClass為引用它的PVC在建立的時候通過置備程式建立一個PV
- 如果將PVC配置中的storageClassName設定為空,那麼建立PVC時將優先繫結到預先配置的PV,而不是由StorageClass配置新的PV。