目錄
PV和PVC之間的相互作用遵循這個生命周期
根據這 5 個階段,PV 的狀態有以下 4 種
一個PV從創建到銷毀的具體流程如下
靜態PV創建
1、配置nfs存儲
2、定義PV
3、定義PVC
4、測試訪問
動態PV創建
1、在stor01節點上安裝nfs,并配置nfs服務
2、創建 Service Account,用來管理 NFS Provisioner 在 k8s 集群中運行的權限,設置 nfs-client 對 PV,PVC,StorageClass 等的規則
3、使用 Deployment 來創建 NFS Provisioner
方法一
方法二
創建 NFS Provisioner
4、創建 StorageClass,負責建立 PVC 并調用 NFS provisioner 進行預定的工作,并讓 PV 與 PVC 建立關聯
5、創建 PVC 和 Pod 測試
PV 全稱叫做 Persistent Volume,持久化存儲卷。它是用來描述或者說用來定義一個存儲卷的,這個通常都是由運維工程師來定義。
PVC 的全稱是 Persistent Volume Claim,是持久化存儲的請求。它是用來描述希望使用什么樣的或者說是滿足什么條件的 PV 存儲。
PVC 的使用邏輯:在 Pod 中定義一個存儲卷(該存儲卷類型為 PVC),定義的時候直接指定大小,PVC 必須與對應的 PV 建立關系,PVC 會根據配置的定義去 PV 申請,而 PV 是由存儲空間創建出來的。PV 和 PVC 是 Kubernetes 抽象出來的一種存儲資源。
上面介紹的PV和PVC模式是需要運維人員先創建好PV,然后開發人員定義好PVC進行一對一的Bond,但是如果PVC請求成千上萬,那么就需要創建成千上萬的PV,對于運維人員來說維護成本很高,Kubernetes提供一種自動創建PV的機制,叫StorageClass,它的作用就是創建PV的模板。
創建 StorageClass 需要定義 PV 的屬性,比如存儲類型、大小等;另外創建這種 PV 需要用到的存儲插件,比如 Ceph 等。 有了這兩部分信息,Kubernetes 就能夠根據用戶提交的 PVC,找到對應的 StorageClass,然后 Kubernetes 就會調用 StorageClass 聲明的存儲插件,自動創建需要的 PV 并進行綁定。
PV是集群中的資源。 PVC是對這些資源的請求,也是對資源的索引檢查。?
PV和PVC之間的相互作用遵循這個生命周期
Provisioning(配置)---> Binding(綁定)---> Using(使用)---> Releasing(釋放) ---> Recycling(回收)
●Provisioning:即 PV 的創建,可以直接創建 PV(靜態方式),也可以使用 StorageClass 動態創建
●Binding:將 PV 分配給 PVC
●Using:Pod 通過 PVC 使用該 Volume,并可以通過準入控制StorageProtection(1.9及以前版本為PVCProtection) 阻止刪除正在使用的 PVC
●Releasing:Pod 釋放 Volume 并刪除 0PVC
●Reclaiming:回收 PV,可以保留 PV 以便下次使用,也可以直接從云存儲中刪除
根據這 5 個階段,PV 的狀態有以下 4 種
●Available(可用):表示可用狀態,還未被任何 PVC 綁定
●Bound(已綁定):表示 PV 已經綁定到 PVC
●Released(已釋放):表示 PVC 被刪掉,但是資源尚未被集群回收
●Failed(失敗):表示該 PV 的自動回收失敗
一個PV從創建到銷毀的具體流程如下
1、一個PV創建完后狀態會變成Available,等待被PVC綁定。
2、一旦被PVC邦定,PV的狀態會變成Bound,就可以被定義了相應PVC的Pod使用。
3、Pod使用完后會釋放PV,PV的狀態變成Released。
4、變成Released的PV會根據定義的回收策略做相應的回收工作。有三種回收策略,Retain、Delete和Recycle。Retain就是保留現場,K8S集群什么也不做,等待用戶手動去處理PV里的數據,處理完后,再手動刪除PV。Delete策略,K8S會自動刪除該PV及里面的數據。Recycle方式,K8S會將PV里的數據刪除,然后把PV的狀態變成Available,又可以被新的PVC綁定使用。
kubectl explain pv ? ?#查看pv的定義方式
FIELDS:apiVersion: v1kind: PersistentVolumemetadata: ? ?#由于 PV 是集群級別的資源,即 PV 可以跨 namespace 使用,所以 PV 的 metadata 中不用配置 namespacename:?spec
kubectl explain pv.spec ? ?#查看pv定義的規格
spec:nfs:(定義存儲類型)path:(定義掛載卷路徑)server:(定義服務器名稱)accessModes:(定義訪問模型,有以下三種訪問模型,以列表的方式存在,也就是說可以定義多個訪問模式)- ReadWriteOnce ? ? ? ? ?#(RWO)卷可以被一個節點以讀寫方式掛載。 ReadWriteOnce 訪問模式也允許運行在同一節點上的多個 Pod 訪問卷。- ReadOnlyMany ? ? ? ? ? #(ROX)卷可以被多個節點以只讀方式掛載。- ReadWriteMany ? ? ? ? ?#(RWX)卷可以被多個節點以讀寫方式掛載。
#nfs 支持全部三種;iSCSI 不支持 ReadWriteMany(iSCSI 就是在 IP 網絡上運行 SCSI 協議的一種網絡存儲技術);HostPath 不支持 ReadOnlyMany 和 ReadWriteMany。capacity:(定義存儲能力,一般用于設置存儲空間)storage: 2Gi (指定大小)storageClassName: (自定義存儲類名稱,此配置用于綁定具有相同類別的PVC和PV)persistentVolumeReclaimPolicy: Retain ? ?#回收策略(Retain/Delete/Recycle)
#Retain(保留):當用戶刪除與之綁定的PVC時候,這個PV被標記為released(PVC與PV解綁但還沒有執行回收策略)且之前的數據依然保存在該PV上,但是該PV不可用,需要手動來處理這些數據并刪除該PV。
#Delete(刪除):刪除與PV相連的后端存儲資源。對于動態配置的PV來說,默認回收策略為Delete。表示當用戶刪除對應的PVC時,動態配置的volume將被自動刪除。(只有 AWS EBS, GCE PD, Azure Disk 和 Cinder 支持)
#Recycle(回收):如果用戶刪除PVC,則刪除卷上的數據,卷不會刪除。(只有 NFS 和 HostPath 支持)
kubectl explain pvc ? #查看PVC的定義方式
KIND: ? ? PersistentVolumeClaim
VERSION: ?v1
FIELDS:apiVersion?? ?<string>kind?? ?<string> ?metadata?? ?<Object>spec?? ?<Object>
#PV和PVC中的spec關鍵字段要匹配,比如存儲(storage)大小、訪問模式(accessModes)、存儲類名稱(storageClassName)
kubectl explain pvc.spec
spec:accessModes: (定義訪問模式,必須是PV的訪問模式的子集)resources:requests:storage: (定義申請資源的大小)storageClassName: (定義存儲類名稱,此配置用于綁定具有相同類別的PVC和PV)
靜態PV創建
1、配置nfs存儲
mkdir z{1,2,3,4,5}
vim /etc/exports
/opt/z1 192.168.110.0/24(rw,no_root_squash)
/opt/z2 192.168.110.0/24(rw,no_root_squash)
/opt/z3 192.168.110.0/24(rw,no_root_squash)
/opt/z4 192.168.110.0/24(rw,no_root_squash)
/opt/z5 192.168.110.0/24(rw,no_root_squash)
exportfs -arvshowmount -e
2、定義PV
?這里定義5個PV,并且定義掛載的路徑以及訪問模式,還有PV劃分的大小。
vim pv-demo.yaml
apiVersion: v1
kind: PersistentVolume
metadata:name: pv001labels:name: pv001
spec:nfs:path: /data/volumes/v1server: 192.168.110.60accessModes: ["ReadWriteMany","ReadWriteOnce"]capacity:storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:name: pv002labels:name: pv002
spec:nfs:path: /data/volumes/v2server: 192.168.110.60accessModes: ["ReadWriteOnce"]capacity:storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:name: pv003labels:name: pv003
spec:nfs:path: /data/volumes/v3server: 192.168.110.60accessModes: ["ReadWriteMany","ReadWriteOnce"]capacity:storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:name: pv004labels:name: pv004
spec:nfs:path: /data/volumes/v4server: 192.168.110.60accessModes: ["ReadWriteMany","ReadWriteOnce"]capacity:storage: 4Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:name: pv005labels:name: pv005
spec:nfs:path: /data/volumes/v5server: 192.168.110.60accessModes: ["ReadWriteMany","ReadWriteOnce"]capacity:storage: 5Gi
kubectl apply -f pv-demo.yaml
kubectl get pv
NAME ? ? ?CAPACITY ? ACCESS MODES ? RECLAIM POLICY ? STATUS ? ? ?CLAIM ? ? STORAGECLASS ? REASON ? ?AGE
pv001 ? ? 1Gi ? ? ? ?RWO,RWX ? ? ? ?Retain ? ? ? ? ? Available ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7s
pv002 ? ? 2Gi ? ? ? ?RWO ? ? ? ? ? ?Retain ? ? ? ? ? Available ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7s
pv003 ? ? 2Gi ? ? ? ?RWO,RWX ? ? ? ?Retain ? ? ? ? ? Available ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7s
pv004 ? ? 4Gi ? ? ? ?RWO,RWX ? ? ? ?Retain ? ? ? ? ? Available ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7s
pv005 ? ? 5Gi ? ? ? ?RWO,RWX ? ? ? ?Retain ? ? ? ? ? Available ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ??? ??? ?7s
3、定義PVC
這里定義了pvc的訪問模式為多路讀寫,該訪問模式必須在前面pv定義的訪問模式之中。定義PVC申請的大小為2Gi,此時PVC會自動去匹配多路讀寫且大小為2Gi的PV,匹配成功獲取PVC的狀態即為Bound
vim pod-vol-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: mypvcnamespace: default
spec:accessModes: ["ReadWriteMany"]resources:requests:storage: 2Gi
---
apiVersion: v1
kind: Pod
metadata:name: pod-vol-pvcnamespace: default
spec:containers:- name: myappimage: ikubernetes/myapp:v1volumeMounts:- name: htmlmountPath: /usr/share/nginx/htmlvolumes:- name: htmlpersistentVolumeClaim:claimName: mypvc
kubectl apply -f pod-vol-pvc.yaml
kubectl get pv
NAME ? ? ?CAPACITY ? ACCESS MODES ? RECLAIM POLICY ? STATUS ? ? ?CLAIM ? ? ? ? ? STORAGECLASS ? REASON ? ?AGE
pv001 ? ? 1Gi ? ? ? ?RWO,RWX ? ? ? ?Retain ? ? ? ? ? Available ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?19m
pv002 ? ? 2Gi ? ? ? ?RWO ? ? ? ? ? ?Retain ? ? ? ? ? Available ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?19m
pv003 ? ? 2Gi ? ? ? ?RWO,RWX ? ? ? ?Retain ? ? ? ? ? Bound ? ? ? default/mypvc ? ? ? ? ? ? ? ? ? ? ? ? ? ?19m
pv004 ? ? 4Gi ? ? ? ?RWO,RWX ? ? ? ?Retain ? ? ? ? ? Available ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?19m
pv005 ? ? 5Gi ? ? ? ?RWO,RWX ? ? ? ?Retain ? ? ? ? ? Available ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?19m
kubectl get pvc
NAME ? ? ?STATUS ? ?VOLUME ? ?CAPACITY ? ACCESS MODES ? STORAGECLASS ? AGE
mypvc ? ? Bound ? ? pv003 ? ? 2Gi ? ? ? ?RWO,RWX ? ? ? ? ? ? ? ? ? ? ? 22s
4、測試訪問
在存儲服務器上創建index.html,并寫入數據,通過訪問Pod進行查看,可以獲取到相應的頁面。
cd /opt/v3/
echo "ggl" > index.html
kubectl get pods -o wide
pod-vol-pvc ? ? ? ? ? ? 1/1 ? ? ? Running ? 0 ? ? ? ? ?3m ? ? ? ?10.244.2.39 ? k8s-node02
curl ?10.244.2.39
ggl
動態PV創建
搭建 StorageClass + nfs-client-provisioner ,實現 NFS 的動態 PV 創建
Kubernetes 本身支持的動態 PV 創建不包括 NFS,所以需要使用外部存儲卷插件分配PV。詳見:https://kubernetes.io/zh/docs/concepts/storage/storage-classes/
卷插件稱為 Provisioner(存儲分配器),NFS 使用的是 nfs-client,這個外部卷插件會使用已經配置好的 NFS 服務器自動創建 PV。
Provisioner:用于指定 Volume 插件的類型,包括內置插件(如 kubernetes.io/aws-ebs)和外部插件(如 external-storage 提供的 ceph.com/cephfs)。
1、在stor01節點上安裝nfs,并配置nfs服務
?
yum install -y rpcbind nfs-utils
mkdir /opt/ycx
chmod 777 /opt/ycx/
vim /etc/exports
/opt/k8s 192.168.110.0/24(rw,no_root_squash,sync)
systemctl restart nfs
2、創建 Service Account,用來管理 NFS Provisioner 在 k8s 集群中運行的權限,設置 nfs-client 對 PV,PVC,StorageClass 等的規則
vim nfs-client-rbac.yaml
#創建 Service Account 賬戶,用來管理 NFS Provisioner 在 k8s 集群中運行的權限
apiVersion: v1
kind: ServiceAccount
metadata:name: nfs-client-provisioner
---
#創建集群角色
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:name: nfs-client-provisioner-clusterrole
rules:- apiGroups: [""]resources: ["persistentvolumes"]verbs: ["get", "list", "watch", "create", "delete"]- apiGroups: [""]resources: ["persistentvolumeclaims"]verbs: ["get", "list", "watch", "update"]- apiGroups: ["storage.k8s.io"]resources: ["storageclasses"]verbs: ["get", "list", "watch"]- apiGroups: [""]resources: ["events"]verbs: ["list", "watch", "create", "update", "patch"]- apiGroups: [""]resources: ["endpoints"]verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
---
#集群角色綁定
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:name: nfs-client-provisioner-clusterrolebinding
subjects:
- kind: ServiceAccountname: nfs-client-provisionernamespace: default
roleRef:kind: ClusterRolename: nfs-client-provisioner-clusterroleapiGroup: rbac.authorization.k8s.io
kubectl apply -f nfs-client-rbac.yaml
3、使用 Deployment 來創建 NFS Provisioner
NFS Provisioner(即 nfs-client),有兩個功能:一個是在 NFS 共享目錄下創建掛載點(volume),另一個則是將 PV 與 NFS 的掛載點建立關聯。
#由于 1.20 版本啟用了 selfLink,所以 k8s 1.20+ 版本通過 nfs provisioner 動態生成pv會報錯,解決方法如下:
vim /etc/kubernetes/manifests/kube-apiserver.yaml
spec:containers:- command:- kube-apiserver- --feature-gates=RemoveSelfLink=false ? ? ? #添加這一行- --advertise-address=192.168.80.20
......
方法一
kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
kubectl delete pods kube-apiserver -n kube-system?
kubectl get pods -n kube-system | grep apiserver
方法二
mv?/etc/kubernetes/manifests/kube-apiserver.yaml /opt
mv /opt/kube-apiserver.yaml?/etc/kubernetes/manifests
創建 NFS Provisioner
vim nfs-client-provisioner.yaml
kind: Deployment
apiVersion: apps/v1
metadata:name: nfs-client-provisioner
spec:replicas: 1selector:matchLabels:app: nfs-client-provisionerstrategy:type: Recreatetemplate:metadata:labels:app: nfs-client-provisionerspec:serviceAccountName: nfs-client-provisioner ? ?? ? ?#指定Service Account賬戶containers:- name: nfs-client-provisionerimage: quay.io/external_storage/nfs-client-provisioner:latestimagePullPolicy: IfNotPresentvolumeMounts:- name: nfs-client-rootmountPath: /persistentvolumesenv:- name: PROVISIONER_NAMEvalue: nfs-storage ? ? ? #配置provisioner的Name,確保該名稱與StorageClass資源中的provisioner名稱保持一致- name: NFS_SERVERvalue: 192.168.110.60 ? ? ? ? #配置綁定的nfs服務器- name: NFS_PATHvalue: /opt/ycx ? ? ? ? ?#配置綁定的nfs服務器目錄volumes: ? ? ? ? ? ? ?#申明nfs數據卷- name: nfs-client-rootnfs:server: 192.168.110.60path: /opt/ycx
kubectl apply -f nfs-client-provisioner.yaml?
kubectl get pod
NAME ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? READY ? STATUS ? ?RESTARTS ? AGE
nfs-client-provisioner-cd6ff67-sp8qd ? 1/1 ? ? Running ? 0 ? ? ? ? ?14s
4、創建 StorageClass,負責建立 PVC 并調用 NFS provisioner 進行預定的工作,并讓 PV 與 PVC 建立關聯
vim nfs-client-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: nfs-client-storageclass
provisioner: nfs-storage ? ? #這里的名稱要和provisioner配置文件中的環境變量PROVISIONER_NAME保持一致
parameters:archiveOnDelete: "false" ? #false表示在刪除PVC時不會對數據目錄進行打包存檔,即刪除數據;為ture時就會自動對數據目錄進行打包存檔,存檔文件以archived開頭
kubectl apply -f nfs-client-storageclass.yaml
kubectl get storageclass
NAME ? ? ? ? ? ? ? ? ? ? ?PROVISIONER ? RECLAIMPOLICY ? VOLUMEBINDINGMODE ? ALLOWVOLUMEEXPANSION ? AGE
nfs-client-storageclass ? nfs-storage ? Delete ? ? ? ? ?Immediate ? ? ? ? ? false ? ? ? ? ? ? ? ? ?43s
5、創建 PVC 和 Pod 測試
vim test-pvc-pod.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: test-nfs-pvc#annotations: volume.beta.kubernetes.io/storage-class: "nfs-client-storageclass" ? ? #另一種SC配置方式
spec:accessModes:- ReadWriteManystorageClassName: nfs-client-storageclass ? ?#關聯StorageClass對象resources:requests:storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:name: test-storageclass-pod
spec:containers:- name: busyboximage: busybox:latestimagePullPolicy: IfNotPresentcommand:- "/bin/sh"- "-c"args:- "sleep 3600"volumeMounts:- name: nfs-pvcmountPath: /mntrestartPolicy: Nevervolumes:- name: nfs-pvcpersistentVolumeClaim:claimName: test-nfs-pvc ? ? ?#與PVC名稱保持一致
kubectl apply -f test-pvc-pod.yaml
PVC 通過 StorageClass 自動申請到空間
kubectl get pvc
NAME ? ? ? ? ? ?STATUS ? VOLUME ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? CAPACITY ? ACCESS MODES ? STORAGECLASS ? ? ? ? ? ? ?AGE
test-nfs-pvc ? Bound ? ?pvc-11670f39-782d-41b8-a842-eabe1859a456 ? 1Gi ? ? ? ?RWX ? ? ? ? ? ?nfs-client-storageclass ? 2s
查看 NFS 服務器上是否生成對應的目錄,自動創建的 PV 會以
${namespace}-${pvcName}-${pvName} 的目錄格式放到 NFS 服務器上
ls /opt/ycx/
default-test-nfs-pvc-pvc-11670f39-782d-41b8-a842-eabe1859a456
進入 Pod 在掛載目錄 /mnt 下寫一個文件,然后查看 NFS 服務器上是否存在該文件
kubectl exec -it test-storageclass-pod sh
/ # cd /mnt/
/mnt # echo 'ggl' > test.txt
發現 NFS 服務器上存在,說明驗證成功
cat /opt/ycx/test.txt
ggl
?