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