K8S 部署 NFS Dynamic Provisioning(動態存儲供應)
本文檔提供完整的 K8s NFS 動態存儲部署流程,包含命名空間創建、RBAC 權限配置、Provisioner 部署、StorageClass 創建及驗證步驟。
2. 部署步驟
2.1 創建命名空間
首先創建獨立的命名空間 nfs-storageclass
,用于隔離 NFS 相關資源:
kubectl create namespace nfs-storageclass
2.2 創建 ServiceAccount 和 RBAC 權限
NFS Provisioner 需要特定權限才能管理 PV/PVC 資源,通過 nfs-rbac.yaml
配置權限:
apiVersion: v1
kind: ServiceAccount
metadata:name: nfs-client-provisioner# 與命名空間保持一致namespace: nfs-storageclass
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: nfs-client-provisioner-runner
rules:# 權限1:獲取節點信息- apiGroups: [""]resources: ["nodes"]verbs: ["get", "list", "watch"]# 權限2:管理 PV(創建/刪除/查看)- apiGroups: [""]resources: ["persistentvolumes"]verbs: ["get", "list", "watch", "create", "delete"]# 權限3:管理 PVC(查看/更新)- apiGroups: [""]resources: ["persistentvolumeclaims"]verbs: ["get", "list", "watch", "update"]# 權限4:查看 StorageClass- apiGroups: ["storage.k8s.io"]resources: ["storageclasses"]verbs: ["get", "list", "watch"]# 權限5:創建事件(用于狀態通知)- apiGroups: [""]resources: ["events"]verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: run-nfs-client-provisioner
subjects:- kind: ServiceAccountname: nfs-client-provisionernamespace: nfs-storageclass
roleRef:kind: ClusterRolename: nfs-client-provisioner-runnerapiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: leader-locking-nfs-client-provisionernamespace: nfs-storageclass
rules:# 權限:管理 endpoints(用于 Provisioner leader 選舉)- apiGroups: [""]resources: ["endpoints"]verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: leader-locking-nfs-client-provisionernamespace: nfs-storageclass
subjects:- kind: ServiceAccountname: nfs-client-provisionernamespace: nfs-storageclass
roleRef:kind: Rolename: leader-locking-nfs-client-provisionerapiGroup: rbac.authorization.k8s.io
2.3 部署 NFS Provisioner
NFS Provisioner 是動態生成 PV 的核心組件,需先拉取鏡像并配置部署文件。
2.3.2 編寫部署文件 nfs-deployment.yaml
kind: Deployment
apiVersion: apps/v1
metadata:name: nfs-client-provisionernamespace: nfs-storageclass
spec:replicas: 1 # 單副本(避免多副本競爭)selector:matchLabels:app: nfs-client-provisionerstrategy:type: Recreate # 重建策略(避免滾動更新導致的狀態不一致)template:metadata:labels:app: nfs-client-provisionerspec:serviceAccountName: nfs-client-provisioner # 關聯前面創建的 ServiceAccountcontainers:- name: nfs-client-provisionerimage: docker.1ms.run/dyrnq/nfs-subdir-external-provisioner:v4.0.2 # 鏡像名volumeMounts:# 掛載 NFS 共享目錄到容器內 /persistentvolumes- name: nfs-client-rootmountPath: /persistentvolumesenv:# 1. Provisioner 名稱(需與后續 StorageClass 的 provisioner 一致)- name: PROVISIONER_NAMEvalue: k8s-sigs.io/nfs-subdir-external-provisioner# 2. NFS 服務器 IP(替換為你的 NFS 服務器地址)- name: NFS_SERVERvalue: 192.168.48.19# 3. NFS 共享目錄路徑(替換為你的 NFS 共享路徑)- name: NFS_PATHvalue: /data/k8s_datavolumes:# 定義 NFS 掛載卷- name: nfs-client-rootnfs:server: 192.168.48.19 # NFS 服務器 IP(與上面一致)path: /data/k8s_data # NFS 共享路徑(與上面一致)
2.4 創建 StorageClass
StorageClass 是 PVC 申請存儲的「模板」,通過 nfs-sc.yaml
配置:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: nfs-client # StorageClass 名稱(PVC 需引用此名)namespace: nfs-storageclass
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # 與 Provisioner 環境變量 PROVISIONER_NAME 一致
parameters:# 1. PV 在 NFS 中的目錄結構:${PVC命名空間}/${PVC名稱}(便于區分不同 PVC 的存儲)pathPattern: ${.PVC.namespace}/${.PVC.name}# 2. PVC 刪除時的策略:delete 表示刪除 NFS 中對應的目錄(可選:retain 保留目錄)onDelete: delete
2.5 驗證 NFS 存儲
通過創建 PVC 和 PV(可選,動態模式下 PV 會自動生成)驗證存儲是否可用。
2.5.1 創建 PVC(nfs-pvc.yaml
)
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: nfs # PVC 名稱# annotations: # 可選:添加注解(如指定 StorageClass,若未指定則使用默認 SC)
spec:accessModes:- ReadWriteMany # NFS 支持多節點讀寫(RWX)storageClassName: nfs-client # 引用前面創建的 StorageClassresources:requests:storage: 1Mi # 申請的存儲容量(最小 1Mi,可根據需求調整)
2.5.2 手動創建 PV(可選,動態模式可省略)
若需手動綁定 PV(非動態模式),可創建 nfs-pv.yaml
:
apiVersion: v1
kind: PersistentVolume
metadata:name: nfs-pv # PV 名稱# namespace: kube-system # PV 是集群級資源,無需指定命名空間(此處原配置有誤,建議刪除)
spec:capacity:storage: 30Gi # PV 容量(需 ≥ PVC 申請的容量)accessModes:- ReadWriteMany # 與 PVC 的 accessModes 一致persistentVolumeReclaimPolicy: Retain # PVC 刪除后保留 PV 數據(可選:Delete 自動刪除)storageClassName: nfs-client # 關聯 StorageClassnfs:server: 192.168.48.19 # NFS 服務器 IPpath: /data/k8s_data # NFS 共享路徑
2.6 執行所有 YAML 文件
將上述所有 YAML 文件放在同一目錄,執行部署:
kubectl apply -f ./
3. 驗證部署結果
3.1 查看 NFS Provisioner 組件狀態
kubectl get all -n nfs-storageclass
預期輸出(確保 Pod 為 Running
狀態):
NAME READY STATUS RESTARTS AGE
pod/nfs-client-provisioner-c8b7f495d-b2zpk 1/1 Running 0 64mNAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nfs-client-provisioner 1/1 1 1 82mNAME DESIRED CURRENT READY AGE
replicaset.apps/nfs-client-provisioner-c8b7f495d 1 1 1 82m
3.2 查看 StorageClass
kubectl get sc
預期輸出(確保 PROVISIONER
正確且 VOLUMEBINDINGMODE
為 Immediate
):
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 83m
3.3 查看 PVC 和 PV
# 查看 PVC(確保 STATUS 為 Bound)
kubectl get pvc# 查看 PV(確保 STATUS 為 Bound,且 CLAIM 關聯 PVC)
kubectl get pv
預期輸出:
# PVC 輸出
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
nfs Bound nfs-pv 30Gi RWX nfs-client <unset> 83m# PV 輸出
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
nfs-pv 30Gi RWX Retain Bound default/nfs nfs-client <unset> 84m
關鍵說明
- 動態 vs 靜態:
- 動態模式(推薦):創建 PVC 后,Provisioner 會自動生成 PV 并綁定,無需手動創建 PV;
- 靜態模式:需先手動創建 PV,再創建 PVC 綁定。
- NFS 服務器配置:
需確保 NFS 服務器已正確配置共享目錄(如/data/k8s_data
),且 K8s 所有節點能訪問 NFS 服務器(防火墻開放 2049 端口)。 - 權限問題:
NFS 共享目錄需設置足夠權限(如chmod 777 /data/k8s_data
),避免 Provisioner 無法讀寫目錄。