StorageClass 动态存储
第 12 章讲了 PV/PVC 解耦,但手动为每个应用创建 PV 不现实。StorageClass 解决"缺货时自动进货":应用声明 PVC,StorageClass 自动创建对应存储并生成 PV。本章讲透动态供给机制、CSI 架构与实战。
本篇目标:理解静态供给的痛点与动态供给的优势,看懂 StorageClass 关键参数与 CSI 架构,能完成 NFS/Ceph/云厂商块存储的动态绑定。
1. 静态供给的痛点与动态供给
1.1 静态供给的问题
管理员手动创建 PV(静态供给)时:
- 每个应用都要预先估算容量并手动建 PV,工作量大;
- 容量、性能、可用区要人工对齐,容易出错;
- 应用删除后 PV 清理靠人工,容易遗留或误删。
# 静态供给示例:管理员手动创建 PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-uploads
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
- ReadOnlyMany
persistentVolumeReclaimPolicy: Retain
nfs:
server: 10.0.0.20
path: /exports/uploads
1.2 动态供给
PVC 声明 storageClassName 后,集群里的 provisioner(由 CSI 驱动提供)自动创建对应存储并生成 PV:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: uploads
namespace: learning
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard # 指定 StorageClass
resources:
requests:
storage: 20Gi
流程:创建 PVC → StorageClass 的 provisioner 在云上创建云盘 → 生成 PV 并绑定 → Pod 挂载。删除 PVC 时按 reclaimPolicy 决定底层存储是删除还是保留。
2. StorageClass 核心定义与 CSI 架构
2.1 StorageClass 关键参数
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
annotations:
storageclass.kubernetes.io/is-default-class: "true" # 设为默认 StorageClass
provisioner: pd.csi.storage.gke.io # 取决于 CSI 驱动
parameters:
type: pd-ssd # 供应商特定参数
reclaimPolicy: Retain # 删除 PVC 时保留 PV
volumeBindingMode: WaitForFirstConsumer # 等 Pod 调度后再创建卷(避免跨 AZ)
allowVolumeExpansion: true # 允许在线扩容
mountOptions: # 挂载选项(可选)
- discard
| 参数 | 含义 | 建议 |
|---|---|---|
provisioner | 谁来创建存储,如 pd.csi.storage.gke.io、ebs.csi.aws.com | 与集群安装的 CSI 驱动一致 |
parameters | 供应商特定参数(磁盘类型、IOPS、复制策略) | 参照 CSI 驱动文档 |
reclaimPolicy | Delete / Retain | 生产 Retain |
volumeBindingMode | Immediate / WaitForFirstConsumer | 生产首选 WaitForFirstConsumer |
allowVolumeExpansion | 是否允许在线扩容 | 建议开启 |
mountOptions | 挂载到节点时的附加选项 | 按存储类型需要 |
2.2 默认 StorageClass
给 StorageClass 打上 storageclass.kubernetes.io/is-default-class: "true" 注解后,不写 storageClassName 的 PVC 会自动使用它:
kubectl get storageclass -A
kubectl get storageclass -o custom-columns='NAME:.metadata.name,DEFAULT:.metadata.annotations.storageclass\.kubernetes\.io/is-default-class'
2.3 CSI 架构原理
CSI(Container Storage Interface)是存储接入的标准接口,让存储厂商以统一方式提供卷能力:
kubelet / kube-controller-manager
│ CSI 调用(gRPC)
▼
CSI Driver(由厂商提供,如 aws-ebs-csi-driver、ceph-csi)
│
▼
真实存储后端(云盘 / NFS / Ceph 集群)
CSI 驱动通常由两部分组成:
- Controller 组件(Deployment):负责创建/删除/快照/扩容卷;
- Node 组件(DaemonSet):负责把卷挂载到节点。
3. 动态存储卷自动绑定流程实战
3.1 通用绑定流程
1. 应用创建 PVC(指定 storageClassName、容量、访问模式)
2. provisioner 调用 CSI 创建底层存储(云盘/NFS 子目录等)
3. 生成 PV 并绑定到该 PVC(Status: Bound)
4. Pod 通过 volumeMounts 挂载使用
5. 删除 PVC → 按 reclaimPolicy 处理底层存储
kubectl get pvc -w -n learning # 观察 Pending → Bound
kubectl get pv # 动态生成的 PV
kubectl describe pvc uploads -n learning # 看 provisioner 与事件
3.2 NFS 动态供给(示例)
以 NFS CSI 驱动为例(如 nfs.csi.k8s.io,需先安装驱动):
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-standard
provisioner: nfs.csi.k8s.io
parameters:
server: 10.0.0.20 # NFS 服务器
share: /exports # 导出的根目录
reclaimPolicy: Retain
volumeBindingMode: Immediate
mountOptions:
- hard
- nfsvers=4.1
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-data
namespace: learning
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs-standard
resources:
requests:
storage: 10Gi
NFS 的优势是支持 RWX(多副本共享读写)。
3.3 云厂商块存储(示例)
AWS EBS 与 GCE PD 通常只支持 RWO,适合数据库等单写者:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ebs-gp3
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
3.4 Ceph(示例)
CephFS 支持 RWX,适合共享存储;RBD 块设备适合 RWO 高性能:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: cephfs
provisioner: cephfs.csi.ceph.com
parameters:
clusterID: <ceph-cluster-id>
fsName: cephfs
csi.storage.k8s.io/controller-expand-secret-name: csi-cephfs-secret
csi.storage.k8s.io/controller-expand-secret-namespace: ceph-csi
reclaimPolicy: Retain
mountOptions:
- mds_mode=rw
3.5 选型建议
| 场景 | 存储 | 访问模式 | 注意 |
|---|---|---|---|
| 数据库(单写者) | 云盘(EBS/PD) | RWO | 优先托管数据库 |
| 多副本共享上传 | NFS / CephFS | RWX | 关注性能上限 |
| 高吞吐块设备 | Ceph RBD | RWO | 需要 Ceph 集群 |
| 本地高性能 | Local PV | RWO | 节点绑定,需配套调度约束 |
4. 常见问题与排障
4.1 PVC 一直 Pending
kubectl describe pvc <pvc-name> -n <namespace>
kubectl get storageclass -A
kubectl get pv
kubectl get events -n <namespace> --sort-by=.lastTimestamp
| 现象 | 原因 | 处理 |
|---|---|---|
storageclass.storage.k8s.io "xxx" not found | 写的 StorageClass 不存在 | 核对集群里实际的 StorageClass 名 |
| 事件提示配额不足 | Namespace ResourceQuota 限制 PVC 数量或容量 | 见第 3 章 |
| 静态供给 + 默认 StorageClass | 未写 storageClassName: "",PVC 被动态供给抢走 | 显式指定空 StorageClass |
WaitForFirstConsumer 一直 Pending | 还没有 Pod 引用该 PVC | 创建引用它的工作负载即可,属预期 |
| 事件提示绑定失败 | 手动 PV 容量/访问模式不匹配 | 检查 PV 的 capacity 和 accessModes |
4.2 扩容相关
- 只能增大、不能缩小:
kubectl patch pvc <name> -p '{"spec":{"resources":{"requests":{"storage":"40Gi"}}}}'; - 前提是 StorageClass 声明了
allowVolumeExpansion: true,且 CSI 驱动支持; - 部分存储后端扩容后文件系统不自动感知,需要 Pod 内手动
resize2fs/xfs_growfs。
5. 练习
练习 A
- 查看集群中的 StorageClass,确认默认类与各自的 provisioner、reclaimPolicy、volumeBindingMode
- 创建一个 PVC 并观察 Pending → Bound 的完整过程,用
kubectl get pv看动态生成的 PV - 删除 PVC,观察底层存储(PV)按 reclaimPolicy 被删除或保留
练习 B
- 如果集群支持,创建一个 NFS 或云盘 StorageClass,验证 RWX/RWO 的差异
- 修改 PVC 容量触发在线扩容,确认
allowVolumeExpansion生效 - 故意写错
storageClassName,用describe pvc观察not found事件并修复
下一篇:Resource 资源限制与 QoS。