k8s StorageClass 儲存類

misakivv發表於2024-09-24

目錄
  • 一、概述
    • 1、StorageClass 物件定義
    • 2、StorageClass YAML 示例
  • 二、StorageClass 欄位
    • 1、provisioner(儲存製備器)
      • 1.1、內建製備器
      • 1.2、第三方製備器
    • 2、reclaimPolicy(回收策略)
    • 3、allowVolumeExpansion(允許卷擴充套件)
    • 4、mountOptions(掛載選項)
    • 5、volumeBindingMode(卷繫結模式)
      • 5.1、Immediate
      • 5.2、WaitForFirstConsumer
    • 6、allowedTopologies(允許的拓撲結構)
      • 6.1、示例
    • 7、parameters(儲存引數)
      • 7.1、示例
      • 7.2、儲存引數(AWSElasticBlockStore)
    • 8、設定預設的 StorageClass(storageclass.kubernetes.io/is-default-class)
      • 8.1、示例
      • 8.2、修改已有的 StorageClass
        • 8.2.1、將存在的 SC 設定為預設
        • 8.2.2、將存在的 SC 設定為非預設
  • 三、例項 -- 使用 NFS 型別的 StorageClass 動態建立 PV
    • 1、配置 NFS 服務端
      • 1.1、master 節點安裝 nfs-utils 包
      • 1.2、master 節點建立共享目錄
      • 1.3、編輯/etc/exports檔案
      • 1.4、應用新的匯出設定
      • 1.5、重啟並設定 NFS 開機自啟
      • 1.6、檢查 NFS 共享
    • 2、配置 NFS 客戶端
      • 2.1、安裝 nfs-utils 包
      • 2.2、建立目錄掛載 NFS 共享
        • 2.2.1、解除安裝錯誤的掛載點
      • 2.3、重啟並設定 NFS 開機自啟
      • 2.4、系統啟動自動掛載 NFS 共享(非必要)
      • 2.5、檢視掛載狀態
    • 3、建立儲存類
    • 4、建立 RBAC 許可權
    • 5、建立 provisioner
    • 6、建立 PVC
    • 7、觀察 PV 是否動態建立
    • 8、建立使用同一 PVC 的多個 Pod
    • 9、向共享儲存寫入資料
    • 10、從另一個 Pod 讀取資料
    • 11、檢視 nfs 服務端與客戶端的共享目錄
      • 11.1、PV 目錄建立的流程
      • 11.2、PV 目錄的結構
    • 12、修改 NFS 伺服器共享目錄內容檢視容器內部變化
  • 四、例項 -- 動態建立 PVC 和 PV
    • 1、建立 Headless Service
    • 2、建立 StatefulSet
    • 3、觀察 Pod狀態
    • 4、觀察到 PVC 與 PV 已經動態建立並相互繫結了
    • 5、每一個 Pod 都會透過繫結 PVC 獲取一塊獨立的 PV

一、概述

叢集級別資源,StorageClass 是 Kubernetes 中的一種資源物件,它定義了建立 Persistent Volume (PV) 的策略和方法。StorageClass 主要用於實現 PV 的動態供應,這意味著當使用者建立了一個 Persistent Volume Claim (PVC) 時,Kubernetes 會根據所指定的 StorageClass 自動建立一個符合要求的 PV 並將其繫結到 PVC 上

StorageClass 作為對儲存資源的抽象定義,對使用者設定的 PVC 申請遮蔽後端儲存的細節,一方面減少了使用者對於儲存資源細節的關注,另一方面減輕了管理員手工管理 PV 的工作,由系統自動完成 PV 的建立和繫結,實現動態的資源供應。基於 StorageClass 的動態資源供應模式將逐步成為雲平臺的標準儲存管理模式。

1、StorageClass 物件定義

StorageClass 資源物件的定義主要包括:名稱、後端儲存的提供者 (provisioner)、後端儲存的相關引數配置(parameters)和回收策略(reclaimPolicy)、卷繫結模式(volumeBindingMode)

  • StorageClass 的名稱很重要,將在建立 PVC 時引用,管理員應該準確命名具有不同儲存特性的 StorageClass。

  • StorageClass 一旦被建立,則無法修改,如需更改,則只能刪除原 StorageClass 資源物件並重新建立。

2、StorageClass YAML 示例

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  # 儲存類的名稱,使用者在 PVC 中引用
  name: example-storage-class
  storageclass.kubernetes.io/is-default-class: "true"  # 設定為預設的 StorageClass
# 動態製備器的名稱,需要與已安裝的製備器匹配
provisioner: kubernetes.io/aws-ebs # 例子中使用的是 AWS EBS 製備器
# reclaimPolicy 定義了當 PVC 被刪除時,PV 應該如何處理
reclaimPolicy: Delete # 可選值為 Retain 或 Delete
# 允許卷擴充套件
allowVolumeExpansion: true # 可選值為 true 或 false
# 定義了卷繫結到 Pod 的模式
volumeBindingMode: Immediate # 可選值為 Immediate 或 WaitForFirstConsumer
# 定義了儲存系統需要的引數,這些引數會傳遞給製備器
parameters:
  # 儲存型別,根據製備器和儲存系統的要求設定
  type: gp2 # AWS EBS 的例子,對於其他系統可能有不同的值
  # 儲存 IOPS 效能,某些儲存系統可能需要這個引數
  iopsPerGB: "10" # 例子,具體值根據需求和製備器支援設定
  # 儲存的最小 IOPS 值,某些儲存系統可能需要這個引數
  minimumIOPS: "1000" # 例子,具體值根據需求和製備器支援設定
  # 儲存的最大 IOPS 值,某些儲存系統可能需要這個引數
  maximumIOPS: "20000" # 例子,具體值根據需求和製備器支援設定
  # 儲存的加密選項,某些儲存系統可能支援加密
  encrypted: "true" # 例子,具體值根據需求和製備器支援設定
  # 儲存的區域,對於跨區域儲存系統可能需要這個引數
  availabilityZone: "us-east-1a" # 例子,具體值根據製備器和儲存系統的要求設定
  # 儲存的效能等級,某些儲存系統可能提供不同的效能等級
  performance: "high" # 例子,具體值根據製備器和儲存系統的要求設定
# 定義了掛載選項,這些選項會在 PV 被掛載到節點時使用
mountOptions:
  - debug # 例子,具體值根據需求設定,可能包括 "debug", "defaults", "ro" 等
  # - other-option # 可以新增額外的掛載選項
# 允許的拓撲約束,定義了儲存可以被哪些節點訪問
allowedTopologies:
  - matchLabelExpressions:
    - key: topology.kubernetes.io/region
      values:
        - us-east-1
    - key: topology.kubernetes.io/zone
      values:
        - us-east-1a

storageclass

二、StorageClass 欄位

1、provisioner(儲存製備器)

provisioner 指定了用於動態建立 PersistentVolume (PV) 的製備器(Provisioner)。製備器是一個外掛,它負責在後端儲存系統中根據 PersistentVolumeClaim (PVC) 的請求來建立儲存資源,不同的儲存外掛支援不同的儲存後端和服務提供商。當 PVC 被建立並且與之關聯的 StorageClass 指定了一個製備器時,Kubernetes 會呼叫這個製備器來自動建立相應的 PV。

卷外掛 內建製備器 配置示例
AWSElasticBlockStore AWS EBS
AzureFile Azure檔案(已棄用)
AzureDisk Azure Disk
CephFS - -
Cinder Open Stack Cinder
FC - -
FlexVolume - -
GCEPersistentDisk gcePD
Glusterfs GlusterFS
iSCSI - -
Local - Local
NFS - NFS
PortworxVolume portworx-volume
RBD ceph-rbd
VsphereVolume Vsphere

1.1、內建製備器

Kubernetes 內建支援的 Provisioner 的命名都以 "kubernetes.io/" 開頭

  • kubernetes.io/aws-ebs:用於在 AWS 上建立 Elastic Block Store (EBS) 卷。
  • kubernetes.io/azure-disk:用於在 Azure 上建立磁碟。
  • kubernetes.io/gce-pd:用於在 Google Cloud Platform (GCP) 上建立持久磁碟。
  • kubernetes.io/cinder:用於在 OpenStack 上建立 Cinder 卷。

1.2、第三方製備器

為了符合 StorageClass 的用法,自定義 Provisioner 需要符合儲存卷的開發規範,外部儲存供應商的作者對程式碼、提供方式、執行方式、儲存外掛(包括Flex)等具有完全的自由控制權。

程式碼倉庫 kubernetes-sigs/sig-storage-lib-external-provisioner 包含一個用於為外部製備器編寫功能實現的類庫。你可以訪問程式碼倉庫 kubernetes-sigs/sig-storage-lib-external-provisioner 瞭解外部驅動列表。

例如,對NFS型別,Kubernetes沒有提供內部的Provisioner,但可以使用外部的Provisioner。也有許多第三方儲存提供商自行提供外部的Provisioner。

2、reclaimPolicy(回收策略)

透過動態資源供應模式建立的PV將繼承在StorageClass資源物件上設定的回收策略,配置欄位名稱為“reclaimPolicy“,可以設定的選項包括Delete(刪除)和 Retain(保留)。

  • 如果StorageClass沒有指定reclaimPolicy,則預設值為Delete。
  • 對於管理員手工建立的仍被StorageClass管理的PV,將使用建立PV時設定的資源回收策略。

3、allowVolumeExpansion(允許卷擴充套件)

PV 可以被配置為允許擴容,當 StorageClass 資源物件的 allowVolumeExpansion欄位被設定為true時,將允許使用者透過編輯PVC的儲存空間自動完成PV的擴容。

下表描述了支援儲存擴容的Volume型別和要求的Kubernetes最低版本:

支援儲存擴容的 Volume 型別 Kubernetes 最低版本
gcePersistentDisk 1.11
awsElasticBlock Store 1.11
Cinder 1.11
glusterfs 1.11
RBD 1.11
Azure File 1.11
Azure Disk 1.11
Portworx 1.13
FlexVolume 1.14(Alpha)
CSI 1.16(Beta)

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

4、mountOptions(掛載選項)

透過StorageClass資源物件的mountOptions欄位,系統將為動態建立的PV設定掛載選項。

並不是所有 PV型別都支援掛載選項,如果 PV不支援但 StorageClass 設定了該欄位,則 PV將會建立失敗。另外,系統不會對掛載選項進行驗證,如果設定了錯誤的選項,則容器在掛載儲存時將直接失敗。

5、volumeBindingMode(卷繫結模式)

StorageClass 資源物件的 volumeBindingMode 欄位設定用於控制何時將 PVC 與動態建立的 PV 繫結。

目前支援的繫結模式包括: Immediate 和 WaitForFirstConsumer。

5.1、Immediate

儲存繫結模式的預設值為 Immediate,表示當一個PersistentVolumeClaim (PVC)建立出來時,就動態建立PV並進行PVC與PV的繫結操作。

需要注意的是,對於拓撲受限 (Topology-limited) 或無法從全部Node訪問的後端儲存,將在不瞭解Pod排程需求的情況下完成PV的繫結操作,這可能會導致某些Pod無法完成排程。

5.2、WaitForFirstConsumer

WaitForFirstConsumer繫結模式表示PVC與PV的繫結操作延遲到第一個使用 PVC的Pod建立出來時再進行。

系統將根據Pod的排程需求,在Pod所在的Node上建立PV,這些排程需求可以透過以下條件(不限於)進行設定:

  • Pod對資源的需求

  • Node Selector

  • Pod親和性和反親和性設定

  • Taint和Toleration設定

目前支援 WaitForFirstConsumer 繫結模式的儲存捲包括:

  • AWSElasticBlockStore
  • AzureDisk
  • GCEPersistentDisk.

另外,有些儲存外掛透過預先建立好的PV繫結支援WaitForFirstConsumer模式,比如:

  • AWSElasticBlockStore
  • AzureDisk
  • GCEPersistentDisk
  • Local

6、allowedTopologies(允許的拓撲結構)

在使用WaitForFirstConsumer模式的環境中,如果仍然希望基於特定拓撲資訊(Topology)進行PV繫結操作,則在StorageClass的定義中還可以透過 allowedTopologies欄位進行設定。

6.1、示例

下面的例子透過 matchLabelExpressions 設定目標 Node 的標籤選擇條件 (zone=us-central1-a或 us-central1-b) PV 將在滿足這些條件的 Node 上允許建立

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard
provisioner: kubernetes.io/example
parameters:
  type: pd-standard
volumeBindingMode: WaitForFirstConsumer
allowedTopologies:
- matchLabelExpressions:
  - key: topology.kubernetes.io/zone
    values:
    - us-central-1a
    - us-central-1b

7、parameters(儲存引數)

後端儲存資源提供者的引數設定,不同的 Provisioner 可能提供不同的引數設定。某些引數可以不顯示設定,Provisioner 將使用其預設值。

目前 StorageClass 資源物件支援設定的儲存引數最多為 512個,全部 key 和 value 所佔的空間不能超過 256KiB。

7.1、示例

下面舉常見儲存提供商(Provisioner)提供的 StorageClass 儲存引數示例(以AWSElasticBlockStore儲存卷為例子):

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  csi.storage.k8s.io/fstype: xfs
  type: io1
  iopsPerGB: "50"
  encrypted: "true"
allowedTopologies:
- matchLabelExpressions:
  - key: topology.ebs.csi.aws.com/zone
    values:
    - us-east-2c

7.2、儲存引數(AWSElasticBlockStore)

AWS EBS 儲存引數

AWS EBS 儲存引數

  • type (必需)

    • 定義 EBS 卷的儲存型別(預設值gp3)。例如:
      • gp2:通用目的 SSD
      • io1:提供高 IOPS 的 SSD
      • io2:適用於需要大量 IOPS 的應用程式的新一代 SSD
      • st1:透過 HDD 儲存最佳化的卷
      • sc1:透過冷 HDD 儲存最佳化的卷
  • iopsPerGB (可選,僅當 type 為 io1 或 io2 時有效)

    • 定義每個 GiB 提供的 IOPS 數量。
    • 例如,如果 type 為 io1 並且 iopsPerGB 設定為 10,則 100 GiB 的卷將提供 1000 IOPS。
  • iops (可選,僅當 type 為 io1 時有效)

    • 直接定義卷的 IOPS 總數。例如,iops: "1000" 表示卷將提供 1000 IOPS。
  • throughput (可選,僅當 type 為 st1 時有效)

    • 定義卷的吞吐量,以 MiB/s 為單位。例如,throughput: "500" 表示卷的吞吐量為 500 MiB/s。
  • encrypted (可選)

    • 布林值,指示是否應該加密 EBS 卷。例如,encrypted: "true"。
  • kmsKeyId (可選)

    • 指定用於加密 EBS 卷的 KMS 金鑰 ID。例如,kmsKeyId: "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"。
  • fsType (可選)

    • 定義檔案系統型別。例如,fsType: "ext4"。
  • volumeSize (可選)

    • 定義請求的卷大小(以 GiB 為單位)。例如,volumeSize: "100" 表示請求 100 GiB 的卷。
  • availabilityZone (可選)

    • 定義 EBS 卷應該建立在哪個可用區。例如,availabilityZone: "us-west-2a"。
  • multiAttachEnabled (可選)

    • 布林值,指示是否啟用多附加。例如,multiAttachEnabled: "true" 允許卷同時附加到多個例項。
  • snapshotId (可選)

    • 定義用於建立 EBS 卷的快照 ID。例如,snapshotId: "snap-0123456789abcdef0"。
  • tags (可選)

    • 定義一組鍵值對,用於標記 EBS 卷。例如:

    • tags:
        - key: "project"
          value: "myproject"
        - key: "owner"
          value: "myteam"
      

8、設定預設的 StorageClass(storageclass.kubernetes.io/is-default-class)

在建立 SC 的 YAML 檔案時,需要在 metadata 部分新增一個註解,以標記該 SC 為預設。

8.1、示例

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: low-latency
  annotations:
    storageclass.kubernetes.io/is-default-class: "false"
provisioner: csi-driver.example-vendor.example
reclaimPolicy: Retain # 預設值是 Delete
allowVolumeExpansion: true
mountOptions:
  - discard # 這可能會在塊儲存層啟用 UNMAP/TRIM
volumeBindingMode: WaitForFirstConsumer
parameters:
  guaranteedReadWriteLatency: "true" # 這是服務提供商特定的

8.2、修改已有的 StorageClass

8.2.1、將存在的 SC 設定為預設

kubectl patch storageclass <sc-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

8.2.2、將存在的 SC 設定為非預設

kubectl patch storageclass <sc-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'

如果你在叢集中的多個 StorageClass 上將 storageclass.kubernetes.io/is-default-class 註解設定為 true,然後建立一個未設定 storageClassName 的 PersistentVolumeClaim (PVC), Kubernetes 將使用最近建立的預設 StorageClass。

三、例項 -- 使用 NFS 型別的 StorageClass 動態建立 PV

角色 主機名 ip地址
nfs 服務端 + master 節點 k8s-master1 192.168.112.10
nfs 客戶端 + node 節點 k8s-node1 192.168.112.20
nfs 客戶端 + node 節點 k8s-node2 192.168.112.30

1、配置 NFS 服務端

1.1、master 節點安裝 nfs-utils 包

yum install -y nfs-utils

1.2、master 節點建立共享目錄

mkdir -pv /data/nfs

image-20240924155320111

1.3、編輯/etc/exports檔案

echo "/data/nfs 192.168.112.0/24(rw,sync,no_root_squash)" > /etc/exports

image-20240924155351594

1.4、應用新的匯出設定

exportfs -arv

image-20240924155422292

1.5、重啟並設定 NFS 開機自啟

systemctl restart nfs && systemctl enable nfs

image-20240924155455473

1.6、檢查 NFS 共享

showmount -e localhost

image-20240924155520947

2、配置 NFS 客戶端

所有 node 節點

2.1、安裝 nfs-utils 包

yum install -y nfs-utils

2.2、建立目錄掛載 NFS 共享

mkdir -pv /mnt/nfs

mount -t nfs 192.168.112.10:/data/nfs /mnt/nfs

image-20240924155629964

image-20240924155646500

2.2.1、解除安裝錯誤的掛載點

如果在執行 mount -t nfs 命令時出現了錯誤,比如使用了錯誤的引數或者路徑,你可以透過解除安裝當前的掛載點然後再重新掛載來修正錯誤。

  • 確認當前的掛載狀態

    • 使用 mount 命令檢視當前的所有掛載情況,找到錯誤掛載的條目。

    • mount
      
  • 解除安裝錯誤的掛載點

    • # 知道錯誤的掛載點
      sudo umount /mnt/nfs
      
    • # 知道 nfs 服務端 IP 地址和共享目錄路徑
      sudo umount 192.168.112.10:/data/nfs
      
  • 解除安裝時遇到裝置/檔案正在使用中

    • umount -f /mnt/nfs
      
    • 強制解除安裝可能會導致資料丟失,因此只有在確定沒有資料寫入的情況下才這樣做。

2.3、重啟並設定 NFS 開機自啟

systemctl restart nfs && systemctl enable nfs

image-20240924155723058

image-20240924155742122

2.4、系統啟動自動掛載 NFS 共享(非必要)

echo '192.168.112.10:/data/nfs /mnt/nfs nfs defaults 0 0' >> /etc/fstab

2.5、檢視掛載狀態

mount | grep 192.168.112.10

image-20240924155822568

image-20240924155839917

3、建立儲存類

cat >> nfs-storage.yaml << EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storage
  namespace: default
  labels:
    environment: test
provisioner: fuseim.pri/ifs
reclaimPolicy: Retain
volumeBindingMode: Immediate
EOF
kubectl apply -f nfs-storage.yaml

image-20240924160002838

4、建立 RBAC 許可權

cat >> rbac.yaml << EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
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: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: default                                      
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: default                                        
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: default
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
EOF
kubectl apply -f rbac.yaml

image-20240924160138731

5、建立 provisioner

部署 NFS Client Provisioner,這是一個 Kubernetes 外部儲存外掛,用於動態建立 NFS PV。

cat >> nfs-provisioner.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  namespace: default
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs       # 這裡必須要填寫storageclass中的PROVISIONER名稱資訊一致
            - name: NFS_SERVER
              value: 192.168.112.10       # 指定NFS伺服器的IP地址
            - name: NFS_PATH
              value: /data/nfs            # 指定NFS伺服器中的共享掛載目錄
      volumes:
        - name: nfs-client-root           # 定義持久化卷的名稱,必須要上面volumeMounts掛載的名稱一致
          nfs:
            server: 192.168.112.10        # 指定NFS所在的IP地址
            path: /data/nfs               # 指定NFS伺服器中的共享掛載目錄
EOF
kubectl apply -f nfs-provisioner.yaml

image-20240924160318664

6、建立 PVC

cat >> nfs-pvc.yaml << EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-pvc
  namespace: default
  labels:
    environment: test
    app: nginx
spec:
  storageClassName: nfs-storage
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Mi
EOF
kubectl apply -f nfs-pvc.yaml

image-20240924160452587

7、觀察 PV 是否動態建立

kubectl get pvc,pv,sc

image-20240924160547824

發現使用 NFS Client Provisioner 可以動態建立 pv 並與 PVC 繫結處於 Bound 狀態

8、建立使用同一 PVC 的多個 Pod

cat >> nfs-pod1.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
  name: nfs-pod1
spec:
  containers:
    - name: container1
      image: nginx:1.16.0
      volumeMounts:
        - name: shared-data
          mountPath: /usr/share/nginx/html
  volumes:
    - name: shared-data
      persistentVolumeClaim:
        claimName: nginx-pvc
EOF
cat >> nfs-pod2.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
  name: nfs-pod2
spec:
  containers:
    - name: container2
      image: nginx:1.16.0
      volumeMounts:
        - name: shared-data
          mountPath: /usr/share/nginx/html
  volumes:
    - name: shared-data
      persistentVolumeClaim:
        claimName: nginx-pvc
EOF
kubectl apply -f nfs-pod1.yaml -f nfs-pod2.yaml

image-20240924161233878

9、向共享儲存寫入資料

kubectl exec -it nfs-pod1 -- /bin/bash
echo "hello from nfs-pod1" > /usr/share/nginx/html/index.html
exit

10、從另一個 Pod 讀取資料

kubectl exec -it nfs-pod2 -- /bin/bash
cat /usr/share/nginx/html/index.html
exit

image-20240924161407667

11、檢視 nfs 服務端與客戶端的共享目錄

tree /data/nfs
tree /mnt/nfs

image-20240924162347114

image-20240924162410192

image-20240924162429327

這個新出現的目錄(PV 目錄) default-nginx-pvc-pvc-c8a8b825-1577-4f76-ba1f-a1302941b333 用於對映 PersistentVolume (PV) 到 NFS 伺服器上的具體路徑

11.1、PV 目錄建立的流程

  • 建立 PVC:
    • 當你建立 PVC 時,Kubernetes 會根據 StorageClass 自動建立 PV。
  • Provisioner 建立 PV:
    • Provisioner 會在 NFS 伺服器上的共享目錄下建立一個新目錄,目錄名稱包含了 PVC 的名稱和 UUID。
  • 掛載到 Pod:
    • 建立的 PV 會被掛載到 Pod 中指定的路徑。

11.2、PV 目錄的結構

/<共享目錄>/<名稱空間>-<PVC名稱>-<PV名稱>
  • 共享目錄:
    • 這是你在 NFS 伺服器上建立並共享出去的目錄,比如 nfs 服務端的 /data/nfs 以及 nfs 客戶端的 /mnt/nfs
  • 名稱空間:
    • 這是 Kubernetes 中的一個邏輯分組,用於隔離不同的應用程式和服務。PVC 所屬的名稱空間名稱。
  • PVC 名稱:
    • 這是在 Kubernetes 中建立的 PersistentVolumeClaim 的名稱。
  • PV 名稱:
    • 這是根據 PVC 動態建立出來的 PersistentVolume 的名稱,通常是一個帶有 UUID 的字串。
kubectl get pvc nginx-pvc -o custom-columns='PVC-NAMESPACE:.metadata.namespace,PVC-NAME:.metadata.name'

kubectl get pv pvc-c8a8b825-1577-4f76-ba1f-a1302941b333 -o custom-columns='PV-NAME:.metadata.name'

image-20240924165542755

12、修改 NFS 伺服器共享目錄內容檢視容器內部變化

可以發現也是同步更新的

cd /data/nfs/default-nginx-pvc-pvc-c8a8b825-1577-4f76-ba1f-a1302941b333

echo "hello from nfs-server" > index.html

kubectl get pods -o wide
 
curl 10.244.1.3

curl 10.244.2.8

image-20240924170701945

四、例項 -- 動態建立 PVC 和 PV

1、建立 Headless Service

cat >> nginx-headless.yaml << EOF
apiVersion: v1
kind: Service
metadata:
  name: nginx-headless
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
EOF
kubectl apply -f nginx-headless.yaml

kubectl get svc -l app=nginx -o wide

image-20240924192752244

2、建立 StatefulSet

cat >> sts.yaml << EOF
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 5
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.0
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates: # 透過模板化方式繫結
  - metadata:
      name: www # 指定pvc的名字
      annotations:
        volume.beta.kubernetes.io/storage-class: "nfs-storage" # 只指定了storageClass
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 5Mi
EOF
kubectl apply -f sts.yaml

3、觀察 Pod狀態

由於是 statefulset 控制器所以 pod 是按順序建立的

kubectl get pods -l app=nginx -w

image-20240924192857717

4、觀察到 PVC 與 PV 已經動態建立並相互繫結了

kubectl get pvc -l 'app=nginx,environment!=test'
kubectl get pv | grep -v "default/nginx-pvc"

image-20240924193217284

5、每一個 Pod 都會透過繫結 PVC 獲取一塊獨立的 PV

kubectl get pod web-0 -o custom-columns='PVC-NAME:.spec.volumes[*].persistentVolumeClaim.claimName'

kubectl get pod web-1 -o custom-columns='PVC-NAME:.spec.volumes[*].persistentVolumeClaim.claimName'

kubectl get pod web-2 -o custom-columns='PVC-NAME:.spec.volumes[*].persistentVolumeClaim.claimName'

kubectl get pod web-3 -o custom-columns='PVC-NAME:.spec.volumes[*].persistentVolumeClaim.claimName'

kubectl get pod web-4 -o custom-columns='PVC-NAME:.spec.volumes[*].persistentVolumeClaim.claimName'

image-20240924193309657

相關文章