K8S 部署 NFS Dynamic Provisioning(动态存储供应)
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 无法读写目录。