存储:PV / PVC / StorageClass 动态存储供给(K8s 存储核心篇)
在容器编排中,数据持久化 永远是绕不开的话题。应用可以随便重启、随便迁移,Pod 说没就没,但数据可不能说没就没。
要让 Kubernetes 世界里的数据"安居乐业",我们就要认识三个主角:
- PV(PersistentVolume):存储资源的"房东"
- PVC(PersistentVolumeClaim):Pod 的"租房需求"
- StorageClass:自动建房、自动分配的"房产中介 + 开发商"
今天星哥带你一次搞懂这三者,顺便把 **动态存储供给(Dynamic Provisioning)**一并拿下,真正从零到精通。
🚀 1. 为什么 K8s 中需要持久化存储?
在 Kubernetes 中,Pod 的生命周期极短:
- 自动扩缩容
- 滚动更新
- 节点漂移
- 重启即失忆(Ephemeral)
如果你的应用没有状态还好说,但数据库、缓存、消息队列可受不了。
于是,K8s 必须提供一种跟 Pod 生命周期无关的存储机制,这就是 PV / PVC。
🧱 2. PV(PersistentVolume):集群里的"存储资产"
PV 是由管理员提前创建的存储资源,类似:
- 一个 NFS 的目录
- 一个云盘(如阿里云 ESSD、腾讯云 CFS)
- 一个 Ceph RBD
- 一个本地磁盘路径
它的特点是:
- 独立于 Namespace
- 生命周期不依赖 Pod
- 拥有容量、访问模式、回收策略等属性
例子:一个 10Gi 的 NFS PV
yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
nfs:
path: /data/k8s
server: 10.0.0.10
persistentVolumeReclaimPolicy: Retain
📝 3. PVC(PersistentVolumeClaim):Pod 的"租房需求"
应用不会直接找 PV,而是发出一个需求:我要 10Gi、我要 RWX、我要能多 Pod 挂载。
K8s 会自动帮你匹配合适的 PV。
示例:
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-test
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
PVC 匹配到 PV 后,会进行绑定(Bound),然后 Pod 就能使用它:
yaml
volumes:
- name: data
persistentVolumeClaim:
claimName: pvc-test
🏗 4. StorageClass:自动造房子的"开发商"
如果每次使用前都得运维管理员手动创建 PV,那 Kubernetes 就不够"云原生"了。
StorageClass 让你做到:
PVC 一创建,PV 自动生成,底层存储自动分配。
动态供给架构:
PVC ---> StorageClass ---> Provisioner ---> PV
比如在云平台上,Provisioner 会自动创建真实的磁盘。
🛠 5. 动态存储供给(Dynamic Provisioning)
动态存储供给,需要两个条件:
- 定义 StorageClass
- PVC 指定 StorageClass 名称
这样 K8s 才知道该让哪个 Provisioner 去创建磁盘。
示例 StorageClass(以阿里云为例)
yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: alicloud-essd
provisioner: alicloud/disk
parameters:
type: "cloud_essd"
reclaimPolicy: Delete
volumeBindingMode: Immediate
PVC 使用 StorageClass
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-essd
spec:
storageClassName: alicloud-essd
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
PVC 一创建 → 云盘自动创建 → PV 自动生成 → 自动绑定。
真正做到了"即用即开,即删即回收"。
🪜 6. 三者关系总结(最常见的面试题)
下面是一句话总结:
- PV:房东 → 存储资源
- PVC:租客 → 提出需求
- StorageClass:房产中介 → 动态建房匹配
关系图:
[StorageClass] --(创建PV)--> [PV] <--(绑定)--> [PVC] <--(挂载)--> [Pod]
面试官最爱问:
直接使用 NFS hostPath 不行吗?为什么要用 PV/PVC?
因为 PV/PVC 是 Kubernetes 标准化的存储抽象,可以替换底层存储、支持调度、支持动态供给、支持跨云平台一致性。
🔥 7. 选择哪种访问模式(AccessMode)?
根据应用需要选择:
| AccessMode | 含义 | 场景 |
|---|---|---|
| RWO (ReadWriteOnce) | 单节点可读写 | 数据库、单实例服务 |
| ROX (ReadOnlyMany) | 多节点只读 | 镜像库、内容分发 |
| RWX (ReadWriteMany) | 多节点可读写 | Web 多实例共享存储 |
云盘一般只支持 RWO,想要多 Pod 共享要用 NFS、CephFS 等。
💡 8. PV 回收策略选什么?
PV 用完之后如何处理?
| 策略 | 说明 | 场景 |
|---|---|---|
| Retain | 保留数据、不自动删除 | 数据库等重要场景 |
| Delete | 删除 PV 和底层存储 | 云盘最常用 |
| Recycle | NFS 清空后重用(已弃用) | 不推荐 |
生产环境一般用:
- 动态创建 → Delete
- 手工创建 → Retain
🧩 9. 实战:部署一个带持久化的 Nginx
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nginx
spec:
storageClassName: nfs-sc
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
persistentVolumeClaim:
claimName: pvc-nginx
内容持久存储 → Pod 重启不丢 → 多实例共享。
🏁 最后
Kubernetes 的存储体系非常灵活:
- 有状态应用(StatefulSet)依赖 PVC
- 动态供给让存储自动化
- StorageClass 解耦了底层存储
- PV/PVC 抽象让跨云一致性成为可能