kubernetes系列(十四) – 存儲之PersistentVolume

1. PersistentVolume(PV)簡介

1.1 為什麼需要Persistent Volume(PV)

在將PersistentVolume(PV)之前,我們需要先講一下Volume

Volume詳情可見上一章: kubernetes系列(十三) – 存儲之Volume

Volume是被定義在pod上的(emptyDir或者hostPath),屬於計算資源的一部分。所以Volume是有局限性的,因為在實際的運用過程中,我們通常會先定義一個網絡存儲,然後從中划出一個網盤並掛接到虛擬機上。

為了屏蔽底層存儲實現的細節,讓用戶方便使用,同時讓管理員方便管理。Kubernetes從V1.0版本就引入了PersistentVolume(PV)和與之相關聯的PersistentVolumeClaim(PVC)兩個資源對象來實現對存儲的管理

1.2 PersistentVolume(PV)和Volume的區別

PV可以被理解成kubernetes集群中的某個網絡存儲對應的一塊存儲,它與Volume類似,但是有如下的區別:

  1. PV只能是網絡存儲,不屬於任何Node,但是可以在每個Node上訪問
  2. PV不是被定義在pod上,而是獨立在pod之外被定義的。
    • 意味着pod被刪除了,PV仍然存在,這點與Volume不同

1.3 PV和PVC更具體的概念和關係

1.3.1 PersistentVolume(PV)

PersistentVolume(PV)是由管理員設置的存儲,它是群集的一部分。就像節點是集群中的資源一樣,PV也是集群中的資源。PV是Volume之類的卷插件,但具有獨立於使用PV的Pod的生命周期。此API對象包含存儲實現的細節,即NFSiSCSl或特定於雲供應商的存儲系統。

1.3.2 PersistentVolumeClaim(PVC)

PersistentVolumeClaim(PVC)是用戶存儲的請求。它與Pod相似。Pod消耗節點資源,PVC消耗PV資源。Pod可以請求特定級別的資源(CPU和內存)。聲明可以請求特定的大小和訪問模式(例如,可以以讀/寫一次或只讀多次模式掛載)

1.3.3 PV和PVC的關係和圖解

pvc是一種pv的請求方案,PVC定義我當前需要什麼樣類型的PV,然後會自動在當前存在的pv中選取一個匹配度最高的pv

一個PVC只能綁定一個PV!!

2. PersistentVolume(PV)的分類

2.1 靜態PV

簡單來說

由集群管理員手動創建的一些PV

完整的概念

集群管理員創建一些PV。它們帶有可供群集用戶使用的實際存儲的細節。它們存在於KubernetesAPl中,可用於消費。

2.2 動態PV

簡單來說

配置了允許動態PV的策略後,如果當前存在的PV無法滿足PVC的要求,則會動態創建PV.

動態PV了解即可

完整的概念

當管理員創建的靜態PV都不匹配用戶的PersistentVolumeClaim,集群可能會嘗試動態地為PVC創建卷。此配置基於StorageClasses,所以要啟用基於存儲級別的動態存儲配置要求:

  • PVC必須請求StorageClasses
  • 管理員必須創建並配置StorageClasses才能進行動態創建
  • 聲明該類為「」可以有效地禁用其動態配置
  • 集群管理員需要啟用API server上的DefaultStorageClass[准入控制器]。例如,通過確保DefaultStorageClass位於API server 組件的--admission-control標誌,使用逗號分隔的有序值列表中,可以完成此操作

3. PersistentVolumeClaim(PVC)的保護

PVC保護的目的是確保由pod正在使用的PVC不會從系統中移除,因為如果被移除的話可能會導致數據丟失 當啟用PVC保護alpha功能時,如果用戶刪除了一個pod正在使用的PVC,則該PVC不會被立即刪除。PVC的刪除將被推遲,直到PVC不再被任何 pod使用

4. PersistentVolume(PV)支持的底層存儲類型

PersistentVolume類型以插件形式實現. kubernetes目前支持以下類型(排名不分先後):

跟上一集中的volume支持的類型差不多

  • GCEPersistentDisk AWSElasticBlockStore AzureFile AzureDisk FC(Fibre Channel)
  • FlexVolume Flocker NFS iSCSI RBD(Ceph Block Device) CephFS
  • Cinder(OpenStack block storage) Glusterfs VsphereVolume Quobyte Volumes
  • HostPath VMware Photon Portworx Volumes Scalelo Volumes StorageOS

5. PersistentVolume(PV)的資源清單

5.1 資源清單示例

apiVersion: v1 
kind: PersistentVolume 
metadata:
  name:pve003 
spec:
  capacity:
    # 卷的大小為5G
    storage: 5Gi 
  # 存儲卷的類型為:文件系統
  volumeMode: Filesystem 
  # 訪問策略:該卷可以被單個節點以讀/寫模式掛載
  accessModes:
    - ReadNriteOnce 
  # 回收策略:回收
  persistentVolumeReclaimPolicy: Recycle
  # 對應的具體底層存儲的分級
  # 比如有些固態或者其他存儲類型比較快,就可以定義為strong
  storageClassName: slow
  # (可選的)掛載選項
  mountOptions:
    - hard 
    - nfsvers=4.1
  # 具體對應的真實底層存儲類型為nfs
  # 掛載到172服務器下的/tmp目錄
  nfs:
    path: /tmp 
    server: 172.17.0.2

5.2 PV的訪問模式(spec.accessModes)

5.2.1 三種訪問模式

訪問模式accessModes一共有三種:

  • ReadWriteOnce: 該卷可以被單個節點以讀/寫模式掛載
  • ReadOnlyMany: 該卷可以被多個節點以只讀模式掛載
  • ReadWriteMany: 該卷可以被多個節點以讀/寫模式掛載

在命令行cli中,三種訪問模式可以簡寫為:

  • RWOReadWriteOnce
  • ROXReadOnlyMany
  • RWXReadWriteMany

但不是所有的類型的底層存儲都支持以上三種,每種底層存儲類型支持的都不一樣!!

5.2.2 各種底層存儲具體支持的訪問模式

Volume Plugin ReadWriteOnce ReadOnlyMany ReadWriteMany
AWSElasticBlockStore
AzureFile
AzureDisk
CephFS
Cinder
FC
FlexVolume
Flocker
GCEPersistentDisk
Glusterfs
HostPath
iSCSI
PhotonPersistentDisk
Quobyte
NFS
RBD
VsphereVolume
PortworxVolume
ScaleIO

5.3 PV的回收策略(spec.persistentVolumeReclaimPolicy)

5.3.1 回收策略的三種策略

  • Retain(保留): pv被刪除後會保留內存,手動回收
  • Recycle(回收): 刪除卷下的所有內容(rm-rf /thevolume/*)
  • Delete(刪除): 關聯的存儲資產(例如AWS EBS、GCE PD、Azure Disk 和OpenStack Cinder卷)將被刪除。即直接把卷給刪除了

5.3.2 回收策略注意事項

  1. 當前,只有NFSHostPath支持Recycle回收策略

最新版本中的Recycle已被廢棄,截圖如下

附:具體官網文檔詳細說明鏈接點擊此處

  1. AWS EBS、GCE PD、Azure Disk 和Cinder 卷支持Delete刪除策略

6. PersistentVolume(PV)的狀態

PV可以處於以下的某種狀態:

  • Available(可用): 塊空閑資源還沒有被任何聲明綁定
  • Bound(已綁定): 卷已經被聲明綁定, 注意:但是不一定不能繼續被綁定,看accessModes而定
  • Released(已釋放): 聲明被刪除,但是資源還未被集群重新聲明
  • Failed(失敗): 該卷的自動回收失敗

命令行會顯示綁定到PV的PVC的名稱

7. 實驗-持久化演示說明-NFS

註:以下內容筆者沒有實際嘗試過,僅做記錄使用

7.1 安裝NFS服務器

yum install -y nfs-common nfs-utils rpcbind 
mkdir /nfsdata 
chmod 777 /nfsdata 
chown nfsnobody /nfsdata 
cat /etc/exports /nfsdata *(rw,no_root_squash,no_all_squash,sync)
systemctl start rpcbind 
systemctl start nfs

7.2 在其他節點上安裝客戶端

yum -y install nfs-utils rpcbind
mkdir /test
showmount -e 192.168.66.100
mount -t nfs 192.168.66.100:/nfsdata /test/
cd /test/
ls
umount /test/

7.3 部署PV

apiVersion: v1 
kind: PersistentVolume 
metadata:
  name: nfspv1 
spec:
  capacity:
    storage: 10Gi 
  accessModes:
    - ReadWriteOnce 
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
   path: /nfsdata
   server: 192.168.66.100

7.4 創建服務並使用PVC

apiVersion: v1 
kind: Service 
metadata:
  name: nginx 
  labels:
    app: nginx 
spec:
  ports:
  - port: 80 
    name: web 
  clusterIP: None 
  selector:
    app: nginx
---
apiVersion: apps/v1 
kind: StatefulSet 
metadata:
  name: web 
spec:
  selector:
    matchLabels:
      app: nginx 
  serviceName: "nginx"
  replicas: 3 
  template:
    metadata:
      labels:
        app: nginx 
    spec:
      containers:
      - name: nginx 
        image: k8s.gcr.io/nginx-slim:0.8 
        ports:
        - containerPort: 80 
          name: web 
        volumeMounts:
        - name: www 
          mountPath: /usr/share/nginx/html 
  volumeClaimTemplates:
  - metadata:
      name: www 
    spec:
      accessModes: [ "ReadWriteOnce" ] 
      storageClassName: "nfs"
      resources:
        requests:
          storage: 1Gi

8. 關於 Statefulset

  1. StatefulSet為每個Pod副本創建了一個DNS域名,這個域名的格式為:S(podname).(headless servername)

也就意味着服務間是通過Pod域名來通信而非PodIP,因為當Pod所在Node發生故障時,Pod會被飄移到其它 Node上,PodIP會發生變化,但是Pod域名不會有變化

  1. StatefulSet使用Headless服務來控制Pod的域名,這個域名的FQDN為:S(servicename).$(namespace).svc.cluster.local

其中,「cluster.local」指的是集群的域名

  1. 根據volumeClaimTemplates,為每個Pod 創建一個pvo,pvc的命名規則匹配模式:
    (volumeClaimTemplates.name)-(pod_name)

比如上面的 volumeMounts.name=www,Podname-web-[0-2],因此創建出來的PVC是 www-web-0、www-web-1、 www-web-2

  1. 刪除 Pod 不會刪除其pvc,手動刪除 pvc將自動釋放pv
  2. Statefulset的啟停順序:
    • 有序部署:部罷Statefulset時,如果有多個Pod副本,它們會被順序地創建(從0到N-1)並且,在下一個Pod運行之前所有之前的Pod必須都是Running和Ready狀態。
    • 有序刪除:當Pod被刪除時,它們被終止的順序是從N-1到0。
    • 有序擴展:當對Pod執行擴展操作時,與部署一樣,它前面的Pod必須都處於Running和Ready狀態。
  3. Statefulset使用場景:
    • 穩定的持久化存儲,即Pod重新調度後還是能訪問到相同的持久化數據,基於PVC 來實現。
    • 穩定的網絡標識符,即Pod 重新調度後其iPodName 和 HostName不變。
    • 有序部署,有序擴展,基於init containers 來實現。
    • 有序收縮。