Volume 是在 Docker 中用來儲存資料的元件。在容器的世界中,應用程式中的資料會隨著容器的刪除而跟著消失,故需要透過 Volume 的方式保存這些資料。
除了讓資料不會跟著容器刪除消失外,Volume 可以很輕易地去做到在不同容器上共享資料。
同樣的在 k8s 中,pods 中的資料於刪除時也會跟著消失。這時就需要談到 Persistent Volume 以及 PersistentVolumeClaim 這兩個角色。
在 k8s 中有很多不同類型的 Volume,這邊介紹 hostPath(實務盡量避免不使用)、Persistent Volume Claim。
因 hostPath 是將資料儲存在 worker node 上,但此做法存在許多安全性問題,因此「官方不建議使用」。
來看以下 pod 範例。
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: test-container
image: registry.k8s.io/test-webserver
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /data
type: DirectoryOrCreate
以上是在容器中使用 log-volume,將 /log
資料儲存在 node 上的 /var/log/webapp
位址。
volumeMounts
:mountPath
為需要掛載的路徑,name
為 volume 名稱volumes
:該 pod 使用哪些 volumes,hostPath
為使用的類型
path
:掛載到哪個路徑type
:DirectoryOrCreate
若目錄不存在會自動建立,其他類型可以參考。Persistent Volume(簡稱為PV)是在叢集中使用的 volume,由管理者建立讓使用者(應用程式)們在叢集上部署程式時使用。應用程式可以請求一個 volume,稱之為 Persistent Volume Claim(簡稱PVC)。
在 k8s 中:
以下是一個 PVC 範例。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi # 需求為 500MB
volumeMode: Filesystem
以下說明:
accessModes
:存取該 volume 的模式,在此為 ReadWriteOnce
即資料只能被一個 node 讀取及寫入的動作resources
:描述資源需求,storage: 500Mi
即需要 500MB 的空間以下是一個 PV 範例。
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
capacity:
storage: 2Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
hostPath:
path: /tmp/data # 儲存在 node 上的位址
以下說明:
capacity
:storage
定義要存 2G 資料當 PVC 建立後,k8s 會根據以上設定檔中的請求,與當前存在叢集中的 persistent volume 設定參數來比對,將PV 跟 PVC 做綁定,意即一個 PVC 會配對到一個 PV。
也就是說:
accessModes
、volumeMode
尋找合適的 PV。若當下有兩個 PV 符合 PVC 的請求時,可以另外使用 label selector (matchLabels
) 去篩選 PVC 要配到哪個 PV。
一但 PVC 建立後沒有相符的選擇,例如因容量不合(需求 500MB、PV 定義 2GB),但因沒有其他更好的選擇,k8s 會進行 binding。但如果當下沒有 PV 可以提供給 PVC,則 PVC 會處於 pending state 等待管理者建立 PV。
這邊使用 k8s 官網的範例。
index.html
,查看後並離開 ssh。minikube ssh
docker@minikube:~$ sudo mkdir /mnt/data
docker@minikube:~$ sudo sh -c "echo 'Hello from Kubernetes storage' > /mnt/data/index.html"
docker@minikube:~$ cat /mnt/data/index.html
Hello from Kubernetes storage
hostPath
,但在實務上不建議使用。vi po-volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
建立 persistent volume。
kubectl apply -f po-volume.yaml
persistentvolume/task-pv-volume created
STATUS
仍為 Available
意思是還沒指定到 PVC 上。
kubectl get pv task-pv-volume
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
task-pv-volume 10Gi RWO Retain Available manual manual 54s
vi pv-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
建立 PVC。
kubectl apply -f pv-claim.yaml
persistentvolumeclaim/task-pv-claim created
若 k8s 找到符合的 PV,會將該 PVC 綁定到 PV 上。STATUS
為 Bound
代表已綁定 PV。
kubectl get pvc task-pv-claim
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
task-pv-claim Bound task-pv-volume 10Gi RWO manual 2m19s
另外在 PV 上 CLAIM
可以看到綁定的 PVC 為 default/task-pv-claim
。
kubectl get pv task-pv-volume
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
task-pv-volume 10Gi RWO Retain Bound default/task-pv-claim 5m13s
vi pv-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage
persistentVolumeClaim:
claimName: task-pv-claim
containers:
- name: task-pv-container
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: task-pv-storage
persistentVolumeClaim
:指定 pod 使用的 PVC 類別的 volume。建立 pod。
kubectl apply -f pv-pod.yaml
pod/task-pv-pod created
kubectl get pod task-pv-pod
NAME READY STATUS RESTARTS AGE
task-pv-pod 1/1 Running 0 25s
/mnt/data/index.html
。apt update
apt install curl
curl http://localhost/
# 會更新與安裝一些套件的 log 就不列出來了
Hello from Kubernetes storage
看到 Hello from Kubernetes storage
就代表該 pod 成功使用 PVC,最後記得刪除 pod、pvc 與 pv。
kubectl delete pod task-pv-pod
kubectl delete pvc task-pv-claim
kubectl delete pv task-pv-volume
pod "task-pv-pod" deleted
persistentvolumeclaim "task-pv-claim" deleted
persistentvolume "task-pv-volume" deleted
當 PVC 刪掉後,PV 上沒有對應到 PVC,其預設是 Retain,PV 會留下直至管理者手動去刪除它前,並不會再給其他 PVC 使用。
以下範例。
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp
server: 172.17.0.2
persistentVolumeReclaimPolicy
:當 PVC 刪除後,PV 有三種情況可以設定:
Retain(預設)
Delete(PV 連同一起刪除)
Recycle(PV 的資料會被清洗掉,再給其他 PVC 使用)
以下為 2023-11-30 補充
一般我們透過 PV 與 PVC,再透過 pod 中 volume 去指定 persistentVolumeClaim
及 claimName
使用 PVC,稱之為 Static Provisioning。
每次 pod 要使用 PV、PVC,管理者就需要事先建立好 PV 讓 pod 可以 mount,這樣的方式會造成管理上的困擾。為了讓應用程式(pod)在需要時可以「自動建立 PV」,可以使用 StorageClass。這樣的方式稱為 Dynamic Volume Provisioning。
例如:
mypvc-def.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: my-storage-class
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
在 storageClassName
指定 StorageClass,在 pod 建立並指定該 PVC 時,StorageClass 會自動建立所需的 PV (AWS EBS gp2 磁碟類型,儲存容量為 1Gi)。
mysc-def.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: my-storage-class
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
1.Kubernetes - 配置 Pod 以使用 PersistentVolume 作为存储
2.Certified Kubernetes Administrator (CKA) with Practice Tests