K8S 的 存儲卷 volumes
emptyDir可實現Pod中的容器之間共享目錄數據,但emptyDir存儲卷沒有持久化數據的能力,存儲卷會隨著Pod生命周期結束而一起刪除
(一個pod中創建了docker1 docker2兩個容器,他們都掛載這個emptyDir,就能實現pod內容器間數據互通)
hostPath
將Node節點(宿主機)上的目錄/文件掛載到Pod容器的指定目錄中,有持久化數據的能力,但只能在單個Node節點上持久化數據,不能實現跨Node節點的Pod共享數據
(pod1在node1上生成,則掛載node1的宿主機卷,若重啟后又調度到node2,則掛載node2的宿主機卷。pod只是單純的掛載所在宿主機的目錄)
NFS
使用NFS服務將存儲卷掛載到Pod容器的指定目錄中,有持久化數據的能力,且也能實現跨Node節點的Pod共享數據
(由于NFS是網絡文件系統,pod1 pod2掛載同一個NFS,最終的文件都會寫入到NFS服務器中,實現跨pod資源共享)
PV PVC
PV:K8S在指定存儲設備空間中邏輯劃分創建的可持久化的存儲資源對象
PVC:是對PV資源對象的請求和綁定,也是Pod能掛載使用的一種存儲卷類型
?
容器磁盤上的文件的生命周期是短暫的,這就使得在容器中運行重要應用時會出現一些問題。首先,當容器崩潰時,kubelet 會重啟它,但是容器中的文件將丟失——容器以干凈的狀態(鏡像最初的狀態)重新啟動。其次,在Pod中同時運行多個容器時,這些容器之間通常需要共享文件。Kubernetes 中的Volume抽象就很好的解決了這些問題。Pod中的容器通過Pause容器共享Volume。
EmptyDir存儲卷
當Pod被分配給節點時,首先創建emptyDir卷,并且只要該Pod在該節點上運行,該卷就會存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以讀取和寫入emptyDir卷中的相同文件,盡管該卷可以掛載到每個容器中的相同或不同路徑上。當出于任何原因從節點中刪除 Pod 時,emptyDir中的數據將被永久刪除。
mkdir /opt/volumes cd /opt/volumesvim pod-emptydir.yamlapiVersion: v1 kind: Pod metadata:name: pod-emptydirnamespace: defaultlabels:app: myapptier: frontend spec:containers:- name: myapp #容器1 掛載同一個emptyDir 與容器2實現共享image: nginximagePullPolicy: IfNotPresentports:- name: httpcontainerPort: 80volumeMounts: #容器掛載數據卷- name: htmldir #使用的存儲卷名稱,如果跟下面volume字段name值相同,則表示使用volume的這個存儲卷mountPath: /usr/share/nginx/html/ #掛載至容器中哪個目錄(這里是nginx的網頁文件夾。容器2進行emptyDir寫入后 容器1即可共享使用)- name: busybox #容器2 掛載同一個emptyDir 與容器1實現共享image: busybox:latestimagePullPolicy: IfNotPresentvolumeMounts: #在容器內定義掛載存儲名稱和掛載路徑- name: htmldir #與下面定義的存儲卷name需要相同mountPath: /data/ #容器2將emptyDir掛載到/data/。雖然與容器1掛載的目錄不同,但是本質上都是寫入的emptyDir存儲設備。掛載點不同并不影響emptyDir內的文件結構,容器2的/data/與容器1的/usr/share/nginx/html/看到的是一樣的文件command: ['/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done'] #容器2的默認執行命令。這里是為了向掛載的emptyDir內寫入index.html文件內容,實驗emptyDir的容器文件共享。(容器2寫入網頁文件,容器1 nginx即可使用網頁文件)#定義存儲卷 與containers容器同一級。在containers定義掛載這個存儲卷volumes:- name: htmldir #定義存儲卷名稱emptyDir: {} #定義存儲卷類型
kubectl apply -f pod-emptydir.yaml
kubectl get pods -o wideNAME ? ? ? ? ? READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? ? ? ?NODE ? ? NOMINATED NODE ? READINESS GATES pod-emptydir ? 2/2 ? ? Running ? 0 ? ? ? ? ?36s ? 10.244.2.19 ? node02 ? <none> ? ? ? ? ? <none>
//在上面定義了2個容器,其中一個容器是輸入日期到index.html中,然后驗證訪問nginx的html是否可以獲取日期。以驗證兩個容器之間掛載的emptyDir實現共享。
curl 10.244.2.19Thu May 27 18:17:11 UTC 2021 Thu May 27 18:17:13 UTC 2021 Thu May 27 18:17:15 UTC 2021 Thu May 27 18:17:17 UTC 2021 Thu May 27 18:17:19 UTC 2021 Thu May 27 18:17:21 UTC 2021 Thu May 27 18:17:23 UTC 2021
HostPath存儲卷
hostPath卷將 node 節點的文件系統中的文件或目錄掛載到集群中。
hostPath可以實現持久存儲,但是在node節點故障時,也會導致數據的丟失。?//在 node01 節點上創建掛載目錄(測試hostpath掛載方式,因為hostpath只是pod簡單掛載宿主機的目錄,并不能做到多宿主機的數據互通。即為在pod生成在node1上就掛載node1的目錄,生成在node2就掛載node2的目錄。)
mkdir -p /data/pod/volume1 echo 'node01.xue.com' > /data/pod/volume1/index.html
//在 node02 節點上創建掛載目錄(測試hostpath掛載方式,因為hostpath只是pod簡單掛載宿主機的目錄,并不能做到多宿主機的數據互通。即為在pod生成在node1上就掛載node1的目錄,pod生成在node2就掛載node2的目錄。)
mkdir -p /data/pod/volume1 echo 'node02.xue.com' > /data/pod/volume1/index.html
//創建 Pod 資源
vim pod-hostpath.yamlapiVersion: v1 kind: Pod metadata:name: pod-hostpathnamespace: default spec:containers:- name: myappimage: nginxvolumeMounts: #掛載數據卷- name: htmldir #使用的存儲卷名稱,如果跟下面volume字段name值相同,則表示使用volume的這個存儲卷mountPath: /usr/share/nginx/html #掛載至容器中哪個目錄readOnly: false #讀寫掛載方式,默認為讀寫模式false#volumes字段定義了paues容器關聯的宿主機或分布式文件系統存儲卷volumes:- name: htmldir #存儲卷名稱hostPath: #hostPath方式path: /data/pod/volume1 #在宿主機上目錄的路徑type: DirectoryOrCreate #定義類型,這表示如果宿主機沒有此目錄則會自動創建
kubectl apply -f pod-hostpath.yaml
//訪問測試
kubectl get pods -o wideNAME ? ? ? ? ? READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? ? ? ?NODE ? ? NOMINATED NODE ? READINESS GATES pod-hostpath ? 2/2 ? ? Running ? 0 ? ? ? ? ?37s ? 10.244.2.35 ? node02 ? <none> ? ? ? ? ? <none>
curl 10.244.2.35node02.xue.com 由于pod現在調度到node2上。就掛載了node2宿主機的目錄、
//刪除pod,再重建,依舊可以訪問原來的內容,實現持久化(不過pod此時還是調度在在node2 掛載的是node2的宿主機目錄)
kubectl delete -f pod-hostpath.yaml ? kubectl apply -f pod-hostpath.yaml?
kubectl get pods -o wideNAME ? ? ? ? ? READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? ? ? ?NODE ? ? NOMINATED NODE ? READINESS GATES pod-hostpath ? 2/2 ? ? Running ? 0 ? ? ? ? ?36s ? 10.244.2.37 ? node02 ? <none> ? ? ? ? ? <none>
curl ?10.244.2.37?node02.xue.com
?//刪除pod,再重建,直到pod被調度到node1上
kubectl delete -f pod-hostpath.yaml ? kubectl apply -f pod-hostpath.yaml?
kubectl get pods -o wideNAME ? ? ? ? ? READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? ? ? ?NODE ? ? NOMINATED NODE ? READINESS GATES pod-hostpath ? 2/2 ? ? Running ? 0 ? ? ? ? ?36s ? 10.244.2.38 ? node01 ? <none> ? ? ? ? ? <none>
curl ?10.244.2.38node01.xue.com 由于pod現在調度到node1上。就掛載了node1宿主機的目錄、
NFS共享存儲卷?
選取一個節點做NFS存儲。(stor01 192.168.80.110)安裝并配置NFS服務。提供給pod通過網絡掛載文件系統。
生成并授權NFS分享的目錄 mkdir /data/volumes -p chmod 777 /data/volumes
更改NFS配置分享給192.168.80.0網段的主機 vim /etc/exports/data/volumes 192.168.80.0/24(rw,no_root_squash)
啟動rpcbind(NFS的依賴項)和NFS systemctl start rpcbind systemctl start nfs
查看掛載情況(分享情況) showmount -eExport list for stor01:/data/volumes 192.168.80.0/24
//master節點操作 創建pod并設置掛載NFS文件系統vim pod-nfs-vol.yamlapiVersion: v1 kind: Pod metadata:name: pod-vol-nfsnamespace: default spec:containers:- name: myappimage: nginxvolumeMounts: #掛載存儲卷- name: htmldir #存儲卷名。與volume創建的存儲卷name需要保持一致mountPath: /usr/share/nginx/html #將存儲卷掛載到pod內的指定目錄(這里指定的是下面設定的NFS服務器的/data/volumes,掛載到pod中的/usr/share/nginx/html目錄)volumes: #創建存儲卷- name: htmldir #存儲卷名稱nfs: #NFS方式path: /data/volumes #nfs服務器分享的文件夾#server: stor01 #nfs服務器名。需要做host主機名與IP映射,否則無法解析。可直接指定IPserver: 192.168.80.110 #nfs服務器IP
kubectl apply -f pod-nfs-vol.yaml
kubectl get pods -o wideNAME ? ? ? ? ? ? ? ? ? ? READY ? ? STATUS ? ?RESTARTS ? AGE ? ? ? IP ? ? ? ? ? ?NODE pod-vol-nfs ? ? ? ? ? ? ?1/1 ? ? ? Running ? 0 ? ? ? ? ?21s ? ? ? 10.244.2.38 ? node02
//在nfs服務器上創建index.html(用于讓pod共享訪問)cd /data/volumes vim index.html<h1> nfs stor01</h1>
//master節點操作(pod由于掛載了這個NFS所以可以訪問NFS服務器上這個網頁文件,通過nginx發布網頁)
curl 10.244.2.38<h1> nfs stor01</h1>
? #刪除nfs相關pod,再重新創建,可以發現無論在pod調度在node1上還是在node2上都可以獲取到存儲卷內文件(可以得到數據的持久化存儲,數據都存儲在NFS服務器上,pod掛載nfs。)
kubectl delete -f pod-nfs-vol.yaml
kubectl apply -f pod-nfs-vol.yaml
kubectl get pods -o wideNAME ? ? ? ? ? ? ? ? ? ? READY ? ? STATUS ? ?RESTARTS ? AGE ? ? ? IP ? ? ? ? ? ?NODE pod-vol-nfs ? ? ? ? ? ? ?1/1 ? ? ? Running ? 0 ? ? ? ? ?21s ? ? ? 10.244.2.39 ? node01
curl 10.244.2.39<h1> nfs stor01</h1>
PVC 和 PV?
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 并刪除 PVC
- Reclaiming,回收 PV,可以保留 PV 以便下次使用,也可以直接從云存儲中刪除
根據這 5 個階段,PV 的狀態有以下 4 種
- Available(可用):表示可用狀態,PV 被創建出來了,還未被 PVC 綁定
- Bound(已綁定):表示 PV 已經被 PVC 綁定,PV 與 PVC 是一對一的綁定關系
- Released(已釋放):表示 PVC 被刪除,但是 PV 資源還未被回收
- Failed(失敗):表示 PV 自動回收失敗
一個PV從創建到銷毀的具體流程如下
- 一個PV創建完后狀態會變成Available,等待被PVC綁定。
- 一旦被PVC邦定,PV的狀態會變成Bound,就可以被定義了相應PVC的Pod使用。
- Pod使用完后會釋放PV,PV的狀態變成Released。
- 變成Released的PV會根據定義的回收策略做相應的回收工作。有三種回收策略,Retain、Delete和Recycle。
- Retain就是保留現場,K8S集群什么也不做,等待用戶手動去處理PV里的數據,處理完后,再手動刪除PV。
- Delete策略,K8S會自動刪除該PV及里面的數據。
- Recycle方式,K8S會將PV里的數據刪除,然后把PV的狀態變成Available,又可以被新的PVC綁定使用。
pv的參數
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)用于pvc指定使用pvpersistentVolumeReclaimPolicy: 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 支持)
pvc的參數?
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.specspec:accessModes: (定義訪問模式,必須是PV的訪問模式的子集)resources:requests:storage: (定義申請資源的大小)storageClassName: (定義存儲類名稱,此配置用于1.綁定具有相同類別的PVC和PV(靜態創建pv情況)2.引用storageclass通過插件創建pv(動態創建pv情況))
NFS使用PV和PVC
PV/PVC調度方式?
你知道哪些kubernetes存儲資源對象 ?? ? /? ? ?kubernetes中 怎么存儲數據?【重要】
? ? ? ? ? ? ? PV? ? ? ? ? ? ? ? ?PVC????????
創建 PV 的方式(PV的類型)
- 手動根據配置文件創建的靜態PV
- 通過StorageClass調用存儲卷插件創建的動態PV
怎么創建pv pvc【重要】
動態創建
動態方式是 通過存儲卷插件和storageclass來實現的
- 準備好存儲設備和共享目錄
- 如果是外置存儲卷插件,需要先創建serviceaccount賬戶(Pod使用的賬戶)和做RBAC授權(創建角色授予相關資源對象的操作權限,再將賬戶和角色進行綁定),使serviceaccount賬戶具有對PV PVC StorageClass等資源的操作權限? ? ? ? ?先創建存儲卷插件用戶,然后給用戶授權
- 創建外置存儲卷插件provisioner的Pod,配置中使用serviceaccount賬戶作為Pod的用戶,并設置相關環境變量參數? ? ? ? ? ?使用存儲卷用戶創建存儲卷插件的pod
- 創建StorageClass(SC)資源,配置中引用存儲卷插件的插件名稱(PROVISIONER_NAME)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???創建storageclass引用存儲卷插件
---------------- 以上操作都是做授權,是一勞永逸的,以后只需要創建PVC時設置StorageClass就可以自動調用存儲卷插件動態生成PV資源 ----------------
- 創建PVC資源,配置中設置 StorageClass資源名稱 訪問模式 存儲空間大小。創建PVC資源會自動創建相關的PV資源。? ? ? ?? 創建pvc引用storageclass
- 創建Pod資源掛載PVC存儲卷,配置存儲卷類型為 persistentVolumeClaim ,并在容器配置中定義存儲卷掛載點目錄? ? ? ? ? ? ? ?創建pod 掛載pvc存儲卷
創建使用 靜態PV
- 準備好存儲設備和共享目錄
- 手動創建PV資源,配置 存儲卷類型 訪問模式(RWO RWX ROX RWOP) 存儲空間大小 ?回收策略(Retain Recycle Delete)等? ? ? ? ?手動創建pv資源
- 創建PVC資源,配置請求PV資源的訪問模式(必要條件,必須是PV能支持的訪問模式) 存儲空間大小(默認就近選擇大于等于指定大小的PV)來綁定PV? ? ?pvc與pv綁定
- 創建Pod和Pod控制器資源掛載PVC存儲卷,配置存儲卷類型為 persistentVolumeClaim ,并在容器配置中定義存儲卷掛載點目錄? ? ? ? ? 創建pod掛載使用pvc類型存儲卷
1、配置nfs存儲
mkdir -p /data/volumes/ cd /data/volumes/ mkdir v{1,2,3,4,5}vim /etc/exports /data/volumes/v1 192.168.80.0/24(rw,no_root_squash) /data/volumes/v2 192.168.80.0/24(rw,no_root_squash) /data/volumes/v3 192.168.80.0/24(rw,no_root_squash) /data/volumes/v4 192.168.80.0/24(rw,no_root_squash) /data/volumes/v5 192.168.80.0/24(rw,no_root_squash)
systemctl stop firewalld
?
exportfs -arvshowmount -e
?2、手動定義PV
//這里定義5個PV,并且定義掛載的路徑以及訪問模式,還有PV劃分的大小。?pv只管自己創建,不用考慮與pvc的對應關系: pvc無需指定使用哪一個pv,pvc只管發布需求,然后系統會匹配最近似的pv。
pod則需要指定存儲卷,并在存儲卷中指定使用哪一個pvc,然后再給容器掛載上這個存儲卷。
vim pv-demo.yamlapiVersion: v1 kind: PersistentVolume metadata:name: pv001labels:name: pv001 spec:nfs:path: /data/volumes/v1#server: stor01server: 192.168.80.110 #做了host主機名映射可以直接寫主機名,沒做就直接寫nfs服務器IPaccessModes: ["ReadWriteMany","ReadWriteOnce"]capacity:storage: 1Gi#persistentVolumeReclaimPoilcy: Recycle #pv回收方式#storageClassName: slow #在pvc中指定同樣的storageClassName,可以讓pvc指定使用某一pv --- apiVersion: v1 kind: PersistentVolume metadata:name: pv002labels:name: pv002 spec:nfs:path: /data/volumes/v2#server: stor01server: 192.168.80.110 #做了host主機名映射可以直接寫主機名,沒做就直接寫nfs服務器IPaccessModes: ["ReadWriteOnce"]capacity:storage: 2Gi --- apiVersion: v1 kind: PersistentVolume metadata:name: pv003labels:name: pv003 spec:nfs:path: /data/volumes/v3#server: stor01server: 192.168.80.110 #做了host主機名映射可以直接寫主機名,沒做就直接寫nfs服務器IPaccessModes: ["ReadWriteMany","ReadWriteOnce"]capacity:storage: 2Gi --- apiVersion: v1 kind: PersistentVolume metadata:name: pv004labels:name: pv004 spec:nfs:path: /data/volumes/v4#server: stor01server: 192.168.80.110 #做了host主機名映射可以直接寫主機名,沒做就直接寫nfs服務器IPaccessModes: ["ReadWriteMany","ReadWriteOnce"]capacity:storage: 4Gi --- apiVersion: v1 kind: PersistentVolume metadata:name: pv005labels:name: pv005 spec:nfs:path: /data/volumes/v5#server: stor01server: 192.168.80.110 #做了host主機名映射可以直接寫主機名,沒做就直接寫nfs服務器IPaccessModes: ["ReadWriteMany","ReadWriteOnce"]capacity:storage: 5Gi
kubectl apply -f pv-demo.yaml
kubectl get pvNAME ? ? ?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的狀態即為Boundpv只管自己創建,不用考慮與pvc的對應關系: pvc無需指定使用哪一個pv,pvc只管發布需求,然后系統會匹配最近似的pv。
pod則需要指定存儲卷,并在存儲卷中指定使用哪一個pvc,然后再給容器掛載上這個存儲卷。
vim pod-vol-pvc.yaml 在這個yaml文件中寫了pvc與pod兩個配置文件。也可以分開寫兩個yaml配置文件#定義pvc的配置文件 apiVersion: v1 kind: PersistentVolumeClaim metadata:name: mypvc #保持一致🧨 定義pvc名namespace: default spec:accessModes: ["ReadWriteMany"]resources:requests:storage: 2Gi---#容器的配置文件。在容器中指定使用pvc apiVersion: v1 kind: Pod metadata:name: pod-vol-pvcnamespace: default spec:containers:- name: myappimage: nginxvolumeMounts:- name: htmldir #保持一致?mountPath: /usr/share/nginx/htmlvolumes:- name: htmldir #保持一致? 指定存儲卷名persistentVolumeClaim: #存儲卷使用PVC方式claimName: mypvc #保持一致🧨 指定使用哪個pvc
kubectl apply -f pod-vol-pvc.yaml
系統自動選擇最適合的pv進行綁定(pvc需求2G并且RWX。pv003最好的滿足了。并且一個pv只能綁定一個pvc,后續pv003在解綁之前不再能被其他pvc綁定)?
kubectl get pvNAME ? ? ?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 pvcNAME ? ? ?STATUS ? ?VOLUME ? ?CAPACITY ? ACCESS MODES ? STORAGECLASS ? AGE mypvc ? ? Bound ? ? pv003 ? ? 2Gi ? ? ? ?RWO,RWX ? ? ? ? ? ? ? ? ? ? ? 22s
4、測試訪問
//在NFS存儲服務器上創建index.html,并寫入數據,通過訪問Pod進行查看,可以獲取到相應的頁面。cd /data/volumes/v3/ echo "welcome to use pv3" > index.html
kubectl get pods -o widepod-vol-pvc ? ? ? ? ? ? 1/1 ? ? ? Running ? 0 ? ? ? ? ?3m ? ? ? ?10.244.2.4 k8s-node02
curl 10.244.2.42welcome to use pv3
注意,如果pod內容器使用pvc存儲卷,不能使用nodename指定節點調度。
使用pvc存儲 還需要做節點選擇的話 使用nodeselect,節點親和,pod親和,或是污點實現。
搭建 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.準備存儲設備
2.安裝存儲卷插件(有外置【需要自己安裝】與內置區分)
3.將存儲卷插件與storageclass關聯
pvc提出需求,調用storageclass,storageclass找到相關的存儲卷插件,存儲卷插件根據需求創建指定大小 和 訪問模式的pv資源
1、在stor01節點上安裝nfs,并配置nfs服務
mkdir /opt/k8s chmod 777 /opt/k8s/
vim /etc/exports/opt/k8s 192.168.80.0/24(rw,no_root_squash,sync)
systemctl restart nfs
2、創建 Service Account(由于NFS卷插件以pod運行 每個pod都有一個用戶賬號 而默認的default權限非常小,需要創建新用戶給NFS卷插件使用),用來管理 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 #ServiceAccount的名稱 --- #創建集群角色 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-provisioner #角色 與權限綁定namespace: default roleRef:kind: ClusterRolename: nfs-client-provisioner-clusterrole #權限 與角色綁定apiGroup: rbac.authorization.k8s.io
kubectl apply -f nfs-client-rbac.yaml
kubectl get serviceaccounts
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.yamlspec:containers:- command:- kube-apiserver- --feature-gates=RemoveSelfLink=false ? ? ? #添加這一行- --advertise-address=192.168.80.101 ......
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
#創建 NFS Provisioner 存儲器插件的pod
vim nfs-client-provisioner.yamlkind: 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-provisioner #nfs插件以容器形式運行image: quay.io/external_storage/nfs-client-provisioner:latest #此處為網絡拉取NFS插件,也可以指定本地插件imagePullPolicy: IfNotPresentvolumeMounts:- name: nfs-client-root #對應下面存儲卷名字?mountPath: /persistentvolumesenv:- name: PROVISIONER_NAMEvalue: nfs-storage #😊可自定義 配置provisioner的Name(存儲卷插件的名稱),確保該名稱與StorageClass資源中的provisioner名稱保持一致- name: NFS_SERVER#value: stor01 #配置綁定的nfs服務器地址(與volume定義的server一致)value: 192.168.80.110 #🧨做了host主機名映射可以直接寫主機名,沒做就直接寫nfs服務器IP- name: NFS_PATHvalue: /opt/k8s #🐔配置綁定的nfs服務器目錄(與volume定義的path一致)volumes: #申明nfs數據卷- name: nfs-client-root #對應?nfs:#server: stor01server: 192.168.80.110 ##🧨對應 做了host主機名映射可以直接寫主機名,沒做就直接寫nfs服務器IPpath: /opt/k8s #🐔對應
kubectl apply -f nfs-client-provisioner.yaml
kubectl get podNAME ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 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.yamlapiVersion: storage.k8s.io/v1 kind: StorageClass metadata:name: nfs-client-storageclass #🔥下方pvc會指定StorageClass名,保持一致 provisioner: nfs-storage #😊可自定義 這里的名稱要和provisioner配置文件中的環境變量PROVISIONER_NAME保持一致 parameters:archiveOnDelete: "false" #false表示在刪除PVC時不會對數據目錄進行打包存檔,即刪除數據;為ture時就會自動對數據目錄進行打包存檔,存檔文件以archived開頭
kubectl apply -f nfs-client-storageclass.yaml
kubectl get storageclassNAME ? ? ? ? ? ? ? ? ? ? ?PROVISIONER ? RECLAIMPOLICY ? VOLUMEBINDINGMODE ? ALLOWVOLUMEEXPANSION ? AGE nfs-client-storageclass ? nfs-storage ? Delete ? ? ? ? ?Immediate ? ? ? ? ? false ? ? ? ? ? ? ? ? ?43s
5、創建 PVC 和 Pod 測試
vim test-pvc-pod.yamlapiVersion: v1 kind: PersistentVolumeClaim metadata:name: test-nfs-pvc #?pvc名對應#annotations: volume.beta.kubernetes.io/storage-class: "nfs-client-storageclass" #另一種SC配置方式(在元信息中添加注釋字段 關聯) spec:accessModes:- ReadWriteManystorageClassName: nfs-client-storageclass #🔥與上方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-pvc #😊名稱對應mountPath: /mntrestartPolicy: Nevervolumes: #定義存儲卷- name: nfs-pvc #😊名稱對應persistentVolumeClaim:claimName: test-nfs-pvc #?與PVC名稱保持一致
kubectl apply -f test-pvc-pod.yaml
?//PVC 通過 StorageClass 自動申請到空間
kubectl get pvcNAME ? ? ? ? ? ?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/k8s/ default-test-nfs-pvc-pvc-278882a7-1195-47de-8da3-8d078d84065d
//進入 Pod 在掛載目錄 /mnt 下寫一個文件,然后查看 NFS 服務器上是否存在該文件
kubectl exec -it test-storageclass-pod sh / # cd /mnt/ /mnt # echo 'this is test file' > test.txt
//發現 NFS 服務器上存在,說明驗證成功
cat cat /opt/k8s/default-test-nfs-pvc-pvc-278882a7-1195-47de-8da3-8d078d84065d/test.txt