一、StorageClass 简介
1.1 什么是 StorageClass
StorageClass(存储类)是 Kubernetes 中用于描述存储类型和策略的资源对象。它为管理员提供了一种方式来描述他们提供的存储的"类别",不同的类别可能会映射到不同的服务质量等级、备份策略或由集群管理员决定的任意策略。
1.2 StorageClass 的核心作用
- 动态卷供应(Dynamic Volume Provisioning):自动创建 PV,无需管理员手动预配置
- 存储抽象:为用户提供统一的存储访问接口,隐藏底层存储实现细节
- 策略管理:定义存储的回收策略、挂载选项等
- 多存储后端支持:支持不同类型的存储系统(NFS、云存储、本地存储等)
1.3 StorageClass 与 PV/PVC 的关系
用户创建 PVC → 指定 StorageClass → Provisioner 动态创建 PV → PVC 绑定 PV → Pod 使用存储二、StorageClass 核心组件
2.1 Provisioner(存储提供者)
Provisioner 是负责动态创建 PV 的组件,常见类型包括:
内置 Provisioner:
kubernetes.io/aws-ebs(AWS EBS)kubernetes.io/gce-pd(Google Cloud Persistent Disk)kubernetes.io/azure-disk(Azure Disk)
外部 Provisioner:
k8s-sigs.io/nfs-subdir-external-provisioner(NFS)csi.driver.name(CSI 驱动)
2.2 Parameters(参数)
定义存储的具体配置参数,不同 Provisioner 支持的参数不同。
2.3 ReclaimPolicy(回收策略)
Delete:默认策略,PVC 删除时自动删除 PV 和底层存储Retain:保留 PV 和数据,需要手动清理
2.4 VolumeBindingMode(卷绑定模式)
Immediate:立即绑定(默认)WaitForFirstConsumer:等待第一个消费者(Pod)调度后再绑定
三、NFS StorageClass 实验环境搭建
3.1 环境准备
本实验需要以下环境:
- Kubernetes 集群(v1.18+)
- NFS 服务器(IP: 10.128.0.5)
- NFS 共享目录:
/nfs/share
3.2 NFS 服务器配置
在 NFS 服务器上执行以下命令:
bash
dnf install nfs-utils rpcbind
mkdir -p /nfs/share
chown nobody:nobody /nfs/share
chmod 755 /nfs/share
echo "/nfs/share *(rw,sync,no_subtree_check,no_root_squash)" >> /etc/exports
systemctl enable --now rpcbind
systemctl enable --now nfs-server
exportfs -ra
showmount -e localhost3.3 Kubernetes 节点配置
在所有 Kubernetes 节点上安装 NFS 客户端:
bash
dnf install nfs-utils
apt-get update && apt-get install -y nfs-common
showmount -e 10.128.0.5四、部署 NFS External Provisioner
4.1 创建命名空间
bash
kubectl create namespace nfs-storageclass4.2 部署 RBAC 权限
创建 serviceAccount.yaml 文件:
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:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- 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: nfs-storageclass
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: nfs-storageclass
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: nfs-storageclass
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: nfs-storageclass
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io4.3 部署 NFS Provisioner
创建 nfs-client.yaml 文件:
yaml
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-client-provisioner
namespace: nfs-storageclass
spec:
replicas: 1
selector:
matchLabels:
app: nfs-client-provisioner
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: k8s.dockerproxy.com/sig-storage/nfs-subdir-external-provisioner:v4.0.2
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 10.140.0.8 # NFS 服务器 IP
- name: NFS_PATH
value: /nfs/share # NFS 共享路径
volumes:
- name: nfs-client-root
nfs:
server: 10.140.0.8
path: /nfs/share4.4 创建 StorageClass
创建 storageClass.yaml 文件:
yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client
namespace: nfs-storageclass
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
pathPattern: ${.PVC.namespace}/${.PVC.name}
onDelete: delete参数说明:
pathPattern:定义在 NFS 服务器上创建的目录路径模式${.PVC.namespace}:PVC 所在的命名空间${.PVC.name}:PVC 的名称
onDelete:PVC 删除时的行为delete:删除对应的 NFS 目录retain:保留 NFS 目录
五、StorageClass 实验操作
5.1 部署所有组件
bash
kubectl apply -f serviceAccount.yaml
kubectl apply -f nfs-client.yaml
kubectl apply -f storageClass.yaml
kubectl get pods -n nfs-storageclass
kubectl get storageclass5.2 创建测试 PVC 和 Pod
创建 pod.yaml 测试文件:
yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
spec:
accessModes:
- ReadWriteMany # 支持多节点读写
resources:
requests:
storage: 1Mi # 请求 1MB 存储空间
storageClassName: nfs-client # 指定使用的 StorageClass
---
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: wangyanglinux/myapp:v1.0 # Nginx 镜像
volumeMounts:
- name: nfs-pvc
mountPath: "/usr/share/nginx/html" # 挂载到 Nginx 网站根目录
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim5.3 执行测试
bash
kubectl apply -f pod.yaml
kubectl get pvc test-claim
kubectl get pv
kubectl get pods test-pod -o wide
ls -la /nfs/share/default/test-claim/5.4 验证存储功能
bash
POD_IP=$(kubectl get pod test-pod -o jsonpath='{.status.podIP}')
curl $POD_IP
kubectl exec -it test-pod -- /bin/bash
echo "Hello from NFS StorageClass!" > /usr/share/nginx/html/index.html
exit
curl $POD_IP
cat /nfs/share/default/test-claim/index.html六、StorageClass 高级特性
6.1 设置默认 StorageClass
bash
kubectl patch storageclass nfs-client -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
kubectl get storageclass6.2 卷绑定模式配置
yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client-wait
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
volumeBindingMode: WaitForFirstConsumer # 等待第一个消费者
parameters:
pathPattern: ${.PVC.namespace}/${.PVC.name}
onDelete: delete6.3 挂载选项配置
yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client-custom
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
mountOptions:
- hard # 硬挂载
- nfsvers=4 # 使用 NFSv4
- timeo=600 # 超时时间
parameters:
pathPattern: ${.PVC.namespace}/${.PVC.name}
onDelete: retain # 保留数据七、故障排查与维护
7.1 常见问题诊断
bash
kubectl logs -n nfs-storageclass deployment/nfs-client-provisioner
kubectl describe pvc test-claim
kubectl describe storageclass nfs-client
kubectl exec -it test-pod -- df -h
journalctl -u nfs-server -f7.2 性能优化建议
NFS 挂载参数优化:
yamlmountOptions: - vers=4.1 - rsize=1048576 - wsize=1048576 - hard - timeo=600 - retrans=2网络优化:
- 使用千兆或万兆网络
- 配置 NFS 专用网络
- 调整 MTU 大小
存储优化:
- 使用 SSD 存储
- 配置 RAID
- 定期备份重要数据
7.3 清理资源
bash
kubectl delete -f pod.yaml
kubectl delete -f storageClass.yaml
kubectl delete -f nfs-client.yaml
kubectl delete -f serviceAccount.yaml
kubectl delete namespace nfs-storageclass八、实验总结
通过本实验,我们学习了:
- StorageClass 的基本概念:了解了存储类的作用和核心组件
- 动态卷供应:掌握了如何通过 StorageClass 自动创建 PV
- NFS 集成:学会了如何将 NFS 存储集成到 Kubernetes 中
- 实际应用:通过完整的实验验证了 StorageClass 的工作流程
关键要点
- StorageClass 简化了存储管理,实现了存储的动态供应
- Provisioner 是 StorageClass 的核心,负责实际的存储创建
- 不同的存储后端需要不同的 Provisioner 和参数配置
- 合理的存储策略配置对于生产环境至关重要
生产环境建议
- 安全性:配置适当的 RBAC 权限和网络策略
- 高可用:部署多副本 Provisioner,配置存储高可用
- 监控:建立完善的存储监控和告警机制
- 备份:制定数据备份和恢复策略
- 测试:定期进行故障恢复测试