存储体系-PV-PVC-StorageClass
1. 概念
K8s 把存储抽象成三层:
| 层 | 角色 |
|---|---|
| StorageClass | 存储"类型"(SSD / HDD / 云盘) |
| PV (PersistentVolume) | 一块具体的存储资源 |
| PVC (PersistentVolumeClaim) | 对存储的申请(Pod 用 PVC,不直接绑 PV) |
Pod → PVC ←─bind─→ PV ←─provision─→ 物理存储
↑
StorageClass
2. 静态供应 vs 动态供应
2.1 静态:管理员先建好 PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-data-1
spec:
capacity:
storage: 100Gi
accessModes: [ReadWriteOnce]
persistentVolumeReclaimPolicy: Retain
nfs:
server: 10.0.0.5
path: /exports/data1
PVC 申请,K8s 找匹配的 PV 绑定。少用。
2.2 动态:StorageClass 按需创建 PV
# StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: alicloud-disk-ssd
provisioner: diskplugin.csi.alibabacloud.com
parameters:
type: cloud_ssd
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
# PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
storageClassName: alicloud-disk-ssd
resources:
requests:
storage: 50Gi
# Pod 使用
spec:
volumes:
- name: data
persistentVolumeClaim:
claimName: data
containers:
- name: app
volumeMounts:
- name: data
mountPath: /var/lib/data
3. 访问模式
| 模式 | 简写 | 含义 |
|---|---|---|
| ReadWriteOnce | RWO | 单节点读写(云盘最常见) |
| ReadOnlyMany | ROX | 多节点只读 |
| ReadWriteMany | RWX | 多节点读写(NFS、CephFS) |
| ReadWriteOncePod | RWOP | 单 Pod 读写(1.22+) |
前端项目大多用 RWO。需要 RWX 时(多 Pod 共享上传文件):NFS / 云对象存储。
4. 回收策略
persistentVolumeReclaimPolicy:
Retain # PVC 删除后 PV 保留(手动清理)
Delete # PVC 删除后 PV 一并删(云盘也删)
Recycle # 已 deprecated
生产数据用 Retain,避免误删丢数据。
5. volumeBindingMode
volumeBindingMode:
Immediate # 创建 PVC 立即 provision
WaitForFirstConsumer # 等到 Pod 调度才 provision(推荐)
WaitForFirstConsumer 在多可用区集群很重要:先看 Pod 被调度到哪个 zone,再在那个 zone 建云盘。否则可能 PV 在 zone-a 但 Pod 调度到 zone-b,挂不上。
6. 卷扩展
storageClass:
allowVolumeExpansion: true
修改 PVC 的 storage 字段:
spec:
resources:
requests:
storage: 100Gi # 原来 50Gi
底层云盘扩容 + 文件系统 resize。只能扩不能缩。
7. 常见 CSI Driver
| 平台 | Driver |
|---|---|
| 阿里 | alibabacloud-csi-driver |
| AWS | aws-ebs-csi-driver / efs-csi-driver |
| GCP | pd.csi.storage.gke.io |
| Azure | disk.csi.azure.com |
| 本地 | local-path-provisioner(Rancher)、OpenEBS |
8. emptyDir 与 hostPath
不是持久化但常用:
volumes:
- name: cache
emptyDir:
sizeLimit: 1Gi # Pod 销毁数据丢失,可设大小限制和 medium: Memory
- name: docker-sock
hostPath:
path: /var/run/docker.sock
type: Socket
hostPath 慎用:破坏调度可移植性、安全风险。生产基本只用于系统组件(DaemonSet 收集节点日志)。
9. StatefulSet + PVC 模板
每个副本独立 PVC:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
storageClassName: ssd
resources:
requests:
storage: 100Gi
每个 Pod 自动建独立 PVC:data-postgres-0、data-postgres-1、data-postgres-2。
10. 故障排查
# PVC 一直 Pending
kubectl describe pvc data
# 看 Events: ProvisioningFailed / WaitForPodScheduled
# 看 PV 状态
kubectl get pv
# Status: Available / Bound / Released / Failed
# 卷挂不上
kubectl describe pod <pod>
# Events: FailedMount
# 看 CSI driver 日志
kubectl logs -n kube-system -l app=csi-driver
11. 常见反模式
- 生产用 emptyDir 存数据:Pod 重建数据丢
Reclaim: Delete给生产 DB:误删 PVC = 数据没了- 不开
WaitForFirstConsumer:跨 zone 挂不上 - 多 Pod 共享 RWO 卷:第二个 Pod 起不来
- storage 设特小 (1Gi):满了再扩烦
hostPath用在业务容器:失去可移植性- StatefulSet 改 volumeClaimTemplates:不可变,改了要删重建
12. 延伸阅读
- Persistent Volumes 文档
- CSI 规范
- Storage Classes
- 模块 04 数据卷与持久化(容器层面)