Kubernetes 存儲卷管理 PV&PVC(十)
Volume 的生命周期獨立於容器,Pod 中的容器可能被銷毀和重建,但 Volume 會被保留。
本質上,Kubernetes Volume 是一個目錄,這一點與 Docker Volume 類似。當 Volume 被 mount 到 Pod,Pod 中的所有容器都可以訪問這個 Volume。Kubernetes Volume 也支持多種 backend 類型,包括 emptyDir、hostPath、GCE Persistent Disk、AWS Elastic Block Store、NFS、Ceph 等,完整列表可參考 https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes
一、emptyDir
emptyDir 是最基礎的 Volume 類型。正如其名字所示,一個 emptyDir Volume 是 Host 上的一個空目錄。
emptyDir Volume 對於容器來說是持久的,對於 Pod 則不是。當 Pod 從節點刪除時,Volume 的內容也會被刪除。但如果只是容器被銷毀而 Pod 還在,則 Volume 不受影響。
也就是說:emptyDir Volume 的生命周期與 Pod 一致。
Pod 中的所有容器都可以共享 Volume,它們可以指定各自的 mount 路徑。下面通過例子來實踐 emptyDir,配置文件如下:
apiVersion: v1 kind: Pod metadata: name: producer-consumer spec: containers: - name: producer image: busybox volumeMounts: - name: shared-volume mountPath: /producer_dir args: - /bin/sh - -c - echo "hello world" > /producer_dir/hello; sleep 30000 - name: consumer image: busybox volumeMounts: - name: shared-volume mountPath: /consumer_dir args: - /bin/sh - -c - cat /consumer_dir/hello; sleep 30000 volumes: - name: shared-volume emptyDir: {}
這裏我們模擬了一個 producer-consumer 場景。Pod 有兩個容器 producer和 consumer,它們共享一個 Volume。producer 負責往 Volume 中寫數據,consumer 則是從 Volume 讀取數據。
- 文件最底部 volumes 定義了一個 emptyDir 類型的 Volume shared-volume。
- producer 容器將 shared-volume mount 到 /producer_dir 目錄。
- producer 通過 echo 將數據寫到文件 hello 裏。
- consumer 容器將 shared-volume mount 到 /consumer_dir 目錄。
- consumer 通過 cat 從文件 hello 讀數據。
執行如下命令創建 Pod:
[root@master ~]# kubectl apply -f emptydir.yaml
pod/producer-consumer created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
producer-consumer 2/2 Running 0 8s
[root@master ~]# kubectl logs producer-consumer consumer
hello world
kubectl logs
顯示容器 consumer 成功讀到了 producer 寫入的數據,驗證了兩個容器共享 emptyDir Volume。
emptyDir 是 Host 上創建的臨時目錄,其優點是能夠方便地為 Pod 中的容器提供共享存儲,不需要額外的配置。但它不具備持久性,如果 Pod 不存在了,emptyDir 也就沒有了。根據這個特性,emptyDir 特別適合 Pod 中的容器需要臨時共享存儲空間的場景,比如前面的生產者消費者用例。
二、hostPath
hostPath Volume 的作用是將 Docker Host 文件系統中已經存在的目錄 mount 給 Pod 的容器。大部分應用都不會使用 hostPath Volume,因為這實際上增加了 Pod 與節點的耦合,限制了 Pod 的使用。不過那些需要訪問 Kubernetes 或 Docker 內部數據(配置文件和二進制庫)的應用則需要使用 hostPath。
下面的例子,我們把主機上的目錄/data/pod/v1
掛載到 Pod 上容器的/usr/share/nginx/html/
。
apiVersion: v1
kind: Pod
metadata:
name: pod-vol-hostPath
spec:
containers:
- name: mytest
image: wangzan18/mytest:v1
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
volumes:
- name: html
hostPath:
path: /data/pod/v1
type: DirectoryOrCreate
如果 Pod 被銷毀了,hostPath 對應的目錄也還會被保留,從這點看,hostPath 的持久性比 emptyDir 強。不過一旦 Host 崩潰,hostPath 也就沒法訪問了。
三、PV & PVC
Volume 提供了非常好的數據持久化方案,不過在可管理性上還有不足。
拿前面 AWS EBS 的例子來說,要使用 Volume,Pod 必須事先知道如下信息:
- 當前 Volume 來自 AWS EBS。
- EBS Volume 已經提前創建,並且知道確切的 volume-id。
Pod 通常是由應用的開發人員維護,而 Volume 則通常是由存儲系統的管理員維護。開發人員要獲得上面的信息:
- 要麽詢問管理員。
- 要麽自己就是管理員。
這樣就帶來一個管理上的問題:應用開發人員和系統管理員的職責耦合在一起了。如果系統規模較小或者對於開發環境這樣的情況還可以接受。但當集群規模變大,特別是對於生成環境,考慮到效率和安全性,這就成了必須要解決的問題。
Kubernetes 給出的解決方案是 PersistentVolume
和 PersistentVolumeClaim
。
PersistentVolume (PV)
是外部存儲系統中的一塊存儲空間,由管理員創建和維護。與 Volume 一樣,PV 具有持久性,生命周期獨立於 Pod。
PersistentVolumeClaim (PVC)
是對 PV 的申請 (Claim)。PVC 通常由普通用戶創建和維護。需要為 Pod 分配存儲資源時,用戶可以創建一個 PVC,指明存儲資源的容量大小和訪問模式(比如只讀)等信息,Kubernetes 會查找並提供滿足條件的 PV。
有了 PersistentVolumeClaim
,用戶只需要告訴 Kubernetes 需要什麽樣的存儲資源,而不必關心真正的空間從哪裏分配,如何訪問等底層細節信息。這些 Storage Provider 的底層信息交給管理員來處理,只有管理員才應該關心創建 PersistentVolume 的細節信息。
Kubernetes 支持多種類型的 PersistentVolume,比如 AWS EBS、Ceph、NFS 等,完整列表請參考 https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes
下節我們用 NFS 來體會 PersistentVolume 的使用方法。
1、NFS PersistentVolume
作為準備工作,我們已經在 node3 節點上搭建了一個 NFS 服務器,輸出三個目錄:
[root@datanode03 ~]# showmount -e localhost
Export list for localhost:
/data/volumes/pv003 192.168.1.0/24
/data/volumes/pv002 192.168.1.0/24
/data/volumes/pv001 192.168.1.0/24
下面創建PV
,配置文件 nfs-pv.yaml
如下:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
path: /data/volumes/pv001
server: 192.168.1.203
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv002
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteMany
nfs:
path: /data/volumes/pv002
server: 192.168.1.203
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv003
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /data/volumes/pv003
server: 192.168.1.203
accessModes
指定訪問模式為 ReadWriteOnce,支持的訪問模式有:
ReadWriteOnce
– PV 能以 read-write 模式 mount 到單個節點。ReadOnlyMany
– PV 能以 read-only 模式 mount 到多個節點。ReadWriteMany
– PV 能以 read-write 模式 mount 到多個節點。
persistentVolumeReclaimPolicy
指定當 PV 的回收策略為 Recycle,支持的策略有:
Retain
– 需要管理員手工回收。Recycle
– 清除 PV 中的數據,效果相當於執行rm -rf /thevolume/*
。Delete
– 刪除 Storage Provider 上的對應存儲資源,例如 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。
創建我們剛剛做好的PV。
[root@master ~]# kubectl apply -f nfs-pv.yaml
persistentvolume/pv001 created
persistentvolume/pv002 created
persistentvolume/pv003 created
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 1Gi RWX Retain Available 6s
pv002 5Gi RWX Retain Available 6s
pv003 10Gi RWX Recycle Available 6s
2、創建 PVC
創建配置文件nfs-pvc.yaml
,修改內容如下:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc001
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
創建 PVC。
[root@master ~]# kubectl apply -f nfs-pvc.yaml
persistentvolumeclaim/pvc001 created
[root@master ~]# kubectl get pvc
[root@master ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc001 Bound pv001 1Gi RWX 9s
[root@master ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 1Gi RWX Retain Bound default/pvc001 2m7s
pv002 5Gi RWX Retain Available 2m7s
pv003 10Gi RWX Recycle Available 2m7s
3、創建 Pod 進行掛載
創建 pod 配置文件nfs-pvc-pod.yaml
,內容如下:
apiVersion: v1
kind: Pod
metadata:
name: mypod1
spec:
containers:
- name: mypod1
image: busybox
args:
- /bin/sh
- -c
- sleep 30000
volumeMounts:
- name: mydata
mountPath: "/mydata"
volumes:
- name: mydata
persistentVolumeClaim:
claimName: pvc001
創建pod。
[root@master ~]# kubectl apply -f nfs-pvc-pod.yaml
pod/mypod1 created
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mypod1 1/1 Running 0 17m 10.244.1.16 node01 <none> <none>
驗證 PV 是否可用:
[root@master ~]# kubectl exec mypod1 touch /mydata/hello
然後在node3服務器上面查看。
[root@node03 pv001]# ll
-rw-r--r-- 1 root root 0 12月 13 19:39 hello
可見,在 Pod 中創建的文件 /mydata/hello
確實已經保存到了 NFS 服務器目錄 /data/volumes/pv001
中。
Kubernetes 存儲卷管理 PV&PVC(十)