1. 程式人生 > 其它 >07-持久化儲存和StorageClass

07-持久化儲存和StorageClass

在k8s中部署的應用都是以pod容器的形式執行的,假如我們部署MySQL、Redis等資料庫,需要對這些資料庫產生的資料做備份。因為Pod是有生命週期的,如果pod不掛載資料卷,那pod被刪除或重啟後這些資料會隨之消失,如果想要長久的保留這些資料就要用到pod資料持久化儲存。

1、持久化儲存

我們可以通過下面的命令查詢Kubernetes的Pod支援哪些持久化儲存方案:

kubectl  explain pods.spec.volumes
  • awsElasticBlockStore:AWSElasticBlockStore 表示一個 AWS 磁碟資源,它附加到 kubelet 的主機,然後暴露給 pod。
  • azureDisk:AzureDisk 表示主機上的 Azure 資料磁碟掛載,並將掛載繫結到 pod。
  • azureFile:AzureFile 表示主機上的 Azure 檔案服務掛載,並將掛載繫結到 pod。
  • cephfs:CephFS 表示主機上的 Ceph FS 掛載,共享 pod 的生命週期。
  • cinder:Cinder 表示附加並安裝在 kubelets 主機上的 cinder 卷。
  • configMap:ConfigMap 表示應該填充此卷的 configMap。
  • csi:CSI(容器儲存介面)表示由某些外部 CSI 驅動程式(Beta 功能)處理的臨時儲存。
  • downwardAPI
    :DownwardAPI 表示關於應該填充此卷的 pod 的向下 API。
  • emptyDir:EmptyDir 表示共享 pod 生命週期的臨時目錄。
  • ephemeral:Ephemeral 表示由叢集儲存驅動程式(Alpha 功能)處理的卷。 卷的生命週期與定義它的 pod 相關聯——它將在 pod 啟動之前建立,並在 pod 被刪除時刪除。
  • fc:FC 表示連線到 kubelet 主機然後暴露給 pod 的光纖通道資源。
  • flexVolume:FlexVolume 表示使用基於 exec 的外掛配置/附加的通用卷資源。
  • flocker:Flocker 表示附加到 kubelet 主機的 Flocker 卷。 這取決於正在執行的 Flocker 控制服務。
  • gcePersistentDisk:GCEPersistentDisk 表示一個 GCE 磁碟資源,它附加到 kubelet 的主機上,然後暴露給 pod。
  • gitRepo:GitRepo 代表特定版本的 git 儲存庫。 GitRepo 已棄用。 要使用 git repo 配置容器,請將 EmptyDir 掛載到使用 git 克隆 repo 的 InitContainer 中,然後將 EmptyDir 掛載到 Pod 的容器中。
  • glusterfs:Glusterfs 表示主機上的 Glusterfs 掛載,共享一個 pod 的生命週期。
  • hostPath:HostPath 表示主機上直接暴露給容器的預先存在的檔案或目錄。 這通常用於系統代理或其他允許檢視主機的特權事物。 大多數容器不需要這個。
  • iscsi:ISCSI 代表一個 ISCSI 磁碟資源,它連線到 kubelet 的主機,然後暴露給 pod。
  • name:卷的名稱。 必須是 DNS_LABEL 並且在 pod 中是唯一的。
  • nfs:NFS 表示共享 pod 生命週期的主機上的 NFS 掛載。
  • persistentVolumeClaim:PersistentVolumeClaimVolumeSource 表示對同一名稱空間中的 PersistentVolumeClaim 的引用。
  • photonPersistentDisk:PhotonPersistentDisk 表示附加並掛載在 kubelets 主機上的 PhotonController 永久磁碟。
  • portworxVolume:PortworxVolume 表示連線並掛載在 kubelets 主機上的 portworx 卷。
  • projected:一站式資源祕密、配置對映和向下 API 的專案。
  • quobyte:Quobyte 表示共享 pod 生命週期的主機上的 Quobyte 掛載。
  • rbd:RBD 表示在共享 pod 生命週期的主機上掛載的 Rados 塊裝置。
  • scaleIO:ScaleIO 表示附加並安裝在 Kubernetes 節點上的 ScaleIO 持久卷。
  • secret:Secret 表示應填充此卷的金鑰。
  • storageos:StorageOS 表示附加並安裝在 Kubernetes 節點上的 StorageOS 卷。
  • vsphereVolume:VsphereVolume 表示附加並安裝在 kubelets 主機上的 vSphere 卷。

其中比較常用的掛在卷型別有:

  • emptyDir
  • hostPath
  • nfs
  • persistentVolumeClaim
  • glusterfs
  • cephfs
  • configMap
  • secret

想要使用儲存卷,需要經歷下面兩個步驟:

  1. 定義pod的volume,這個volume指明它要關聯到哪個儲存上的
  2. 在容器中要使用volumemounts掛載對應的儲存

1.1 emptyDir

emptyDir型別的Volume是在Pod分配到Node上時被建立,Kubernetes會在Node上自動分配一個目錄,因此無需指定宿主機Node上對應的目錄檔案。 這個目錄的初始內容為空,當Pod從Node上移除時,emptyDir中的資料會被永久刪除。emptyDir Volume主要用於某些應用程式無需永久儲存的臨時目錄,多個容器的共享目錄等。

官方文件:https://kubernetes.io/docs/concepts/storage/volumes#emptydir

示例:建立一個Pod掛載emptyDir:

emptydir.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-emptydir
  namespace: default
  labels:
    app: pod-emptydir
spec:
  containers:
    - name: pod-emptydir
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
      resources:
        requests:
          cpu: "250m"
          memory: "128Mi"
        limits:
          cpu: "500m"
          memory: "256Mi"
  restartPolicy: Always
  volumes:
    - name: cache-volume
      emptyDir:
        {}

更新資源清單:

kubectl apply -f emptydir.yaml

檢視Pod描述資訊,可以看到對應的掛載卷為cache-volume,型別為EmptyDir

然後去Pod所在的節點檢視對應的Volume掛在卷:

kubectl get pods -l app=pod-emptydir -o wide
kubectl get pods -l app=pod-emptydir -o yaml | grep uid

獲得對應Pod所在的節點以及uid資訊:

在對應的節點上檢視Pod相關資訊:

tree /var/lib/kubelet/pods/18168545-1292-4086-aaba-0bf71edadc0e

右下圖可知,臨時目錄在對應工作節點的/var/lib/kubelet/pods/18168545-1292-4086-aaba-0bf71edadc0e/volumes/目錄下:

1.2 hostPath

hostPath Volume是指Pod掛載宿主機上的目錄或檔案。 hostPath Volume使得容器可以使用宿主機的檔案系統進行儲存,hostpath(宿主機路徑):節點級別的儲存卷,在pod被刪除,這個儲存卷還是存在的,不會被刪除,所以只要同一個pod被排程到同一個節點上來,在pod被刪除重新被排程到這個節點之後,對應的資料依然是存在的。

示例:建立一個Pod掛載hostPath型別的儲存卷:

hostpath.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-hostpath
  namespace: default
  labels:
    app: pod-hostpath
spec:
  containers:
    - name: pod-hostpath-nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - mountPath: /test-nginx
          name: hostpath-volume
    - name: pod-hostpath-tomcat
      image: tomcat:8.5-jre8-alpine
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - mountPath: /test-tomcat
          name: hostpath-volume
  restartPolicy: Always
  volumes:
    - name: hostpath-volume
      hostPath:
        path: /data1
        type: DirectoryOrCreate

更新資源清單:

kubectl apply -f hostpath.yaml

檢視Pod被排程到了哪個節點:

get pods -l app=pod-hostpath -o wide

結果如下:

前往對應的工作節點,檢視是否建立了/data1目錄:

ll /data1/

結果如下:

進入/data1目錄,建立一個資料夾,並且進入對應的Pod中檢查:

# 在對應的工作節點上執行
cd /data1 && mkdir -p testDir

結果如下:

# 到控制節點上執行進入Pod並檢查的操作
kubectl exec -it pod-hostpath -c pod-hostpath-nginx  -- /bin/bash
ls -l /test-nginx

kubectl exec -it pod-hostpath -c pod-hostpath-tomcat  -- /bin/bash
ls -l /test-tomcat

分別進入兩個Pod中檢查,都存在testDir這個目錄:

由此可知,pod-hostpath-nginxpod-hostpath-tomcat兩個Pod這兩個容器是共享儲存卷的。

hostPath型別儲存卷的缺點:

  • 單節點:pod刪除之後重新建立必須排程到同一個node節點,資料才不會丟失

要解決單節點問題,可以使用分散式儲存來解決,例如:nfs、cephfs、glusterfs等。

1.3 nfs

1.3.1 搭建nfs服務

NFS服務端搭建:

# 1. nfs服務端安裝nfs-utils
yum install -y nfs-utils

# 2. 建立NFS共享的目錄
mkdir -pv /data/volumes

# 3. 配置nfs共享目錄
cat > /etc/exports << EOF
/data/volumes 192.168.126.40/24(rw,no_root_squash)
EOF

# 4. 啟動nfs服務
systemctl start nfs.service
systemctl status nfs.service
systemctl enable nfs.service

NFS客戶端搭建:

在Kubernetes的各個工作節點上操作:

yum install -y nfs-utils

systemctl enable nfs.service

# 手動掛載nfs
mkdir -p /test
mount 192.168.126.40:/data/volumes /test/
df -Th

掛載成功顯示如下:

# 手動解除安裝
umount /test
df -Th

解除安裝成功:

1.3.2 建立Pod掛載nfs作為儲存卷

Kubernetes掛載NFS的官方文件:https://kubernetes.io/zh/docs/concepts/storage/volumes/#nfs

nfs.yaml

apiVersion: v1
kind: Pod
metadata:
  name: test-nfs-volume
  namespace: default
  labels:
    app: test-nfs-volume
spec:
  containers:
    - name: nfs-volume-nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - containerPort: 80
          protocol: TCP
      volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: nfs-volume
  restartPolicy: Always
  volumes:
    - name: nfs-volume
      nfs:
        path: /data/volumes
        server: 192.168.126.40

更新資源清單:

kubectl apply -f nfs.yaml

檢查Pod是否建立成功:

kubectl get pods -l app=test-nfs-volume -o wide

結果如下:

進入到NFS共享目錄下,建立一個index.html檔案:

# 在nfs-server伺服器上操作
cd /data/volumes/
echo 'NFS Volume Successed!' > index.html

效果如下:

通過curl Pod IP檢視結果:

curl 10.244.85.208

結果如下:

NFS掛載成功,nfs支援多個客戶端掛載,可以建立多個pod,掛載同一個nfs伺服器共享出來的目錄;但是nfs如果宕機了,資料也就丟失了,所以需要使用分散式儲存,常見的分散式儲存有glusterfs和cephfs。

2、PVC

官方文件:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes

2.1 什麼是PV?

PersistentVolume(PV)是群集中的一塊儲存,由管理員配置或使用儲存類動態配置。 它是叢集中的資源,就像pod是k8s叢集資源一樣。 PV是容量外掛,如Volumes,其生命週期獨立於使用PV的任何單個pod。

2.2 什麼是PVC?

PersistentVolumeClaim(PVC)是一個持久化儲存卷,我們在建立pod時可以定義這個型別的儲存卷。 它類似於一個pod。 Pod消耗節點資源,PVC消耗PV資源。 Pod可以請求特定級別的資源(CPU和記憶體)。 pvc在申請pv的時候也可以請求特定的大小和訪問模式(例如,可以一次讀寫或多次只讀)。

2.3 PVC和PV工作原理

PV是群集中的資源。 PVC是對這些資源的請求。

PV和PVC之間的相互作用遵循以下生命週期。

2.3.1 pv的供應方式

  • 靜態的:叢集管理員建立了許多PV。它們包含可供群集使用者使用的實際儲存的詳細資訊。它們存在於Kubernetes API中,可供使用。
  • 動態的:當管理員建立的靜態PV都不匹配使用者的PersistentVolumeClaim時,群集可能會嘗試為PVC專門動態配置卷。此配置基於StorageClasses,PVC必須請求儲存類,管理員必須建立並配置該類,以便進行動態配置。

2.3.2 繫結

使用者建立pvc並指定需要的資源和訪問模式。在找到可用pv之前,pvc會保持未繫結狀態。

2.3.3 使用

  1. 需要找一個儲存伺服器,把它劃分成多個儲存空間;
  2. k8s管理員可以把這些儲存空間定義成多個pv;
  3. 在pod中使用pvc型別的儲存卷之前需要先建立pvc,通過定義需要使用的pv的大小和對應的訪問模式,找到合適的pv;
  4. pvc被建立之後,就可以當成儲存捲來使用了,我們在定義pod時就可以使用這個pvc的儲存卷;
  5. pvc和pv它們是一一對應的關係,pv如果被pvc綁定了,就不能被其他pvc使用了;
  6. 我們在建立pvc的時候,應該確保和底下的pv能繫結,如果沒有合適的pv,那麼pvc就會處於pending狀態。

2.3.4 回收策略

當我們建立pod時如果使用pvc做為儲存卷,那麼它會和pv繫結,當刪除pod,pvc和pv繫結就會解除,解除之後和pvc繫結的pv卷裡的資料需要怎麼處理,目前,卷可以保留,回收或刪除:

  • Retain
  • Recycle (不推薦使用,1.15可能被廢棄了)
  • Delete

從其宣告中釋放持久卷時會發生什麼。 有效選項是 Retain(手動建立的 PersistentVolumes 的預設值)、Delete(動態配置的 PersistentVolumes 的預設值)和 Recycle(已棄用)。 此 PersistentVolume 下的卷外掛必須支援回收。

2.3.4.1 Retain

當刪除pvc的時候,pv仍然存在,處於released狀態,但是它不能被其他pvc繫結使用,裡面的資料還是存在的,當我們下次再使用的時候,資料還是存在的,這個是預設的回收策略。

2.3.4.2 Delete

刪除pvc時即會從Kubernetes中移除PV,也會從相關的外部設施中刪除儲存資產。

2.4 通過PVC給Pod提供持久化儲存卷

2.4.1 建立NFS共享目錄

# 在nfs-server伺服器上操作
mkdir -p  /data/volume_test/v{1,2,3,4,5,6,7,8,9,10}

# 配置nfs
cat > /etc/exports << EOF
/data/volumes 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v1 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v2 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v3 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v4 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v5 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v6 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v7 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v8 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v9 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v10 192.168.126.40/24(rw,no_root_squash)
EOF

# 重新載入配置
exportfs -arv

2.4.2 PV資源清單

通過kubectl explain pv命令可以檢視pv資源物件的欄位和配置資訊。

  • apiVersion:pv物件的API組和版本資訊。當前版本資訊為v1,可以通過kubectl explain pv.apiVersion檢視當前Kubernetes版本的API版本資訊。
  • kind:資源物件型別,PersistentVolume,可以通過kubectl explain pv.kind查詢。
  • metadata:PV資源物件的元資料資訊
    • name:PV物件的名稱
    • namespace:PV資源物件所屬的名稱空間
  • spec:PV資源物件的詳細配置
    • accessModes:AccessModes 包含可以掛載卷的訪問方式。參考:https://kubernetes.io/zh/docs/concepts/storage/persistent-volumes/#access-modes
      • ReadWriteOnce:卷可以被一個節點以讀寫方式掛載。 ReadWriteOnce 訪問模式也允許執行在同一節點上的多個 Pod 訪問卷。
      • ReadOnlyMany:卷可以被多個節點以只讀方式掛載。
      • ReadWriteMany:卷可以被多個節點以讀寫方式掛載。
      • ReadWriteOncePod:卷可以被單個 Pod 以讀寫方式掛載。 如果你想確保整個叢集中只有一個 Pod 可以讀取或寫入該 PVC, 請使用ReadWriteOncePod 訪問模式。這隻支援 CSI 卷以及需要 Kubernetes 1.22 以上版本。
    • awsElasticBlockStore:AWSElasticBlockStore 表示一個 AWS 磁碟資源,它附加到 kubelet 的主機,然後暴露給 pod。
    • azureDisk:AzureDisk 表示主機上的 Azure 資料磁碟掛載,並將掛載繫結到 pod。
    • azureFile:AzureFile 表示主機上的 Azure 檔案服務掛載,並將掛載繫結到 pod。
    • capacity:持久卷的資源和容量的描述。參考:https://kubernetes.io/zh/docs/concepts/storage/persistent-volumes/#capacityhttps://kubernetes.io/zh/docs/reference/glossary/?all=true#term-quantity
      • storage:PV儲存卷的大小。例如:1Gi
    • cephfs:CephFS 表示主機上的 Ceph FS 掛載,共享 pod 的生命週期。
    • cinder:Cinder 表示附加並安裝在 kubelets 主機上的 cinder 卷。
    • claimRef:ClaimRef 是 PersistentVolume 和 PersistentVolumeClaim 之間雙向繫結的一部分。 繫結時預計為非零。 claim.VolumeName 是 PV 和 PVC 之間的權威繫結。
    • csi:CSI(容器儲存介面)表示由某些外部 CSI 驅動程式(Beta 功能)處理的臨時儲存。
    • fc:FC 表示連線到 kubelet 主機然後暴露給 pod 的光纖通道資源。
    • flexVolume:FlexVolume 表示使用基於 exec 的外掛配置/附加的通用卷資源。
    • flocker:Flocker 表示附加到 kubelet 主機的 Flocker 卷。 這取決於正在執行的 Flocker 控制服務。
    • gcePersistentDisk:GCEPersistentDisk 表示一個 GCE 磁碟資源,它附加到 kubelet 的主機上,然後暴露給 pod。
    • glusterfs:Glusterfs 表示主機上的 Glusterfs 掛載,共享一個 pod 的生命週期。
    • hostPath:HostPath 表示主機上直接暴露給容器的預先存在的檔案或目錄。 這通常用於系統代理或其他允許檢視主機的特權事物。 大多數容器不需要這個。
    • iscsi:ISCSI 代表一個 ISCSI 磁碟資源,它連線到 kubelet 的主機,然後暴露給 pod。
    • local:Local 表示具有節點親和性的直連儲存。
    • mountOptions:掛載選項列表,例如rosoft
    • nfs:NFS 表示主機上的 NFS 掛載。 由管理員提供。
    • nodeAffinity:NodeAffinity 定義了限制可以從哪些節點訪問此卷的約束。 此欄位影響使用此卷的 pod 的排程。
    • persistentVolumeReclaimPolicy:PV回收策略,從其宣告中釋放持久卷時會發生什麼。 有效選項是 Retain(手動建立的 PersistentVolumes 的預設值)、Delete(動態配置的 PersistentVolumes 的預設值)和 Recycle(已棄用)。 此 PersistentVolume 下的卷外掛必須支援回收。
    • photonPersistentDisk:PhotonPersistentDisk 表示附加並掛載在 kubelets 主機上的 PhotonController 永久磁碟。
    • portworxVolume:PortworxVolume 表示連線並掛載在 kubelets 主機上的 portworx 卷。
    • quobyte:Quobyte 表示共享 pod 生命週期的主機上的 Quobyte 掛載。
    • rbd:RBD 表示在共享 pod 生命週期的主機上掛載的 Rados 塊裝置。
    • scaleIO:ScaleIO 表示附加並安裝在 Kubernetes 節點上的 ScaleIO 持久卷。
    • storageClassName:此持久卷所屬的 StorageClass 的名稱。 空值表示該卷不屬於任何 StorageClass。
    • storageos:StorageOS 表示附加並安裝在 Kubernetes 節點上的 StorageOS 卷。
    • volumeMode:volumeMode 定義卷是打算與格式化的檔案系統一起使用還是保持在原始塊狀態。 當規範中不包含檔案系統的值時,它是隱含的。
    • vsphereVolume:VsphereVolume 表示附加並安裝在 kubelets 主機上的 vSphere 卷。
  • status:Kubernetes建立完PV之後自動生成的狀態資訊,無法手動修改。

2.4.3 建立PV

pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: v1
  namespace: default
spec:
  capacity:
    storage: 1Gi  # pv的儲存空間容量
  accessModes: ["ReadWriteOnce"]
  nfs:
    path: /data/volume_test/v1  # 把nfs的儲存空間建立成pv
    server: 192.168.126.40
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v2
  namespace: default
spec:
  capacity:
    storage: 2Gi  # pv的儲存空間容量
  accessModes: ["ReadWriteMany"]
  nfs:
    path: /data/volume_test/v2  # 把nfs的儲存空間建立成pv
    server: 192.168.126.40
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v3
  namespace: default
spec:
  capacity:
    storage: 3Gi  # pv的儲存空間容量
  accessModes: ["ReadOnlyMany"]
  nfs:
    path: /data/volume_test/v3  # 把nfs的儲存空間建立成pv
    server: 192.168.126.40
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v4
  namespace: default
spec:
  capacity:
    storage: 4Gi  # pv的儲存空間容量
  accessModes: ["ReadWriteOnce", "ReadWriteMany"]
  nfs:
    path: /data/volume_test/v4  # 把nfs的儲存空間建立成pv
    server: 192.168.126.40
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v5
  namespace: default
spec:
  capacity:
    storage: 5Gi  # pv的儲存空間容量
  accessModes: ["ReadWriteOnce", "ReadWriteMany"]
  nfs:
    path: /data/volume_test/v5  # 把nfs的儲存空間建立成pv
    server: 192.168.126.40
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v6
  namespace: default
spec:
  capacity:
    storage: 6Gi  # pv的儲存空間容量
  accessModes: ["ReadWriteOnce", "ReadWriteMany"]
  nfs:
    path: /data/volume_test/v6  # 把nfs的儲存空間建立成pv
    server: 192.168.126.40
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v7
  namespace: default
spec:
  capacity:
    storage: 7Gi  # pv的儲存空間容量
  accessModes: ["ReadWriteOnce", "ReadWriteMany"]
  nfs:
    path: /data/volume_test/v7  # 把nfs的儲存空間建立成pv
    server: 192.168.126.40
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v8
  namespace: default
spec:
  capacity:
    storage: 8Gi  # pv的儲存空間容量
  accessModes: ["ReadWriteOnce", "ReadWriteMany"]
  nfs:
    path: /data/volume_test/v8  # 把nfs的儲存空間建立成pv
    server: 192.168.126.40
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v9
  namespace: default
spec:
  capacity:
    storage: 9Gi  # pv的儲存空間容量
  accessModes: ["ReadWriteOnce", "ReadWriteMany"]
  nfs:
    path: /data/volume_test/v9  # 把nfs的儲存空間建立成pv
    server: 192.168.126.40
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v10
  namespace: default
spec:
  capacity:
    storage: 10Gi  # pv的儲存空間容量
  accessModes: ["ReadWriteOnce", "ReadWriteMany"]
  nfs:
    path: /data/volume_test/v10  # 把nfs的儲存空間建立成pv
    server: 192.168.126.40

更新資源清單:

kubectl apply -f pv.yaml

Kubernetes會自動建立pv:

STATUSAvailable表示PV是可用的。

2.4.4 建立PVC繫結PV

pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc1
  namespace: default
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 2Gi

更新資源清單:

kubectl apply -f pvc.yaml

建立完成之後,檢視PVC和哪個PV繫結成功了:

STATUSBound表示已經被綁定了,CLAIN表示綁定了哪一個PVC。

2.4.5 建立Pod掛載PVC

pod-pvc.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-pvc
  namespace: default
  labels:
    app: pod-pvc
spec:
  containers:
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: nginx-html
  restartPolicy: Always
  volumes:
    - name: nginx-html
      persistentVolumeClaim:
        claimName: my-pvc1

更新資源清單:

kubectl apply -f pod-pvc.yaml

檢視Pod是否成功建立:

到nfs-serve節點上,在對應的共享路徑下建立index.html

cd /data/volume_test/v2/
echo 'PVC my-pvc1 Mounted Successed!' > index.html

效果如下:

然後返回控制節點,訪問Pod IP:

PVPVC使用注意事項:

  1. 我們每次建立pvc的時候,需要事先有劃分好的pv,這樣可能不方便,那麼可以在建立pvc的時候直接動態建立一個pv這個儲存類,pv事先是不存在的。
  2. pvc和pv繫結,如果使用預設的回收策略retain,那麼刪除pvc之後,pv會處於released狀態,我們想要繼續使用這個pv,需要手動刪除pv,kubectl delete pv pv_name,刪除pv,不會刪除pv裡的資料,當我們重新建立pvc時還會和這個最匹配的pv繫結,資料還是原來資料,不會丟失。

3、Kubernetes儲存類StorageClass

上面提到的PV和PVC繫結的模式都需要提前建立好PV,然後再由PVC和PV進行繫結,但是如果成千上萬個PVC需要繫結PV,那麼我們需要手動建立深千上萬個PV,對於運維人員來說維護成本很高。所以Kubernetes提供了一種自動建立PV的機制,叫做StorageClass,它的作用就是建立PV模板。Kubernetes管理員提供建立StorageClass可以動態生成一個儲存卷PV供PVC使用。

每個StorageClass都包含欄位provisioner,parameters和reclaimPolicy。

具體來說,StorageClass會定義以下兩個部分:

  1. PV的屬性,比如PV儲存的大小、型別、名稱等
  2. 建立這種PV需要使用的儲存外掛,比如Ceph、NFS、Glusterfs等等

有了這兩部分資訊,Kubernetes就能夠根據使用者提交的PVC,找到對應的StorageClass,然後Kubernetes就會呼叫 StorageClass宣告的儲存外掛,創建出需要的PV。

3.1 StorageClass資源清單

通過命令kubectl explain storageclass檢視StorageClass定義所需的欄位和配置資訊。

  • allowVolumeExpansion:AllowVolumeExpansion 顯示儲存類是否允許卷擴充套件。布林型別,是否許卷擴充套件,PersistentVolume 可以配置成可擴充套件。將此功能設定為true時,允許使用者通過編輯相應的 PVC 物件來調整卷大小。當基礎儲存類的allowVolumeExpansion欄位設定為 true 時,以下型別的卷支援卷擴充套件。

    此功能僅用於擴容卷,不能用於縮小卷。

  • allowedTopologies:限制可以動態供應卷的節點拓撲。 每個卷外掛都定義了自己支援的拓撲規範。 空的 TopologySelectorTerm 列表意味著沒有拓撲限制。 此欄位僅適用於啟用 VolumeScheduling 功能的伺服器。

  • apiVersion:StorageClass所屬的API組和版本資訊,storage.k8s.io/v1,可以根據kubectl explain storageclass.apiVersion查詢當前Kubernetes版本中StorageClass的API組和版本資訊。

  • kind:資源型別,StorageClass,可以根據kubectl explain storageclass.kind命令查詢資源型別

  • metadata:StorageClass資源的元資料

  • mountOptions:此儲存類的動態配置 PersistentVolume 是使用這些 mountOptions 建立的,例如 [ro, soft]。 未驗證 - 如果 PV 無效,則安裝 PV 將失敗。

  • parameters:建立此儲存類的卷的配置程式的引數。

  • provisioner:供應商,Provisioner 表示 Provisioner 的型別。StorageClass需要有一個供應者,用來確定我們使用什麼樣的儲存來建立pv。

  • reclaimPolicy:回收策略,預設的回收策略是Delete

  • volumeBindingMode:VolumeBindingMode 指示應如何配置和繫結 PersistentVolumeClaims。 未設定時,使用VolumeBindingImmediate。 此欄位僅適用於啟用 VolumeScheduling 功能的伺服器。

這裡通過NFS演示StorageClass的使用。

3.2 安裝nfs provisioner

3.2.1 建立執行nfs-provisioner需要的sa賬號

nfs-serviceaccount.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-provisioner
  namespace: default

更新資源清單:

kubectl apply -f nfs-serviceaccount.yaml

結果如下:

什麼是sa?

sa全稱是ServiceAccount。ServiceAccount是為了方便Pod裡面的程序呼叫Kubernetes API或其他外部服務而設計的。

指定了serviceaccount之後,我們把pod創建出來了,我們在使用這個pod時,這個pod就有了我們指定的賬戶的許可權了。

3.2.2 對sa授權

kubectl create clusterrolebinding nfs-provisioner-clusterrolebinding --clusterrole=cluster-admin --serviceaccount=default:nfs-provisioner

效果如下:

3.2.3 安裝nfs-provisioner程式

3.2.3.1 配置NFS共享目錄
# 1. 建立nfs-provisioner共享目錄(在nfs-server伺服器上操作)
mkdir -p /data/nfs_pro

# 2. 配置nfs
# 配置nfs
cat > /etc/exports << EOF
/data/volumes 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v1 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v2 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v3 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v4 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v5 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v6 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v7 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v8 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v9 192.168.126.40/24(rw,no_root_squash)
/data/volume_test/v10 192.168.126.40/24(rw,no_root_squash)
/data/nfs_pro 192.168.126.40/24(rw,no_root_squash)
EOF

# 重新載入配置
exportfs -arv
3.2.3.2 建立Deployment執行nfs-provisioner

nfs-provisioner-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-provisioner
  labels:
    app: nfs-provisioner
spec:
  selector:
    matchLabels:
      app: nfs-provisioner
  strategy:
    type: Recreate
  replicas: 1
  template:
    metadata:
      name: nfs-provisioner
      labels:
        app: nfs-provisioner
    spec:
      serviceAccountName: nfs-provisioner
      containers:
        - name: nfs-provisioner
          image: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0
          imagePullPolicy: IfNotPresent
          volumeMounts:
            - mountPath: /persistentvolumes
              name: nfs-client-root
          env:
            - name: PROVISIONER_NAME
              value: example.com/nfs
            - name: NFS_SERVER
              value: 192.168.126.40
            - name: NFS_PATH
              value: /data/nfs_pro
      restartPolicy: Always
      volumes:
        - name: nfs-client-root
          nfs:
            path: /data/nfs_pro
            server: 192.168.126.40

更新資源清單:

kubectl apply -f nfs-provisioner-deployment.yaml

檢查是否成功建立資源:

3.3 建立StorageClass動態供給PV

nfs-storageclass.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storageclass
  namespace: default
provisioner: example.com/nfs  # 此處的provisioner必須要和安裝的nfs-prosivioner的PROVISIONER_NAME保持一致

provisioner處寫的example.com/nfs應該跟安裝nfs provisioner時候的env下的PROVISIONER_NAME的value值保持一致。

更新資源清單:

kubectl apply -f nfs-storageclass.yaml

檢車是否成功建立StorageClass:

3.4 建立PVC通過StorageClass動態生成PV

nfs-persistentvolumeclaim.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
  namespace: default
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 2Gi
  storageClassName: nfs-storageclass  # 與定義的StorageClass中的name保持一致

更新資源清單:

kubectl apply -f nfs-persistentvolumeclaim.yaml

檢查PVC是否建立成功並且與動態生成的PV繫結:

PVC動態生成PV並繫結的步驟如下:

  1. 供應商:建立一個nfs provisioner
  2. 建立StorageClass,指向上一步中的供應商
  3. 建立PersistentVolumeClaim,指定StorageClass後動態生成PV並繫結

3.5 建立Pod掛載StorageClass動態生成的PVC

podMountPVC.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pvc-pod
  namespace: default
  labels:
    app: pvc-pod
spec:
  containers:
    - name: pvc-pod-container
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: nfs-pvc-volume
  restartPolicy: Always
  volumes:
    - name: nfs-pvc-volume
      persistentVolumeClaim:
        claimName: nfs-pvc  # PVC的名稱

更新資源清單:

kubectl apply -f podMountPVC.yaml

檢查Pod是否建立成功:

然後去nfs-server伺服器上進入到該PV對應的目錄下建立index.html

cd /data/nfs_pro/default-nfs-pvc-pvc-672785ee-acc5-482e-811a-71f8fdf76886

echo 'Create By nfs provisioner PV Successed!' > index.html

效果如下:

然後回到控制節點,訪問該Pod: