1.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 的細節信息。
2.通過NFS實現持久化存儲
2.1配置nfs
k8s-master nfs-server
k8s-node1 k8s-node2 nfs-client
所有節點安裝nfs
yum install -y nfs-common nfs-utils
在master節點創建共享目錄
[root@k8s-master k8s]# mkdir /nfsdata
授權共享目錄
[root@k8s-master k8s]# chmod 666 /nfsdata
編輯exports文件
[root@k8s-master k8s]# cat /etc/exports /nfsdata *(rw,no_root_squash,no_all_squash,sync)
配置生效
[root@k8s-master k8s]# export -r
啟動rpc和nfs(注意順序)
[root@k8s-master k8s]# systemctl start rpcbind [root@k8s-master k8s]# systemctl start nfs
作為准備工作,我們已經在 k8s-master 節點上搭建了一個 NFS 服務器,目錄為 /nfsdata
:
2.2創建PV
下面創建一個 PV mypv1
,配置文件 nfs-pv1.yml
如下:
① capacity
指定 PV 的容量為 1G。
② 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 等。
④ storageClassName
指定 PV 的 class 為 nfs
。相當於為 PV 設置了一個分類,PVC 可以指定 class 申請相應 class 的 PV。
⑤ 指定 PV 在 NFS 服務器上對應的目錄。
創建 mypv1
:
STATUS
為 Available
,表示 mypv1
就緒,可以被 PVC 申請。
2.3創建PVC
接下來創建 PVC mypvc1
,配置文件 nfs-pvc1.yml
如下:
PVC 就很簡單了,只需要指定 PV 的容量,訪問模式和 class。
執行命令創建 mypvc1
:
從 kubectl get pvc
和 kubectl get pv
的輸出可以看到 mypvc1
已經 Bound 到 mypv1
,申請成功。
2.4創建pod
上面已經創建好了pv和pvc,pod中直接使用這個pvc即可
與使用普通 Volume 的格式類似,在 volumes
中通過 persistentVolumeClaim
指定使用 mypvc1
申請的 Volume。
通過命令創建mypod1
:
2.5驗證
可見,在 Pod 中創建的文件 /mydata/hello
確實已經保存到了 NFS 服務器目錄 /nfsdata
中。
如果不再需要使用 PV,可用刪除 PVC 回收 PV。
3.PV的回收
當 PV 不再需要時,可通過刪除 PVC 回收。
未刪除pvc之前 pv的狀態是Bound
刪除pvc之后pv的狀態變為Available,,此時解除綁定后則可以被新的 PVC 申請。
/nfsdata文件中的文件被刪除了
因為 PV 的回收策略設置為 Recycle
,所以數據會被清除,但這可能不是我們想要的結果。如果我們希望保留數據,可以將策略設置為 Retain
。
通過 kubectl apply
更新 PV:
回收策略已經變為 Retain
,通過下面步驟驗證其效果:
① 重新創建 mypvc1
。
② 在 mypv1
中創建文件 hello
。
③ mypv1
狀態變為 Released
。
④ PV 中的數據被完整保留。
雖然 mypv1
中的數據得到了保留,但其 PV 狀態會一直處於 Released
,不能被其他 PVC 申請。為了重新使用存儲資源,可以刪除並重新創建 mypv1
。刪除操作只是刪除了 PV 對象,存儲空間中的數據並不會被刪除。
新建的 mypv1
狀態為 Available
,已經可以被 PVC 申請。
PV 還支持 Delete
的回收策略,會刪除 PV 在 Storage Provider 上對應存儲空間。NFS 的 PV 不支持 Delete
,支持 Delete
的 Provider 有 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。
4.PV的動態供給
前面的例子中,我們提前創建了 PV,然后通過 PVC 申請 PV 並在 Pod 中使用,這種方式叫做靜態供給(Static Provision)。
與之對應的是動態供給(Dynamical Provision),即如果沒有滿足 PVC 條件的 PV,會動態創建 PV。相比靜態供給,動態供給有明顯的優勢:不需要提前創建 PV,減少了管理員的工作量,效率高。
動態供給是通過 StorageClass 實現的,StorageClass 定義了如何創建 PV,下面是兩個例子。
StorageClass standard
:
StorageClass slow
:
這兩個 StorageClass 都會動態創建 AWS EBS,不同在於 standard
創建的是 gp2
類型的 EBS,而 slow
創建的是 io1
類型的 EBS。不同類型的 EBS 支持的參數可參考 AWS 官方文檔。
StorageClass 支持 Delete
和 Retain
兩種 reclaimPolicy
,默認是 Delete
。
與之前一樣,PVC 在申請 PV 時,只需要指定 StorageClass 和容量以及訪問模式,比如:
除了 AWS EBS,Kubernetes 支持其他多種動態供給 PV 的 Provisioner,完整列表請參考 https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner
5.PV&&PVC在應用在mysql的持久化存儲
下面演示如何為 MySQL 數據庫提供持久化存儲,步驟為:
-
創建 PV 和 PVC。
-
部署 MySQL。
-
向 MySQL 添加數據。
-
模擬節點宕機故障,Kubernetes 將 MySQL 自動遷移到其他節點。
-
驗證數據一致性。
首先創建 PV 和 PVC,配置如下:
mysql-pv.yml
mysql-pvc.yml
創建 mysql-pv
和 mysql-pvc
:
接下來部署 MySQL,配置文件如下:
PVC mysql-pvc
Bound 的 PV mysql-pv
將被 mount 到 MySQL 的數據目錄 var/lib/mysql
。
MySQL 被部署到 k8s-node2
,下面通過客戶端訪問 Service mysql
:
kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -ppassword
更新數據庫:
① 切換到數據庫 mysql。
② 創建數據庫表 my_id。
③ 插入一條數據。
④ 確認數據已經寫入。
關閉 k8s-node2
,模擬節點宕機故障。
驗證數據的一致性:
由於node2節點已經宕機,node1節點接管了這個任務。
通過kubectl run 命令 進入node1的這個pod里,查看數據是否依舊存在
MySQL 服務恢復,數據也完好無損。
6.小結
本章我們討論了 Kubernetes 如何管理存儲資源。
emptyDir 和 hostPath 類型的 Volume 很方便,但可持久性不強,Kubernetes 支持多種外部存儲系統的 Volume。
PV 和 PVC 分離了管理員和普通用戶的職責,更適合生產環境。我們還學習了如何通過 StorageClass 實現更高效的動態供給。
最后,我們演示了如何在 MySQL 中使用 PersistentVolume 實現數據持久性。