title: “K8s 系列 | 第 9 天:StorageClass 与动态存储供给实战”
tags: [Kubernetes, K8s系列, DevOps, Storage, StorageClass, PVC, CSI]
date: 2026-06-25
第 9/30 天
引言
在前一篇文章中,我们深入探讨了 Volume 和 PersistentVolume(PV)的基本概念——它们是 Kubernetes 容器存储的基石。但在生产环境中,手动管理 PV 是一件极其繁琐的任务:每次 Pod 需要存储时,运维人员都必须预先准备好存储设备、创建 PV、再手动绑定到 PVC。这种做法在大规模集群中完全不可持续。
StorageClass 的诞生就是为了解决这个问题。 它引入了一种”动态存储供给”(Dynamic Provisioning)机制——当用户创建 PVC 时,Kubernetes 不再需要等待管理员手动创建 PV,而是根据 StorageClass 中定义的配置自动生成 PV,实现存储的”按需分配”。
本文将深入讲解 StorageClass 的核心原理、常见配置场景,并通过实战演示如何在不同环境中配置和使用动态存储供给。
核心概念
什么是 StorageClass?
StorageClass 是 Kubernetes 中用于定义存储”类别”的 API 资源。它充当了一个存储模板的角色,告诉 Kubernetes:
- 使用哪个存储后端(例如:本地存储、NFS、Ceph RBD、AWS EBS、GCE PD 等)
- 使用什么参数(例如:磁盘类型、IOPS、回收策略等)
- 使用哪个 Provisioner(负责实际创建存储卷的插件)
动态供给 vs 静态供给
| 对比维度 | 静态供给(无 StorageClass) | 动态供给(有 StorageClass) |
|---|---|---|
| 操作流程 | 管理员提前创建 PV → 用户创建 PVC → 绑定 | 用户创建 PVC(指定 StorageClass)→ 自动创建 PV |
| 运维成本 | 高——需要管理员持续预分配存储 | 低——按需自动分配 |
| 资源利用率 | 低——预分配可能造成浪费 | 高——真正按需分配 |
| 适用场景 | 测试集群、存储后端有限的环境 | 生产集群、云环境 |
StorageClass 的核心字段
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
iopsPerGB: "10"
fsType: ext4
reclaimPolicy: Retain # 或 Delete(默认)
allowVolumeExpansion: true # 是否允许在线扩容
volumeBindingMode: Immediate # 或 WaitForFirstConsumer
mountOptions:
- discard
- provisioner:指定存储插件(CSI 驱动或内置驱动)
- parameters:传递给 provisioner 的配置参数,不同 provisioner 各不相同
- reclaimPolicy:当 PVC 被删除时,PV 的处理方式——
Delete(自动删除底层存储)或Retain(保留数据) - allowVolumeExpansion:是否允许后续对 PVC 进行扩容
- volumeBindingMode:
Immediate表示立即创建 PV(即使 Pod 还未调度),WaitForFirstConsumer表示等到 Pod 被调度到某节点后再创建 PV(确保 PV 与节点在同一可用区)
动态供给的工作流程
用户创建 PVC (指定 StorageClass)
↓
Kubernetes 检测到 PVC 未绑定
↓
查找匹配的 StorageClass
↓
调用对应的 Provisioner 插件
↓
Provisioner 在存储后端创建真实存储卷
↓
Kubernetes 创建 PV 对象并绑定到 PVC
↓
Pod 使用 PVC 挂载存储卷
实战步骤
环境准备
首先检查集群中已有的 StorageClass:
# 查看集群中所有 StorageClass
kubectl get storageclass
# 查看默认的 StorageClass(带 (default) 标注)
kubectl get sc
# 查看 StorageClass 的详细配置
kubectl describe storageclass <name>
在一个典型的 kubeadm 部署的集群中,如果安装了相关的 CSI 驱动,你可能会看到类似这样的输出:
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE
local-storage rancher.io/local-path Delete WaitForFirstConsumer
standard (default) k8s.io/minikube-hostpath Delete Immediate
场景一:使用本地路径 StorageClass(开发环境)
对于本地开发集群(如 minikube、kind、kubeadm 单节点),推荐使用 rancher.io/local-path provisioner 来提供本地存储:
# 安装 local-path-provisioner
kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml
# 验证安装
kubectl -n local-path-storage get pod
然后创建一个使用该 StorageClass 的 PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: local-pvc-demo
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path # 指定 StorageClass
resources:
requests:
storage: 5Gi
创建后验证动态供给是否生效:
kubectl get pvc
kubectl get pv
你会看到 PVC 的状态立即变为 Bound,并且系统自动创建了一个 PV——这就是动态供给的魔力。
场景二:使用 NFS CSI 驱动(生产环境)
生产环境中,NFS 是最广泛使用的共享存储方案之一。我们通过 NFS CSI 驱动配置 StorageClass:
# 1. 部署 NFS CSI 驱动
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/deploy/example/nfs-provisioner.yaml
# 2. 创建 NFS StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
server: 192.168.1.100 # NFS 服务器地址
share: /exported/path # NFS 共享路径
mountPermissions: "0777"
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true
创建后测试使用:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
spec:
accessModes:
- ReadWriteMany # NFS 支持多节点读写
storageClassName: nfs-csi
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Pod
metadata:
name: nfs-test-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: storage
mountPath: /data
volumes:
- name: storage
persistentVolumeClaim:
claimName: nfs-pvc
场景三:配置默认 StorageClass
设置一个默认的 StorageClass,当 PVC 不指定 storageClassName 时自动使用:
# 查看当前的默认 StorageClass
kubectl get storageclass -o jsonpath='{.items[?(@.metadata.annotations.storageclass.kubernetes.io/is-default-class=="true")].metadata.name}'
# 将某个 StorageClass 设为默认
kubectl patch storageclass nfs-csi -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
# 移除默认标注(从其他 StorageClass 上)
kubectl patch storageclass standard -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
⚠️ 注意:集群中只能有一个默认 StorageClass。如果存在多个,PVC 不指定 storageClassName 时会报错。
场景四:WaitForFirstConsumer 延迟绑定
对于本地存储或拓扑敏感的存储(如 AWS EBS 只能在特定可用区创建),使用 WaitForFirstConsumer 模式可以延迟 PV 创建,直到 Pod 被调度:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-ssd
provisioner: rancher.io/local-path
volumeBindingMode: WaitForFirstConsumer # 延迟绑定
reclaimPolicy: Delete
这种模式下,创建 PVC 时它不会立即绑定,而是保持 Pending 状态。直到引用了该 PVC 的 Pod 被调度到某节点后,Kubernetes 才在该节点上创建 PV 并绑定。这样就保证了存储卷一定位于 Pod 所在节点。
# PVC 创建后是 Pending 状态
kubectl get pvc # STATUS: Pending
# 创建引用了 PVC 的 Pod 后
kubectl apply -f pod.yaml
kubectl get pvc # STATUS: Bound(Pod 调度后自动绑定)
常见问题
Q1:PVC 一直处于 Pending 状态
可能原因:
1. 没有匹配的 StorageClass — PVC 指定的 storageClassName 不存在
2. Provisioner 未部署 — CSI 驱动 Pod 未正常运行
3. 存储后端不可达 — NFS 服务器不通或权限不足
4. 资源不足 — 存储池空间耗尽
排查方法:
kubectl describe pvc <pvc-name>
kubectl describe storageclass <sc-name>
kubectl -n <csi-namespace> logs -l app=<provisioner-app>
Q2:动态供给创建的磁盘大小不对
某些 CSI 驱动的参数可能以字节或不同单位解释。务必查看对应驱动文档中的 parameters 含义:
# 查看 provisioner 支持的参数
kubectl describe storageclass <name> | grep Parameters
Q3:如何限制 StorageClass 的使用范围
通过 RBAC 或 ResourceQuota 来控制哪些 Namespace 可以使用哪些 StorageClass:
apiVersion: v1
kind: ResourceQuota
metadata:
name: storage-quota
namespace: dev-team
spec:
hard:
persistentvolumeclaims: "10" # PVC 数量限制
requests.storage: "100Gi" # 总存储量限制
<storage-class-name>.storageclass.storage.k8s.io/requests.storage: "50Gi" # 针对特定 StorageClass
Q4:动态供给的 PV 可以扩容吗?
可以,但需要满足两个条件:
1. StorageClass 的 allowVolumeExpansion: true
2. 底层存储后端支持在线扩容
# 扩容 PVC(不需要删除重建)
kubectl edit pvc <pvc-name>
# 将 spec.resources.requests.storage 从 10Gi 改为 20Gi
扩容后需要 Pod 内的文件系统识别新大小(某些系统自动识别,某些需要手动 resize2fs)。
总结
StorageClass 是 Kubernetes 存储体系中最核心的抽象之一。它将存储的”提供”和”使用”彻底解耦,让:
- 运维人员只需配置好 StorageClass 模板,无需手动管理 PV
- 开发人员只需在 PVC 中指定存储大小和 StorageClass,存储自动就绪
- 集群能根据不同负载自动选择最合适的存储后端
关键要点回顾:
| 概念 | 作用 |
|---|---|
| StorageClass | 存储模板,定义 provisioner 和参数 |
| Dynamic Provisioning | 按需自动创建 PV,无需人工干预 |
| reclaimPolicy | Delete(自动清理)/ Retain(保留数据) |
| volumeBindingMode | Immediate(立即绑定)/ WaitForFirstConsumer(延迟到 Pod 调度后) |
| allowVolumeExpansion | 允许 PVC 在线扩容 |
在生产环境中,建议至少配置 2-3 个不同类型的 StorageClass:一个高性能 SSD 类(数据库)、一个普通 HDD 类(日志归档)、一个共享文件系统类(NFS/CephFS),以满足不同工作负载的需求。
下期预告
第 10 天:StatefulSet:有状态应用的部署与管理
在学习了存储和网络的基础之后,我们将进入有状态应用的世界。StatefulSet 是 Kubernetes 为数据库、消息队列等有状态工作负载量身打造的控制器——它如何保证 Pod 的唯一标识?如何与 PV 协同工作?下一篇文章将为你揭晓。
📚 系列目录(持续更新中)**
| 天数 | 标题 | 状态 |
|---|---|---|
| 第 1 天 | Kubernetes 是什么?核心概念与架构全景解析 | ✅ 已发布 |
| 第 2 天 | 手把手搭建你的第一个 K8s 集群(kubeadm 实战) | ✅ 已发布 |
| 第 3 天 | Pod 详解:K8s 最小的调度单元与生命周期管理 | ✅ 已发布 |
| 第 4 天 | Deployment 与 ReplicaSet:声明式应用管理 | ✅ 已发布 |
| 第 5 天 | Service 与网络基础:ClusterIP、NodePort、LoadBalancer 详解 | ✅ 已发布 |
| 第 6 天 | Namespace 与资源配额:多租户隔离基础 | ✅ 已发布 |
| 第 7 天 | ConfigMap 与 Secret:配置管理最佳实践 | ✅ 已发布 |
| 第 8 天 | Volume 与 PersistentVolume:存储抽象层的核心机制 | ✅ 已发布 |
| 第 9 天 | StorageClass 与动态存储供给实战 | 📝 本文 |
| 第 10 天 | StatefulSet:有状态应用的部署与管理 | 🔜 即将发布 |
| 第 11 天 | Ingress 与 Ingress Controller:外部流量接入全攻略 | 🔜 即将发布 |
| 第 12 天 | NetworkPolicy:K8s 网络安全策略与微隔离 | 🔜 即将发布 |
| 第 13 天 | Headless Service 与服务发现机制深度解析 | 🔜 即将发布 |
| 第 14 天 | CSI 存储插件与生产存储选型指南 | 🔜 即将发布 |
| 第 15 天 | 污点与容忍度:掌控 Pod 调度 | 🔜 即将发布 |
| 第 16 天 | Node Affinity 与 Pod Affinity:精细化调度策略实战 | 🔜 即将发布 |
| 第 17 天 | HPA 水平自动扩缩:基于 CPU/内存/自定义指标的弹性伸缩 | 🔜 即将发布 |
| 第 18 天 | VPA 与 Cluster Autoscaler:资源与集群层的自动扩缩 | 🔜 即将发布 |
| 第 19 天 | Job 与 CronJob:批处理与定时任务实战 | 🔜 即将发布 |
| 第 20 天 | PriorityClass 与抢占式调度机制 | 🔜 即将发布 |
| 第 21 天 | 资源配额与 LimitRange:多租户资源管控 | 🔜 即将发布 |
| 第 22 天 | 监控体系搭建:Prometheus + Grafana + Kube-state-metrics | 🔜 即将发布 |
| 第 23 天 | 日志收集实战:EFK/ELK 栈在 K8s 中部署 | 🔜 即将发布 |
| 第 24 天 | RBAC 权限控制:ServiceAccount、Role、ClusterRole 深度解析 | 🔜 即将发布 |
| 第 25 天 | Helm Charts:包管理器使用与 Chart 开发实战 | 🔜 即将发布 |
| 第 26 天 | 集群备份与恢复:etcd 快照 + Velero 方案 | 🔜 即将发布 |
| 第 27 天 | 滚动更新与回滚策略:实现零停机发布 | 🔜 即将发布 |
| 第 28 天 | 集群升级最佳实践:Control Plane 与 Node 升级步骤 | 🔜 即将发布 |
| 第 29 天 | 多集群管理:Federation / Cluster API / 多集群服务网格 | 🔜 即将发布 |
| 第 30 天 | K8s 生产环境踩坑实录:性能调优、故障排查与最佳实践 | 🔜 即将发布 |















暂无评论内容