PV(PersistentVolume)與PVC(PersistentVolumeClaim)就是在用戶與存儲服務之間添加的一個中間層,管理員事先根據PV支持的存儲卷插件及適配的存儲方案(目標存儲系統)細節定義好可以支撐存儲卷的底層存儲空間,而后由用戶通過PVC聲明要使用的存儲特性來綁定符合條件的最佳PV定義存儲卷,從而實現存儲系統的使用與管理職能的解耦,大大簡化了用戶使用存儲的方式。 PV和PVC的生命周期由Controller Manager中專用的PV控制器(PV Controller)獨立管理,這種機制的存儲卷不再依附並受限於Pod對象的生命周期,從而實現了用戶和集群管理員的職責相分離,也充分體現出Kubernetes把簡單留給用戶,把復雜留給自己的管理理念。
1、PV和PVC基礎
PV是由集群管理員於全局級別配置的預掛載存儲空間,它通過支持的存儲卷插件及給定的配置參數關聯至某個存儲系統上可用數據存儲的一段空間,這段存儲空間可能是Ceph存儲系統上的一個存儲映像、一個文件系統(CephFS)或其子目錄,也可能是NFS存儲系統上的一個導出目錄等。PV將存儲系統之上的存儲空間抽象為Kubernetes系統全局級別的API資源,由集群管理員負責管理和維護。 將PV提供的存儲空間用於Pod對象的存儲卷時,用戶需要事先使用PVC在名稱空間級別聲明所需要的存儲空間大小及訪問模式並提交給Kubernetes API Server,接下來由PV控制器負責查找與之匹配的PV資源並完成綁定。隨后,用戶在Pod資源中使用persistentVolumeClaim類型的存儲卷插件指明要使用的PVC對象的名稱即可使用其綁定到的PV所指向的存儲空間,如圖所示。

這種通過管理員手動創建PV來滿足PVC需求的靜態預配(static provisioning)存在着不少的問題。
第一,集群管理員難以預測出用戶的真實需求,很容易導致某些類型的PVC無法匹配到PV而被掛起,直到管理員參與到問題的解決過程中。
第二,那些能夠匹配到PV的PVC也很有可能存在資源利用率不佳的狀況,例如一個聲明使用5G存儲空間的PVC綁定到一個20GB的PV之上。
PV和PVC是一對一的關系:一個PVC僅能綁定一個PV,而一個PV在某一時刻也僅可被一個PVC所綁定。為了能夠讓用戶更精細地表達存儲需求,PV資源對象的定義支持存儲容量、存儲類、卷模型和訪問模式等屬性維度的約束。相應地,PVC資源能夠從訪問模式、數據源、存儲資源容量需求和限制、標簽選擇器、存儲類名稱、卷模型和卷名稱等多個不同的維度向PV資源發起匹配請求並完成篩選。
2、PV的生命周期
Kubernetes系統與存儲相關的組件主要有存儲卷插件、存儲卷管理器、PV/PVC控制器和AD控制器(Attach/Detach Controller)這4種
▪存儲卷插件:Kubernetes存儲卷功能的基礎設施,是存儲任務相關操作的執行方;它是存儲相關的擴展接口,用於對接各類存儲設備。 ▪存儲卷管理器:kubelet內置管理器組件之一,用於在當前節點上執行存儲設備的掛載(mount)、卸載(unmount)和格式化(format)等操作;另外,存儲卷管理器也可執行節點級別設備的附加(attach)及拆除(detach)操作。 ▪PV控制器:負責PV及PVC的綁定和生命周期管理,並根據需求進行存儲卷的預配和刪除操作; ▪AD控制器:專用於存儲設備的附加和拆除操作的組件,能夠將存儲設備關聯(attach)至目標節點或從目標節點之上剝離(detach)。
除了創建、刪除PV對象,以及完成PV和PVC的狀態遷移等生命周期管理之外,PV控制器還要負責綁定PVC與PV對象,而且PVC只能在綁定到PV之后方可由Pod作為存儲卷使用。創建后未能正確關聯到存儲設備的PV將處於Pending狀態,直到成功關聯后轉為Available狀態。而后一旦該PV被某個PVC請求並成功綁定,其狀態也就順應轉為Bound,直到相應的PVC刪除后而自動解除綁定,PV才會再次發生狀態轉換,此時的狀態為(Released),隨后PV的去向將由其“回收策略”(reclaim policy)所決定,具體如下。
1)Retain(保留):刪除PVC后將保留其綁定的PV及存儲的數據,但會把該PV置為Released狀態,它不可再被其他PVC所綁定,且需要由管理員手動進行后續的回收操作:首先刪除PV,接着手動清理其關聯的外部存儲組件上的數據,最后手動刪除該存儲組件或者基於該組件重新創建PV。 2)Delete(刪除):對於支持該回收策略的卷插件,刪除一個PVC將同時刪除其綁定的PV資源以及該PV關聯的外部存儲組件;動態的PV回收策略繼承自StorageClass資源,默認為Delete。多數情況下,管理員都需要根據用戶的期望修改此默認策略,以免導致數據非計划內的刪除。 3)Recycle(回收):對於支持該回收策略的卷插件,刪除PVC時,其綁定的PV所關聯的外部存儲組件上的數據會被清空,隨后,該PV將轉為Available狀態,可再次接受其他PVC的綁定請求。不過,該策略已被廢棄。
相應地,創建后的PVC也將處於Pending狀態,僅在遇到條件匹配、狀態為Available的PV,且PVC請求綁定成功才會轉為Bound狀態。PV和PVC的狀態遷移如圖所示。總結起來,PV和PVC的生命周期存在以幾個關鍵階段。

1)存儲預配(provision):存儲預配是指為PVC准備PV的途徑,Kubernetes支持靜態和動態兩種PV預配方式,前者是指由管理員以手動方式創建PV的操作,而后者則是由PVC基於StorageClass定義的模板,按需請求創建PV的機制。 2)存儲綁定:用戶基於一系列存儲需求和訪問模式定義好PVC后,PV控制器即會為其查找匹配的PV,完成關聯后它們二者同時轉為已綁定狀態,而且動態預配的PV與PVC之間存在強關聯關系。無法找到可滿足條件的PV的PVC將一直處於Pending狀態,直到有符合條件的PV出現並完成綁定為止。 3)存儲使用:Pod資源基於persistenVolumeClaim存儲卷插件的定義,可將選定的PVC關聯為存儲卷並用於內部容器應用的數據存取。 4)存儲回收:存儲卷的使用目標完成之后,刪除PVC對象可使得此前綁定的PV資源進入Released狀態,並由PV控制器根據PV回收策略對PV作出相應的處置。目前,可用的回收策略有Retaine、Delete和Recycle這3種。
3、靜態PV資源
PersistentVolume是隸屬於Kubernetes核心API群組中的標准資源類型,它的目標在於通過存儲卷插件機制,將支持的外部存儲系統上的存儲組件定義為可被PVC聲明所綁定的資源對象。但PV資源隸屬於Kubernetes集群級別,因而它只能由集群管理員進行創建。這種由管理員手動定義和創建的PV被人們習慣地稱為靜態PV資源。 PV支持的存儲卷插件類型是Pod對象支持的存儲卷插件類型的一個子集,它僅涵蓋Pod支持的網絡存儲卷類別中的所有存儲插件以及local卷插件。除了存儲卷插件之外,PersistentVolume資源規范Spec字段主要支持嵌套以下幾個通用字段,它們用於定義PV的容量、訪問模式和回收策略等屬性。
▪capacity <map[string]string>:指定PV的容量;目前,Capacity僅支持存儲容量設定,將來應該還可以指定IOPS和吞吐量(throughput)。 ▪accessModes <[]string>:指定當前PV支持的訪問模式;存儲系統支持的存取能力大體可分為ReadWriteOnce(單路讀寫)、ReadOnlyMany(多路只讀)和ReadWrite-Many(多路讀寫)3種類型,某個特定的存儲系統可能會支持其中的部分或全部的能力。 ▪persistentVolumeReclaimPolicy <string>:PV空間被釋放時的處理機制;可用類型僅為Retain(默認)、Recycle或Delete。目前,僅NFS和hostPath支持Recycle策略,也僅有部分存儲系統支持Delete策略。 ▪volumeMode <string>:該PV的卷模型,用於指定此存儲卷被格式化為文件系統使用還是直接使用裸格式的塊設備;默認值為Filesystem,僅塊設備接口的存儲系統支持該功能。 ▪storageClassName <string>:當前PV所屬的StorageClass資源的名稱,指定的存儲類需要事先存在;默認為空值,即不屬於任何存儲類。 ▪mountOptions <string>:掛載選項組成的列表,例如ro、soft和hard等。 ▪nodeAffinity <Object>:節點親和性,用於限制能夠訪問該PV的節點,進而會影響與該PV關聯的PVC的Pod的調度結果。
需要注意的是,PV的訪問模式用於反映它關聯的存儲系統所支持的某個或全部存取能力,例如NFS存儲系統支持以上3種存取能力,於是NFS PV可以僅支持ReadWriteOnce訪問模式。需要注意的是,PV在某個特定時刻僅可基於一種模式進行存取,哪怕它同時支持多種模式。
下面的配置示例來自於pv-nfs-demo.yaml資源清單,它定義了一個使用NFS存儲系統的PV資源,它將空間大小限制為5GB,並支持多路的讀寫操作。
apiVersion: v1 kind: PersistentVolume metadata: name: pv-nfs-demo spec: capacity: storage: 5Gi volumeMode: Filesystem accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain mountOptions: - hard - nfsvers=4.1 nfs: path: "/data/k8s_pv" server: 172.168.32.201
在NFS服務器172.168.32.201上導出/data/k8s_pv目錄后.
NFS導出/data/k8s_pv root@harbor:~# mkdir /data/k8s_pv root@harbor:~# exportfs -avr root@harbor:~# cat /etc/exports /data/redis_data *(rw,no_root_squash) /data/k8s_pv *(rw,no_root_squash) root@harbor:~# expo root@harbor:~# showmount -e 172.168.33.201 Export list for 172.168.33.201: /data/k8s_pv * /data/redis_data *
可使用如下命令創建該PV資源
root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl apply -f pv-nfs-demo.yaml persistentvolume/pv-nfs-demo created [root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-nfs-demo 5Gi RWX Retain Available 24s
若能夠正確關聯到指定的后端存儲,該PV對象的狀態將顯示為Available,否則其狀態為Pending,直至能夠正確完成存儲資源關聯或者被刪除。我們同樣可使用describe命令來獲取PV資源的詳細描述信息。
[root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-nfs-demo 5Gi RWX Retain Available 24s root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl describe pv pv-nfs-demo Name: pv-nfs-demo Labels: <none> Annotations: <none> Finalizers: [kubernetes.io/pv-protection] StorageClass: Status: Available Claim: Reclaim Policy: Retain Access Modes: RWX VolumeMode: Filesystem Capacity: 5Gi Node Affinity: <none> Message: Source: Type: NFS (an NFS mount that lasts the lifetime of a pod) Server: 172.168.32.201 Path: /data/k8s_pv ReadOnly: false Events: <none>
2)
apiVersion: v1 kind: PersistentVolume metadata: name: pv-rbd-demo labels: usedof: redisdata spec: capacity: storage: 2Gi accessModes: - ReadWriteOnce rbd: monitors: - 172.168.32.201:6789 - 172.168.32.202:6789 - 172.168.32.203:6789 pool: k8spool image: k8spv user: admin keyring: /etc/ceph/ceph.client.admin.keyring fsType: xfs readOnly: false persistentVolumeReclaimPolicy: Retain
將RBD卷插件內嵌字段相關屬性值設定為Ceph存儲系統的實際的環境,包括監視器地址、存儲池、存儲映像、用戶名和認證信息(keyring或secretRef)等。測試時,請事先部署好Ceph集群,參考RBD存儲卷中設定admin用戶賬號和Kubernetes集群工作節點的方式,准備好基礎環境,並在Ceph集群的管理節點運行如下命令創建用到的存儲映像:
#因為掛載rbd的宿主機因內核版本原因不支持rbd的所有特性,只開啟部分特性 root@ceph01:~# rbd create k8spv --size 20480 --pool k8spool --image-format 2 --image-feature layering #開啟全部特性。注意掛載宿主機的內核版本是否支持rbd的特性功能 #root@ceph01:~# rbd create k8spv --size 20480 --pool k8spool root@ceph01:~# rbd feature disable -p k8spool k8spv object-map fast-diff deep-flatten #在Kubernetes集群的所有節點安裝ceph客戶端(ceph-common) ①把ceph01上的ceph.repo拷貝到Kubernetes的所有node節點 #master節點 root@ceph01:~# scp /etc/apt/sources.list 172.168.33.207:/etc/apt/sources.list root@ceph01:~# scp /etc/apt/sources.list 172.168.33.208:/etc/apt/sources.list root@ceph01:~# scp /etc/apt/sources.list 172.168.33.209:/etc/apt/sources.list #node節點 root@ceph01:~# scp /etc/apt/sources.list 172.168.33.210:/etc/apt/sources.list root@ceph01:~# scp /etc/apt/sources.list 172.168.33.211:/etc/apt/sources.list root@ceph01:~# scp /etc/apt/sources.list 172.168.33.212:/etc/apt/sources.list ②kubernetes各個node節點安裝ceph-common客戶端 root@k8s-master01:~# apt update && apt install -y ceph-common root@k8s-master02:~# apt update && apt install -y ceph-common root@k8s-master03:~# apt update && apt install -y ceph-common root@k8s-node01:~# apt update && apt install -y ceph-common root@k8s-node02:~# apt update && apt install -y ceph-common root@k8s-node03:~# apt update && apt install -y ceph-common 5)把ceph中admin的賬號密碼文件和ceph.conf拷貝到kubernetes的所有node節點上 kubernetes所有的node節點 root@k8s-master01:~# mkdir /etc/ceph root@k8s-master02:~# mkdir /etc/ceph root@k8s-master03:~# mkdir /etc/ceph root@k8s-node01:~# mkdir /etc/ceph root@k8s-node02:~# mkdir /etc/ceph root@k8s-node03:~# mkdir /etc/ceph root@ceph01:~# scp -r /etc/ceph/{ceph.client.admin.keyring,ceph.conf} 172.168.33.207:/etc/ceph root@ceph01:~# scp -r /etc/ceph/{ceph.client.admin.keyring,ceph.conf} 172.168.33.208:/etc/ceph root@ceph01:~# scp -r /etc/ceph/{ceph.client.admin.keyring,ceph.conf} 172.168.33.209:/etc/ceph root@ceph01:~# scp -r /etc/ceph/{ceph.client.admin.keyring,ceph.conf} 172.168.33.210:/etc/ceph root@ceph01:~# scp -r /etc/ceph/{ceph.client.admin.keyring,ceph.conf} 172.168.33.211:/etc/ceph root@ceph01:~# scp -r /etc/ceph/{ceph.client.admin.keyring,ceph.conf} 172.168.33.212:/etc/ceph
6)把ceph的hosts解析拷貝到k8s集群的所有節點的hosts中
待所有准備工作就緒后,即可運行如下命令創建示例清單中定義的PV資源pv-rbd-demo:
root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl apply -f pv-rbd-demo.yaml persistentvolume/pv-rbd-demo created root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-nfs-demo 5Gi RWX Retain Available 19m pv-rbd-demo 2Gi RWO Retain Available 3s
同樣可以使用describe命令了解pv-rbd-demo的詳細描述,若處於Pending狀態則需要詳細檢查存儲卷插件的定義是否能吻合存儲系統的真實環境。
root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl describe pv pv-rbd-demo Name: pv-rbd-demo Labels: usedof=redisdata Annotations: <none> Finalizers: [kubernetes.io/pv-protection] StorageClass: Status: Available Claim: Reclaim Policy: Retain Access Modes: RWO VolumeMode: Filesystem Capacity: 2Gi Node Affinity: <none> Message: Source: Type: RBD (a Rados Block Device mount on the host that shares a pod's lifetime) CephMonitors: [172.168.32.201:6789 172.168.32.202:6789 172.168.32.203:6789] RBDImage: k8spv FSType: xfs RBDPool: k8spool RadosUser: admin Keyring: /etc/ceph/ceph.client.admin.keyring SecretRef: nil ReadOnly: false Events: <none>
使用普通用戶client.k8s來部署pv
#如果使用普通用戶掛載rbd #1)給pool=k8spool創建一個client的k8s用戶,對mon有r權限,對k8spool地址池有rwx權限 root@ceph01:~# ceph auth add client.k8s mon 'allow r' osd 'allow rwx pool=k8spool' added key for client.k8s #2)創建一個名為ceph.client.k8s.keyring的密鑰環文件 root@ceph01:~# ceph auth get client.k8s [client.k8s] key = AQAHWGRh/d+JNxAAHrzplwi8WWjwXc/NGdJeAw== caps mon = "allow r" caps osd = "allow rwx pool=k8spool" exported keyring for client.k8s root@ceph01:~# ceph-authtool --create-keyring ceph.client.k8s.keyring creating ceph.client.k8s.keyring #3)導出client.k8s信息之指定的keyring文件 root@ceph01:~# ceph auth get client.k8s -o ceph.client.k8s.keyring exported keyring for client.k8s root@ceph01:~# cat ceph.client.k8s.keyring [client.k8s] key = AQAHWGRh/d+JNxAAHrzplwi8WWjwXc/NGdJeAw== caps mon = "allow r" caps osd = "allow rwx pool=k8spool" #4)把ceph.client.k8s.keyring和ceph.conf 拷貝到所有的k8s節點 root@ceph01:~# scp -r /etc/ceph/{ceph.client.k8s.keyring,ceph.conf} 172.168.33.207:/etc/ceph root@ceph01:~# scp -r /etc/ceph/{ceph.client.k8s.keyring,ceph.conf} 172.168.33.208:/etc/ceph root@ceph01:~# scp -r /etc/ceph/{ceph.client.k8s.keyring,ceph.conf} 172.168.33.209:/etc/ceph root@ceph01:~# scp -r /etc/ceph/{ceph.client.k8s.keyring,ceph.conf} 172.168.33.210:/etc/ceph root@ceph01:~# scp -r /etc/ceph/{ceph.client.k8s.keyring,ceph.conf} 172.168.33.211:/etc/ceph root@ceph01:~# scp -r /etc/ceph/{ceph.client.k8s.keyring,ceph.conf} 172.168.33.212:/etc/ceph #5)修改pv-rbd-demo.yaml的用戶名和keyring apiVersion: v1 kind: PersistentVolume metadata: name: pv-rbd-demo labels: usedof: redisdata spec: capacity: storage: 2Gi accessModes: - ReadWriteOnce rbd: monitors: - 172.168.32.201:6789 - 172.168.32.202:6789 - 172.168.32.203:6789 pool: k8spool image: k8spv user: k8s keyring: /etc/ceph/ceph.client.k8s.keyring fsType: xfs readOnly: false persistentVolumeReclaimPolicy: Retain #6)運行清單 root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl apply -f pv-rbd-demo.yaml persistentvolume/pv-rbd-demo created root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-rbd-demo 2Gi RWO Retain Available 12s #7)驗證 root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl describe pv pv-rbd-demo Name: pv-rbd-demo Labels: usedof=redisdata Annotations: <none> Finalizers: [kubernetes.io/pv-protection] StorageClass: Status: Available Claim: Reclaim Policy: Retain Access Modes: RWO VolumeMode: Filesystem Capacity: 2Gi Node Affinity: <none> Message: Source: Type: RBD (a Rados Block Device mount on the host that shares a pod's lifetime) CephMonitors: [172.168.32.201:6789 172.168.32.202:6789 172.168.32.203:6789] RBDImage: k8spv FSType: xfs RBDPool: k8spool RadosUser: k8s Keyring: /etc/ceph/ceph.client.k8s.keyring SecretRef: nil ReadOnly: false Events: <none>
這里以pv-rbd-demo.yaml為例
第一步:更具client.k8s的key來創建pv-secret.yaml
#在ceph上用client.k8s的key值來base64編碼 #ceph集群上操作 root@ceph01:~# cat /etc/ceph/ceph.client.k8s.keyring [client.k8s] key = AQAHWGRh/d+JNxAAHrzplwi8WWjwXc/NGdJeAw== caps mon = "allow r" caps osd = "allow rwx pool=k8spool" root@ceph01:~# echo AQAHWGRh/d+JNxAAHrzplwi8WWjwXc/NGdJeAw== | base64 QVFBSFdHUmgvZCtKTnhBQUhyenBsd2k4V1dqd1hjL05HZEplQXc9PQo= #根據上面的base64的編碼值來創建pv-k8s-secret.yaml清單 #在k8s集群上操作 cat > pv-k8s-secret.yaml << EOF apiVersion: v1 kind: Secret metadata: name: pv-k8s-secret data: #Please note this value is client.k8s base64 encoded. # ceph auth get client.k8s | base64 key: QVFBSFdHUmgvZCtKTnhBQUhyenBsd2k4V1dqd1hjL05HZEplQXc9PQo= EOF #創建pv-rbd-secret-demo.yaml清單 cat > pv-rbd-secret-demo.yaml << EOF apiVersion: v1 kind: PersistentVolume metadata: name: pv-rbd-secret-demo labels: usedof: redisdata spec: capacity: storage: 2Gi accessModes: - ReadWriteOnce rbd: monitors: - 172.168.32.201:6789 - 172.168.32.202:6789 - 172.168.32.203:6789 pool: k8spool image: k8spv user: k8s secretRef: name: pv-k8s-secret fsType: xfs readOnly: false persistentVolumeReclaimPolicy: Retain EOF #運行清單 root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl apply -f pv-k8s-secret.yaml secret/pv-k8s-secret created root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl apply -f pv-rbd-secret-demo.yaml persistentvolume/pv-rbd-secret-demo created root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-rbd-demo 2Gi RWO Retain Available 15m pv-rbd-secret-demo 2Gi RWO Retain Available 15s #驗證 root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-rbd-demo 2Gi RWO Retain Available 15m pv-rbd-secret-demo 2Gi RWO Retain Available 15s root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl describe pv pv-rbd-secret-demo Name: pv-rbd-secret-demo Labels: usedof=redisdata Annotations: <none> Finalizers: [kubernetes.io/pv-protection] StorageClass: Status: Available Claim: Reclaim Policy: Retain Access Modes: RWO VolumeMode: Filesystem Capacity: 2Gi Node Affinity: <none> Message: Source: Type: RBD (a Rados Block Device mount on the host that shares a pod's lifetime) CephMonitors: [172.168.32.201:6789 172.168.32.202:6789 172.168.32.203:6789] RBDImage: k8spv FSType: xfs RBDPool: k8spool RadosUser: k8s Keyring: /etc/ceph/keyring SecretRef: &SecretReference{Name:pv-k8s-secret,Namespace:,} ReadOnly: false Events: <none>
4、PVC資源
PersistentVolumeClaim也是Kubernetes系統上標准的API資源類型之一,它位於核心API群組,屬於名稱空間級別。用戶提交新建的PVC資源最初處於Pending狀態,由PV控制器找尋最佳匹配的PV並完成二者綁定后,兩者都將轉入Bound狀態,隨后Pod對象便可基於persistentVolumeClaim存儲卷插件配置使用該PVC對應的持久存儲卷。
▪accessModes <[]string>:PVC的訪問模式;它同樣支持RWO、RWX和ROX這3種模式。 ▪dataSrouces <Object>:用於從指定的數據源恢復該PVC卷,它目前支持的數據源包括一個現存的卷快照對象(snapshot.storage.k8s.io/VolumeSnapshot)、一個既有的PVC對象(PersistentVolumeClaim)或一個既有的用於數據轉存的自定義資源對象(resource/object)。 ▪resources <Object>:聲明使用的存儲空間的最小值和最大值;目前,PVC的資源限定僅支持空間大小一個維度。 ▪selector <Object>:篩選PV時額外使用的標簽選擇器(matchLabels)或匹配條件表達式(matchExpressions ▪storageClassName <string>:該PVC資源隸屬的存儲類資源名稱;指定了存儲類資源的PVC僅能在同一個存儲類下篩選PV資源,否則就只能從所有不具有存儲類的PV中進行篩選。 ▪volumeMode <string>:卷模型,用於指定此卷可被用作文件系統還是裸格式的塊設備;默認值為Filesystem。 ▪volumeName <string>:直接指定要綁定的PV資源的名稱。
下面通過匹配前一節中創建的PV資源的兩個具體示例來說明PVC資源的配置方法,兩個PV資源目前的狀態如下所示,它僅截取了命令結果中的一部分。
root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-nfs-demo 5Gi RWX Retain Available 11s pv-rbd-demo 5Gi RWX Retain Available 3s
下面的配置清單(pvc-nfs-001.yaml)定義了一個名為pvc-nfs-001的PVC資源示例,它僅定義了期望的存儲空間范圍、訪問模式和卷模式以篩選集群上的PV資源。
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-nfs-001 namespace: default spec: accessModes: - ReadWriteMany volumeMode: Filesystem resources: requests: storage: 3Gi limits: storage: 10Gi
顯然,此前創建的兩個PV資源中,pv-nfs-demo能夠完全滿足該PVC的篩選條件,因而創建示例清單中的資源后,它能夠迅速綁定至PV之上,如下面的創建和資源查看命令結果所示。
root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl apply -f pvc-nfs-001.yaml persistentvolumeclaim/pvc-nfs-001 created root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pvc -n default NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc-nfs-001 Bound pv-nfs-demo 5Gi RWX 21s root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-nfs-demo 5Gi RWX Retain Bound default/pvc-nfs-001 3m56s pv-rbd-demo 2Gi RWX Retain Available 3m48s
被PVC資源pvc-demo-0001綁定的PV資源pv-nfs-demo的狀態也將從Available轉為Bound
集群上的PV資源數量很多時,用戶可通過指定多維度的過濾條件來縮小PV資源的篩選范圍,以獲取到最佳匹配
2)
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-rbd-002 namespace: default spec: accessModes: - ReadWriteOnce volumeMode: Filesystem resources: requests: storage: 2Gi limits: storage: 5Gi selector: matchLabels: usedof: redisdata
配置清單中的資源PVC/pvc-rbd-002特地為綁定此前創建的資源PV/pv-rbd-demo而創建,其篩選條件可由該PV完全滿足,因而創建配置清單中的PVC/pvc-rbd-002資源后會即刻綁定於PV/pv-rbd-demo之上,如下面命令的結果所示。
root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl apply -f pvc-rbd-002.yaml persistentvolumeclaim/pvc-rbd-002 created root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc-nfs-001 Bound pv-nfs-demo 5Gi RWX 22m pvc-rbd-002 Bound pv-rbd-demo 5Gi RWX 4s NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-nfs-demo 5Gi RWX Retain Bound default/pvc-nfs-001 26m pv-rbd-demo 5Gi RWX Retain Bound default/pvc-rbd-002 8m24s
3)刪除pvc並手動清理數據並恢復pv
以pvc-rbd-002為例
root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl delete pvc pvc-rbd-002 persistentvolumeclaim "pvc-rbd-002" deleted root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc-nfs-001 Bound pv-nfs-demo 5Gi RWX 24m root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-nfs-demo 5Gi RWX Retain Bound default/pvc-nfs-001 28m pv-rbd-demo 5Gi RWX Retain Released default/pvc-rbd-002 9m28s #pv-rbd-demo為Released狀態無法被其他pvc所綁定 root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl delete pv pv-rbd-demo persistentvolume "pv-rbd-demo" deleted #刪除pv-rbd-demo並重建該pv root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl apply -f pv-rbd-demo.yaml persistentvolume/pv-rbd-demo created root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-nfs-demo 5Gi RWX Retain Bound default/pvc-nfs-001 30m pv-rbd-demo 5Gi RWX Retain Available 5s #pv-rbd-demo的狀態為Available,可以被其他pvc所綁定
PVC資源隸屬名稱空間級別,它僅可被同一名稱空間中的Pod對象通過persistentVolumeClaim插件所引用並作為存儲卷使用,該存儲卷插件可嵌套使用如下兩個字段。
▪claimName:要調用的PVC存儲卷的名稱,PVC卷要與Pod在同一名稱空間中。
▪readOnly:是否強制將存儲卷掛載為只讀模式,默認為false。
下面的配置清單(volumes-pvc-demo.yaml)定義了一個Pod資源,該配置清單中直接使用RBD存儲的Pod資源改為了調用指定的PVC存儲卷。
apiVersion: v1 kind: Pod metadata: name: volumes-pvc-demo namespace: default spec: containers: - name: redis image: redis:alpine imagePullPolicy: IfNotPresent ports: - containerPort: 6379 name: redisport volumeMounts: - mountPath: /data name: redis-rbd-vol volumes: - name: redis-rbd-vol persistentVolumeClaim: claimName: pvc-rbd-0002 #PVC的名稱,必須與pod在同一個名稱空間下。
運行清單
root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl apply -f volumes-pvc-demo.yaml pod/volumes-pvc-demo created root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pod NAME READY STATUS RESTARTS AGE volumes-pvc-demo 1/1 Running 0 28s root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl describe pod volumes-pvc-demo ...... Volumes: redis-rbd-vol: Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) ClaimName: pvc-rbd-002 ReadOnly: false ......
存儲類也是Kubernetes系統上的API資源類型之一,它位於storage.k8s.io群組中。存儲類通常由集群管理員為管理PV資源之便而按需創建的存儲資源類別(邏輯組),例如可將存儲系統按照其性能高低或者綜合服務質量級別分類、依照備份策略分類,甚至直接按管理員自定義的標准分類等。存儲類也是PVC篩選PV時的過濾條件之一,這意味着PVC僅能在其隸屬的存儲類之下找尋匹配的PV資源。不過,Kubernetes系統自身無法理解“類別”到底意味着什么,它僅僅把存儲類中的信息當作PV資源的特性描述使用。

1) StorageClass介紹
StorageClass資源的期望狀態直接與apiVersion、kind和metadata定義在同一級別而無須嵌套在spec字段中,它支持使用的字段包括如下幾個。
▪allowVolumeExpansion <boolean>:是否支持存儲卷空間擴展功能。 ▪allowedTopologies <[]Object>:定義可以動態配置存儲卷的節點拓撲,僅啟用了卷調度功能的服務器才會用到該字段;每個卷插件都有自己支持的拓撲規范,空的拓撲選擇器表示無拓撲限制。 ▪provisioner <string>:必選字段,用於指定存儲服務方(provisioner,或稱為預配器),存儲類要基於該字段值來判定要使用的存儲插件,以便適配到目標存儲系統;Kubernetes內置支持許多的provisioner,它們的名字都以kubernetes.io/為前綴,例如kubernetes.io/glusterfs等。 ▪parameters <map[string]string>:定義連接至指定的provisioner類別下的某特定存儲時需要使用的各相關參數;不同provisioner的可用參數各不相同。 ▪reclaimPolicy <string>:由當前存儲類動態創建的PV資源的默認回收策略,可用值為Delete(默認)和Retain兩個;但那些靜態PV的回收策略則取決於它們自身的定義。 ▪volumeBindingMode <string>:定義如何為PVC完成預配和綁定,默認值為Volume-BindingImmediate;該字段僅在啟用了存儲卷調度功能時才能生效。 ▪mountOptions <[]string>:由當前類動態創建的PV資源的默認掛載選項列表。
下面是一個定義在storageclass-rbd-demo.yaml配置文件中的StorageClass資源清單,它定義了一個以Ceph存儲系統的RBD接口為后端存儲的StorageClass資源storage-ceph-rbd,因此,其存儲預配標識為kubernetes.io/rbd。
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: storage-ceph-rbd annotations: storageclass.kubernetes.io/is-default-class: "true" #設置為默認存儲類 provisioner: kubernetes.io/rbd parameters: monitors: 172.168.32.201:6789,172.168.32.202:6789,172.168.32.203:6789 adminId: admin adminSecretName: admin-storage-secret adminSecretNamespace: default pool: k8spool userId: k8s userSecretName: k8s-storage-secret fsType: ext4 imageFormat: "2" imageFeatures: "layering" reclaimPolicy: Retain
不同的provisioner的parameters字段中可嵌套使用的字段各有不同,上面示例中Ceph RBD存儲服務可使用的各字段及意義如下。
▪monitors <string>:Ceph存儲系統的監視器訪問接口,多個套接字間以逗號分隔。 ▪adminId <string>:有權限在指定的存儲池中創建image的管理員用戶名,默認為admin。 ▪adminSecretName <string>:存儲有管理員賬號認證密鑰的Secret資源名稱。 ▪adminSecretNamespace <string>:管理員賬號相關的Secret資源所在的名稱空間。 ▪pool <string>:Ceph存儲系統的RBD存儲池名稱,默認為rbd。 ▪userId <string>:用於映射RBD鏡像的Ceph用戶賬號,默認同adminId字段。 ▪userSecretName <string>:存儲有用戶賬號認證密鑰的Secret資源名稱。 ▪userSecretNamespace <string>:用戶賬號相關的Secret資源所在的名稱空間。 ▪fsType <string>:存儲映像格式化的文件系統類型,默認為ext4。 ▪imageFormat <string>:存儲映像的格式,其可用值僅有“1”和“2”,默認值為“2”。 ▪imageFeatures <string>:“2”格式的存儲映像支持的特性,目前僅支持layering,默認為空值,並且不支持任何功能。
2)ceph-rbd的動態預配
第一步:創建admin和k8s的secret
與Pod或PV資源上的RBD卷插件配置格式不同的是,StorageClass上的RBD供給者參數不支持使用keyring直接認證到Ceph,它僅能引用Secret資源中存儲的認證密鑰完成認證操作。因而,我們需要先將Ceph用戶admin和kube的認證密鑰分別創建為Secret資源對象。
1)在Ceph管理節點上分別獲取admin的認證密鑰,並經行base64編碼,創建admin-secret.yaml ceph集群對client.admin的key經行base64編碼 root@ceph01:~# cat /etc/ceph/ceph.client.admin.keyring [client.admin] key = AQCNxVlhDfpPBBAALJ1Bn6KOGXKug1GIaBXYVA== caps mds = "allow *" caps mgr = "allow *" caps mon = "allow *" caps osd = "allow *" root@ceph01:~# echo AQCNxVlhDfpPBBAALJ1Bn6KOGXKug1GIaBXYVA== | base64 QVFDTnhWbGhEZnBQQkJBQUxKMUJuNktPR1hLdWcxR0lhQlhZVkE9PQo= #k8s集群創建admin-storage-secret.yaml apiVersion: v1 kind: Secret metadata: name: admin-storage-secret data: #Please note this value is client.k8s base64 encoded. # ceph auth get client.admin | base64 key: QVFDTnhWbGhEZnBQQkJBQUxKMUJuNktPR1hLdWcxR0lhQlhZVkE9PQo= 2)在Ceph管理節點上分別獲取k8s的認證密鑰,並經行base64編碼,創建k8s-storage-secret.yaml root@ceph01:~# cat /etc/ceph/ceph.client.k8s.keyring [client.k8s] key = AQAHWGRh/d+JNxAAHrzplwi8WWjwXc/NGdJeAw== caps mon = "allow r" caps osd = "allow rwx pool=k8spool" root@ceph01:~# echo AQAHWGRh/d+JNxAAHrzplwi8WWjwXc/NGdJeAw== | base64 QVFBSFdHUmgvZCtKTnhBQUhyenBsd2k4V1dqd1hjL05HZEplQXc9PQo= #k8s集群創建k8s-storage-secret.yaml apiVersion: v1 kind: Secret metadata: name: k8s-storage-secret data: #Please note this value is client.k8s base64 encoded. # ceph auth get client.k8s | base64 key: QVFBSFdHUmgvZCtKTnhBQUhyenBsd2k4V1dqd1hjL05HZEplQXc9PQo= 2)在Kubernetes集群管理客戶端上使用kubectl命令創建為Secret資源 root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl apply -f admin-storage-secret.yaml secret/admin-storage-secret created root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl apply -f k8s-storage-secret.yaml secret/k8s-storage-secret created
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: storage-ceph-rbd annotations: storageclass.kubernetes.io/is-default-class: "true" #設置為默認存儲類 provisioner: kubernetes.io/rbd reclaimPolicy: Retain parameters: monitors: 172.168.32.201:6789,172.168.32.202:6789,172.168.32.203:6789 adminId: admin adminSecretName: admin-storage-secret adminSecretNamespace: default pool: k8spool userId: k8s userSecretName: k8s-storage-secret fsType: ext4 imageFormat: "2" imageFeatures: "layering" #1,storageclass.beta.kubernetes.io/is-default-class ##如果設置為true,則為默認的storageclasss。pvc申請存儲,如果沒有指定storageclass,則從默認的storageclass申請。 #2,adminId:ceph客戶端ID,用於在ceph 池中創建映像。默認是 “admin”。 #3,userId:ceph客戶端ID,用於映射rbd鏡像。默認與adminId相同。 #4,imageFormat:ceph rbd鏡像格式,“1” 或者 “2”。默認值是 “1”。 #5,imageFeatures:這個參數是可選的,只能在你將imageFormat設置為 “2” 才使用。 目前支持的功能只是layering。默認是 “",沒有功能打開。
待相關Secret資源准備完成后,將示例清單中的StorageClass資源創建在集群上,即可由PVC或PV資源將其作為存儲類。
root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl apply -f storageclass-rbd-demo.yaml storageclass.storage.k8s.io/storage-ceph-rbd created root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get sc storage-ceph-rbd NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE storage-ceph-rbd (default) kubernetes.io/rbd Retain Immediate false 7s
第三步:創建pvc的模板
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-dyn-rbd-demo namespace: default spec: accessModes: ["ReadWriteOnce"] volumeMode: Filesystem resources: requests: storage: 3Gi storageClassName: storage-ceph-rbd
運行該清單
root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl apply -f pvc-dyn-rbd-demo.yaml persistentvolumeclaim/pvc-dyn-rbd-demo created root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc-dyn-rbd-demo Bound pvc-e6f9c06a-58d6-47ee-8ab1-f2fa5ccc8b4e 3Gi RWO storage-ceph-rbd 4s root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-e6f9c06a-58d6-47ee-8ab1-f2fa5ccc8b4e 3Gi RWO Retain Bound default/pvc-dyn-rbd-demo storage-ceph-rbd 9s
storageclass會自動在ceph中創建pv
root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl describe pvc pvc-dyn-rbd-demo Name: pvc-dyn-rbd-demo Namespace: default StorageClass: storage-ceph-rbd Status: Bound Volume: pvc-e6f9c06a-58d6-47ee-8ab1-f2fa5ccc8b4e #pv信息 Labels: <none> Annotations: pv.kubernetes.io/bind-completed: yes pv.kubernetes.io/bound-by-controller: yes volume.beta.kubernetes.io/storage-provisioner: kubernetes.io/rbd Finalizers: [kubernetes.io/pvc-protection] Capacity: 3Gi Access Modes: RWO VolumeMode: Filesystem Used By: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ProvisioningSucceeded 27m persistentvolume-controller Successfully provisioned volume pvc-e6f9c06a-58d6-47ee-8ab1-f2fa5ccc8b4e using kubernetes.io/rbd
再通過pv的信息來確定是ceph集群中的那個rbd鏡像
root@k8s-master01:/apps/k8s-yaml/pv_pvc# kubectl describe pv pvc-e6f9c06a-58d6-47ee-8ab1-f2fa5ccc8b4e Name: pvc-e6f9c06a-58d6-47ee-8ab1-f2fa5ccc8b4e Labels: <none> Annotations: kubernetes.io/createdby: rbd-dynamic-provisioner pv.kubernetes.io/bound-by-controller: yes pv.kubernetes.io/provisioned-by: kubernetes.io/rbd Finalizers: [kubernetes.io/pv-protection] StorageClass: storage-ceph-rbd Status: Bound Claim: default/pvc-dyn-rbd-demo Reclaim Policy: Retain Access Modes: RWO VolumeMode: Filesystem Capacity: 3Gi Node Affinity: <none> Message: Source: Type: RBD (a Rados Block Device mount on the host that shares a pod's lifetime) CephMonitors: [172.168.32.201:6789 172.168.32.202:6789 172.168.32.203:6789] RBDImage: kubernetes-dynamic-pvc-c8d6a084-d5e3-40dd-8dee-a08e715431d7 #RBD鏡像信息 FSType: ext4 RBDPool: k8spool RadosUser: k8s Keyring: /etc/ceph/keyring SecretRef: &SecretReference{Name:k8s-storage-secret,Namespace:,} ReadOnly: false Events: <none>
查看ceph中的rbd
root@ceph01:~# rbd ls k8spool k8spv k8srbd kubernetes-dynamic-pvc-55511c43-4d7a-416f-a885-609ba252a904 kubernetes-dynamic-pvc-94fff9aa-7d75-48f5-8c7f-339b1e0927ce kubernetes-dynamic-pvc-c8d6a084-d5e3-40dd-8dee-a08e715431d7 #kubectl describe pv kubernetes-dynamic-pvc-cd037207-04ec-4b89-a56a-d852deac21f8 kubernetes-dynamic-pvc-e620a2c1-9c30-4aad-a144-b677a223470a
7、總結
PersistentVolume(PV)是群集中的一塊存儲,由管理員配置或使用存儲類動態配置。 它是集群中的資源,就像節點是集群資源一樣。 PV是容量插件,如Volumes,但其生命周期獨立於使用PV的任何單個pod。 此API對象捕獲存儲實現的詳細信息,包括NFS,iSCSI或特定於雲提供程序的存儲系統
2) 什么是pvc
PersistentVolumeClaim(PVC)是一個持久化存儲卷,我們在創建pod時可以定義這個類型的存儲卷。 它類似於一個pod。 Pod消耗節點資源,PVC消耗PV資源。 Pod可以請求特定級別的資源(CPU和內存)。 pvc在申請pv的時候也可以請求特定的大小和訪問模式(例如,可以一次讀/寫或多次只讀)。
3) pv和pvc的聯系
pv和pvc的生命周期
PV是群集中的資源。 PVC是對這些資源的請求,並且還充當對資源的索賠檢查。 PV和PVC之間的相互作用遵循以下生命周期:
(1)pv的供應方式
可以通過兩種方式配置PV:靜態或動態。
靜態的
集群管理員創建了許多PV。它們包含可供群集用戶使用的實際存儲的詳細信息。它們存在於Kubernetes API中,可供使用。
動態的
當管理員創建的靜態PV都不匹配用戶的PersistentVolumeClaim時,群集可能會嘗試為PVC專門動態配置卷。此配置基於StorageClasses:PVC必須請求存儲類,管理員必須已創建並配置該類,以便進行動態配置。
(2)綁定
用戶創建pvc並指定需要的資源和訪問模式。在找到可用pv之前,pvc會保持未綁定狀態
(3)使用
a)需要找一個存儲服務器,把它划分成多個存儲空間;
b)k8s管理員可以把這些存儲空間定義成多個pv;
c)在pod中使用pvc類型的存儲卷之前需要先創建pvc,通過定義需要使用的pv的大小和對應的訪問模式,找到合適的pv;
d)pvc被創建之后,就可以當成存儲卷來使用了,我們在定義pod時就可以使用這個pvc的存儲卷
e)pvc和pv它們是一一對應的關系,pv如果被被pvc綁定了,就不能被其他pvc使用了;
f)我們在創建pvc的時候,應該確保和底下的pv能綁定,如果沒有合適的pv,那么pvc就會處於pending狀態。
(4)回收策略
當我們創建pod時如果使用pvc做為存儲卷,那么它會和pv綁定,當刪除pod,pvc和pv綁定就會解除,解除之后和pvc綁定的pv卷里的數據需要怎么處理,目前,卷可以保留,回收或刪除
Retain
Recycle (不推薦使用,1.15可能被廢棄了)
Delete
· Retain
當刪除pvc的時候,pv仍然存在,處於released狀態,但是它不能被其他pvc綁定使用,里面的數據還是存在的,當我們下次再使用的時候,數據還是存在的,這個是默認的回收策略,管理員能夠通過下面的步驟手工回收存儲卷:
1)刪除PV:在PV被刪除后,在外部設施中相關的存儲資產仍然還在;
2)手工刪除遺留在外部存儲中的數據;
3)手工刪除存儲資產,如果需要重用這些存儲資產,則需要創建新的PV。
· Delete
刪除pvc時即會從Kubernetes中移除PV,也會從相關的外部設施中刪除存儲資產,例如AWS EBS, 或者Cinder存儲卷。
數據卷的缺點: 1、當有多個存儲服務器時,數據卷不利於應用者使用 2、所有存儲服務器信息暴露給應用者,安全性降低 3、數據卷存儲這塊配置更具有專業性
數據持久卷的問題: Q1:pv與pvc是什么關系? A:一對一關系 Q2:pv與pvc怎么匹配的? A:默認使用容量和訪問模式進行匹配 Q3:pv的容量能限制實際的存儲容量? A:取決於后端存儲 Q4:容量匹配策略 A:如果申請的容量,pv沒有正好的,會分配接近最大的那個pv,如果都滿足不了,pod處於pending
配置回收策略: persistentVolumeReclaimPolicy: Recycle
4) 訪問模式
PersistentVolume 卷可以用資源提供者所支持的任何方式掛載到宿主系統上。 如下表所示,提供者(驅動)的能力不同,每個 PV 卷的訪問模式都會設置為 對應卷所支持的模式值。 例如,NFS 可以支持多個讀寫客戶,但是某個特定的 NFS PV 卷可能在服務器 上以只讀的方式導出。每個 PV 卷都會獲得自身的訪問模式集合,描述的是 特定 PV 卷的能力。
訪問模式有:
-
ReadWriteOnce -- 卷可以被一個節點以讀寫方式掛載;
-
ReadOnlyMany -- 卷可以被多個節點以只讀方式掛載;
-
ReadWriteMany -- 卷可以被多個節點以讀寫方式掛載。
在命令行接口(CLI)中,訪問模式也使用以下縮寫形式:
-
RWO - ReadWriteOnce
-
ROX - ReadOnlyMany
-
RWX - ReadWriteMany
重要提醒! 每個卷只能同一時刻只能以一種訪問模式掛載,即使該卷能夠支持 多種訪問模式。例如,一個 GCEPersistentDisk 卷可以被某節點以 ReadWriteOnce 模式掛載,或者被多個節點以 ReadOnlyMany 模式掛載,但不可以同時以兩種模式 掛載。
5) STATUS(狀態)
一個PV 的生命周期中,可能會處於4中不同的階段: •Available(可用):表示可用狀態,還未被任何PVC 綁定 •Bound(已綁定):表示PV 已經被PVC 綁定 •Released(已釋放):PVC 被刪除,但是資源還未被集群重新聲明 •Failed(失敗):表示該PV 的自動回收失敗
6) pod、pvc和pv的關系
PersistentVolume(PV)是指由集群管理員配置提供的某存儲系統上的一段存儲空間,它是對底層共享存儲的抽象,將共享存儲作為一種可由用戶申請使用的資源,實現了“存儲消費”機制。通過存儲插件機制,PV支持使用多種網絡存儲系統或雲端存儲等多種后端存儲系統,例如,前面使用的NFS、RBD和Cinder等。PV是集群級別的資源,不屬於任何名稱空間,用戶對PV資源的使用需要通過PersistentVolumeClaim(PVC)提出的使用申請(或稱為聲明)來完成綁定,是PV資源的消費者,它向PV申請特定大小的空間及訪問模式(如rw或ro),從而創建出PVC存儲卷,而后再由Pod資源通過PersistentVolumeClaim存儲卷關聯使用

8.1 pv的動態供給介紹
存儲類(storage class)是Kubernetes資源類型的一種,它是由管理員為管理PV之便而按需創建的類別(邏輯組),例如可按存儲系統的性能高低分類,或者根據其綜合服務質量級別進行分類、依照備份策略分類,甚至直接按管理員自定義的標准進行分類等。不過,Kubernetes自身無法理解“類別”到底意味着什么,它僅僅是將這些當作PV的特性描述。
存儲類的好處之一便是支持PV的動態創建。用戶用到持久性存儲時,需要通過創建PVC來綁定匹配的PV,此類操作需求量較大,或者當管理員手動創建的PV無法滿足PVC的所有需求時,系統按PVC的需求標准動態創建適配的PV會為存儲管理帶來極大的靈活性。 存儲類對象的名稱至關重要,它是用戶調用的標識。創建存儲類對象時,除了名稱之外,還需要為其定義三個關鍵字段:provisioner、parameter和reclaimPolicy。

動態PV供給的啟用,需要事先由管理員創建至少一個存儲類,不同的Provisoner的創建方法各有不同。另外,並非所有的存儲卷插件都由Kubernetes內建支持PV動態供給功能。
K8s默認不支持NFS動態供給,需要單獨部署社區開發的插件。 項目地址:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
下載https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/tree/master/deploy中的class.ymal,rbac.ymal及deployment.yaml
[root@k8s-master01 nfs-subdir-external-provisioner]# pwd /apps/nfs-subdir-external-provisioner [root@k8s-master01 nfs-subdir-external-provisioner]# ll total 12 -rw-r--r-- 1 root root 255 Apr 18 21:33 class.yaml #創建存儲類 -rw-r--r-- 1 root root 1066 Apr 18 21:34 deployment.yaml #部署插件,需修改里面NFS服務器地址與共享目錄及pod鏡像地址 -rw-r--r-- 1 root root 1819 Apr 18 21:33 rbac.yaml #授權訪問apiserver [root@k8s-master01 nfs-subdir-external-provisioner]# kubectl apply -f class.yaml storageclass.storage.k8s.io/managed-nfs-storage created [root@k8s-master01 nfs-subdir-external-provisioner]# kubectl apply -f deployment.yaml deployment.apps/nfs-client-provisioner created You have new mail in /var/spool/mail/root [root@k8s-master01 nfs-subdir-external-provisioner]# kubectl apply -f rbac.yaml serviceaccount/nfs-client-provisioner created clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created [root@k8s-master01 nfs-subdir-external-provisioner]# kubectl get sc,pod -o wide NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE storageclass.storage.k8s.io/managed-nfs-storage k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 12m NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/nfs-client-provisioner-64c54cf68d-fvn2j 1/1 Running 0 48s 10.244.58.245 k8s-node02 <none> <none>
2、創建pvc時指定存儲類名稱,並指定空間大小
[root@k8s-master01 apps]# vim pvc-sc.yml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: test-claim spec: #storageclass的名稱 storageClassName: "managed-nfs-storage" #訪問模式 accessModes: - ReadWriteMany #資源大小 resources: requests: storage: 1Gi [root@k8s-master01 apps]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE test-claim Bound pvc-387ffb9f-d471-4310-9cef-3bb27d2775e4 1Gi RWX managed-nfs-storage 36s #已經動態綁定了pv
3、配置pod並調用storageclass
[root@k8s-master01 apps]# vim pod-sc.yml apiVersion: v1 kind: Pod metadata: name: test-pod spec: containers: - name: test-pod image: nginx volumeMounts: - name: nfs-pvc mountPath: "/usr/share/nginx/html" volumes: - name: nfs-pvc persistentVolumeClaim: claimName: test-claim #調用pvc [root@k8s-master01 apps]# kubectl apply -f pod-sc.yml pod/test-pod created [root@k8s-master01 apps]# kubectl get pod NAME READY STATUS RESTARTS AGE nfs-client-provisioner-64c54cf68d-fvn2j 1/1 Running 0 11m test-pod 1/1 Running 0 28s [root@k8s-master01 apps]# kubectl get pod test-pod 。。。。。。 Mounts: /usr/share/nginx/html from nfs-pvc (rw) /var/run/secrets/kubernetes.io/serviceaccount from default-token-4zscw (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: nfs-pvc: Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) ClaimName: test-claim ReadOnly: false 。。。。。。 #pvc已經被pod掛載 #在harbor:192.168.32.41上查看nfs服務器,發現已經創建了pv目錄 [root@harbor ~]# cd /ifs/kubernetes/default-test-claim-pvc-387ffb9f-d471-4310-9cef-3bb27d2775e4/ [root@harbor default-test-claim-pvc-387ffb9f-d471-4310-9cef-3bb27d2775e4]#ll total 0 [root@harbor default-test-claim-pvc-387ffb9f-d471-4310-9cef-3bb27d2775e4]# #進入pod [root@k8s-master01 apps]# kubectl exec -it test-pod -- bash root@test-pod:/# ls /usr/share/nginx/html/ root@test-pod:/# #在nfs上創建aa.log文件 [root@harbor default-test-claim-pvc-387ffb9f-d471-4310-9cef-3bb27d2775e4]# touch aa.log [root@harbor default-test-claim-pvc-387ffb9f-d471-4310-9cef-3bb27d2775e4]# ll total 0 -rw-r--r-- 1 root root 0 Apr 18 22:03 aa.log #在pod中查看 root@test-pod:/# ls /usr/share/nginx/html/ aa.log #pod已經有在nfs上創建的文件aa.log
4、刪除pod
[root@k8s-master01 apps]# kubectl delete -f pod-sc.yml pod "test-pod" deleted [root@k8s-master01 apps]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE test-claim Bound pvc-387ffb9f-d471-4310-9cef-3bb27d2775e4 1Gi RWX managed-nfs-storage 13m #刪除了pod,不會影響pvc
5、刪除pvc
[root@k8s-master01 apps]# kubectl delete -f pvc-sc.yml persistentvolumeclaim "test-claim" deleted [root@k8s-master01 apps]# kubectl get pvc No resources found in default namespace. #在nfs上查看 [root@harbor ~]# ll /ifs/kubernetes/ total 0 #可以發現,nfs上的pv目錄隨這pvc的刪除也被刪除 #為了數據的安全會修改class.yaml中 archiveOnDelete參數,設置為"true",當pvc被刪除后,nfs上的pv目錄會有備份,數據會保留 apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: managed-nfs-storage provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME' parameters: archiveOnDelete: "true" [root@k8s-master01 nfs-subdir-external-provisioner]# kubectl delete -f class.yaml storageclass.storage.k8s.io "managed-nfs-storage" deleted [root@k8s-master01 nfs-subdir-external-provisioner]# kubectl apply -f class.yaml storageclass.storage.k8s.io/managed-nfs-storage created #重新創建pvc后,再刪除PVC [root@k8s-master01 apps]# kubectl apply -f pvc-sc.yml persistentvolumeclaim/test-claim created [root@k8s-master01 apps]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE test-claim Bound pvc-8b5e4ae4-a3a2-4377-a87d-a49171bae36c 1Gi RWX managed-nfs-storage 4s #nfs上有pv目錄 [root@harbor ~]# ll /ifs/kubernetes/default-test-claim-pvc-8b5e4ae4-a3a2-4377-a87d-a49171bae36c/ total 0 #刪除pvc [root@k8s-master01 apps]# kubectl delete -f pvc-sc.yml persistentvolumeclaim "test-claim" deleted [root@k8s-master01 apps]# kubectl get pvc No resources found in default namespace. #nfs上會有pv的備份 [root@harbor ~]# ll /ifs/kubernetes/archived-default-test-claim-pvc-8b5e4ae4-a3a2-4377-a87d-a49171bae36c/ total 0


