九、Kubernetes之 PV和PVC


通過網絡存儲卷及使用示例可知,用戶必須要清晰了解用到的網絡存儲系統的訪問細節才能完成存儲卷相關的配置任務,例如RBD存儲卷插件配置中的監視器(monitor)、存儲池(pool)、存儲映像(image)和密鑰環(keyring)等來自於Ceph存儲系統中的概念,這就要求用戶對該類存儲系統有着一定的了解才能夠順利使用。這與Kubernetes向用戶和開發隱藏底層架構的目標有所背離,最好對存儲資源的使用也能像計算資源一樣,用戶和開發人員既無須了解Pod資源究竟運行在哪個節點,也不用了解存儲系統是什么設備、位於何處以及如何訪問。

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所指向的存儲空間,如圖所示。

盡管PVC及PV將存儲資源管理與使用的職責分離至用戶和集群管理員兩類不同的人群之上,簡化了用戶對存儲資源的使用機制,但也對二者之間的協同能力提出了要求。管理員需要精心預測和規划集群用戶的存儲使用需求,提前創建出多種規格的PV,以便於在用戶聲明PVC后能夠由PV控制器在集群中找尋到合適的甚至是最佳匹配的PV進行綁定。

這種通過管理員手動創建PV來滿足PVC需求的靜態預配(static provisioning)存在着不少的問題。

第一,集群管理員難以預測出用戶的真實需求,很容易導致某些類型的PVC無法匹配到PV而被掛起,直到管理員參與到問題的解決過程中。
第二,那些能夠匹配到PV的PVC也很有可能存在資源利用率不佳的狀況,例如一個聲明使用5G存儲空間的PVC綁定到一個20GB的PV之上。

解決方案是一種稱為動態預配、按需創建PV的機制。集群管理員要做的僅是事先借助存儲類(StorageClass)的API資源創建出一到多個“PV模板”,並在模板中定義好基於某個存儲系統創建PV所依賴的存儲組件(例如Ceph RBD存儲映像或CephfFS文件系統等)時需要用到的配置參數。創建PVC時,用戶需要為其指定要使用PV模板(StorageClass資源),而后PV控制器會自動連接相應存儲類上定義的目標存儲系統的管理接口,請求創建匹配該PVC需求的存儲組件,並將該存儲組件創建為Kubernetes集群上可由該PVC綁定的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)。

這4個組件中,存儲卷插件是其他3個組件的基礎庫,換句話說,PV控制器、AD控制器和存儲卷管理器均構建於存儲卷插件之上,以提供不同維度管理功能的接口,具體的實現邏輯均由存儲卷插件完成。

除了創建、刪除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種。

處於綁定狀態的PVC刪除后,相應的PV將轉為Released狀態,之后的處理機制依賴於其回收策略。而處於綁定狀態的PV將會導致相應的PVC轉為Lost狀態,而無法再由Pod正常使用,除非PVC再綁定至其他Available狀態的PV之上,但應用是否能正常運行,則取決於對此前數據的依賴度。另一方面,為了避免使用中的存儲卷被移除而導致數據丟失,Kubernetes自1.9版引入了“PVC保護機制”,其目的在於,用戶刪除了仍被某Pod對象使用中的PVC時,Kubernetes不會立即移除該PVC,而是會推遲到它不再被任何Pod對象使用后方才真正執行刪除操作。處於保護階段的PVC資源的status字段值為Termination,並且其Finalizers字段值中包含有kubernetes.io/pvc-protection。

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在某個特定時刻僅可基於一種模式進行存取,哪怕它同時支持多種模式。

1) NFS 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) 使用keyring文件來創建ceph-rbd-pv

下面是另一個PV資源的配置清單(pv-rbd-demo.yaml),它使用了RBD存儲后端,空間大小等同於指定的RBD存儲映像的大小(這里為2GB),並限定支持的訪問模式為RWO,回收策略為Retain。除此之外,該PV資源還擁有一個名為usedof的資源標簽,該標簽可被PVC的標簽選擇器作為篩選PV資源的標准之一。

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>

3)使用Secret來創建ceph-rbd-pv

這里以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對應的持久存儲卷。 定義PVC時,用戶可通過訪問模式(accessModes)、數據源(dataSource)、存儲資源空間需求和限制(resources)、存儲類、標簽選擇器、卷模型和卷名稱等匹配標准來篩選集群上的PV資源,其中,resources和accessModes是最重要的篩選標准。PVC的Spec字段的可嵌套字段有如下幾個。

▪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

1) NFS PV示例

下面的配置清單(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)ceph-rbd PVC示例

下面這個定義在pvc-rbd-0002.yaml中的配置清單定義了一個PVC資源,除了期望的訪問模式、卷模型和存儲空間容量邊界之外,它使用了標簽選擇器來匹配PV資源的標簽。

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

刪除一個PVC將導致其綁定的PV資源轉入Released狀態,並由相應的回收策略完成資源回收。反過來,直接刪除一個仍由某PVC綁定的PV資源,會由PVC保護機制延遲該刪除操作至相關的PVC資源被刪除。

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所綁定

5、在Pod中使用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
......

 

6、存儲類StorageClass

存儲類也是Kubernetes系統上的API資源類型之一,它位於storage.k8s.io群組中。存儲類通常由集群管理員為管理PV資源之便而按需創建的存儲資源類別(邏輯組),例如可將存儲系統按照其性能高低或者綜合服務質量級別分類、依照備份策略分類,甚至直接按管理員自定義的標准分類等。存儲類也是PVC篩選PV時的過濾條件之一,這意味着PVC僅能在其隸屬的存儲類之下找尋匹配的PV資源。不過,Kubernetes系統自身無法理解“類別”到底意味着什么,它僅僅把存儲類中的信息當作PV資源的特性描述使用。

 

存儲類的最重要功能之一便是對PV資源動態預配機制的支持,它可被視作動態PV資源的創建模板,能夠讓集群管理員從維護PVC和PV資源之間的耦合關系的束縛中解脫出來。需要用到具有持久化功能的存儲卷資源時,用戶只需要向滿足其存儲特性要求的存儲類聲明一個PVC資源,存儲類將會根據該聲明創建恰好匹配其需求的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,默認為空值,並且不支持任何功能。

提示 存儲類接入其他存儲系統時使用的參數請參考https://kubernetes.io/docs/concepts/storage/storage-classes/

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

第二步:創建storageclass

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的模板

pvc-dyn-rbd.yaml

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

查看pvc來確定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

3) 各存儲插件對動態預配方式的支持狀況

 

7、總結

1) 什么是pv

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、NFS的動態預配(StorageClass)

8.1 pv的動態供給介紹

存儲類(storage class)是Kubernetes資源類型的一種,它是由管理員為管理PV之便而按需創建的類別(邏輯組),例如可按存儲系統的性能高低分類,或者根據其綜合服務質量級別進行分類、依照備份策略分類,甚至直接按管理員自定義的標准進行分類等。不過,Kubernetes自身無法理解“類別”到底意味着什么,它僅僅是將這些當作PV的特性描述。

存儲類的好處之一便是支持PV的動態創建。用戶用到持久性存儲時,需要通過創建PVC來綁定匹配的PV,此類操作需求量較大,或者當管理員手動創建的PV無法滿足PVC的所有需求時,系統按PVC的需求標准動態創建適配的PV會為存儲管理帶來極大的靈活性。 存儲類對象的名稱至關重要,它是用戶調用的標識。創建存儲類對象時,除了名稱之外,還需要為其定義三個關鍵字段:provisioner、parameter和reclaimPolicy。

 

StorageClass Spec中的字段是定義存儲類時最重要的字段,其包含以下五個可用字段。·provisioner(供給方):即提供了存儲資源的存儲系統,存儲類要依賴Provisioner來判定要使用的存儲插件以便適配到目標存儲系統。Kubernetes內建有多種供給方(Provisioner),這些供給方的名字都以“kubernetes.io”為前綴。另外,它還支持用戶依據Kubernetes規范自定義Provisioner。·parameters(參數):存儲類使用參數描述要關聯到的存儲卷,不過,不同的Provisioner可用的參數各不相同。·reclaimPolicy:為當前存儲類動態創建的PV指定回收策略,可用值為Delete(默認)和Retain;不過,那些由管理員手工創建的PV的回收策略則取決於它們自身的定義。·volumeBindingMode:定義如何為PVC完成供給和綁定,默認值為“VolumeBinding Immediate”;此選項僅在啟用了存儲卷調度功能時才能生效。·mountOptions:由當前類動態創建的PV的掛載選項列表。

動態PV供給的啟用,需要事先由管理員創建至少一個存儲類,不同的Provisoner的創建方法各有不同。另外,並非所有的存儲卷插件都由Kubernetes內建支持PV動態供給功能。

任何支持PV動態供給的存儲系統都可以在定義為存儲類后由PVC動態申請使用,這對於難以事先預估使用到的存儲空間大小及存儲卷數量的使用場景尤為有用,例如由StatefulSet控制器管理Pod對象時,存儲卷是必備資源,且隨着規模的變動,存儲卷的數量也會隨之變動。 另外,用戶也可以使用雲端存儲提供的PV動態供給機制,如AWS EBS、AzureDisk、Cinder或GCEPersistentDisk等,將Kubernetes部署於IaaS雲端時,此種存儲方式使用的較多。各類雲存儲動態供給的具體使用方式請參考相關的使用手冊。

 

8.2 配置nfs的動態供給

 

1、部署NFS動態供給插件

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM