跳到主要内容

存储体系-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. 访问模式

模式简写含义
ReadWriteOnceRWO单节点读写(云盘最常见)
ReadOnlyManyROX多节点只读
ReadWriteManyRWX多节点读写(NFS、CephFS)
ReadWriteOncePodRWOP单 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
AWSaws-ebs-csi-driver / efs-csi-driver
GCPpd.csi.storage.gke.io
Azuredisk.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-0data-postgres-1data-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. 延伸阅读