3、存储基础:PV与PVC概念、StorageClass动态供给、访问模式
聊到Kubernetes的持久化存储,我脑子里第一个蹦出来的词就是「解耦」。说白了,就是让Pod不用关心底层存储到底长什么样。你想想看,一个应用开发者,他只需要知道「我要存数据」,至于数据是存在NFS上、Ceph里、还是云厂商的EBS上,他根本不想管。Kubernetes的PV和PVC就是干这个事的。
3.1 PV与PVC:存储的供需关系
PV(PersistentVolume)是集群管理员准备的存储资源。它就像仓库里的硬盘,已经接好线、格式化好了,等着被使用。PVC(PersistentVolumeClaim)是用户的存储请求。用户说「我要5GB的快速存储」,PVC就是这个需求单。
我刚开始接触K8s存储时,总觉得PV和PVC的关系有点绕。后来想通了——这不就是租房吗?PV是房东手里的房源,PVC是租客的找房需求。房东把房子挂出来(PV创建),租客提交需求(PVC创建),系统自动匹配,匹配上了就绑定(Bound)。
核心要点:PV和PVC是一对一的绑定关系。一旦绑定,PVC就独占这个PV,直到被删除。
来看一个简单的PV定义:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-example
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /data/pv-example
对应的PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-example
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: manual
这里有个细节——storageClassName必须匹配。如果PV的storageClassName是manual,PVC也得写manual,否则绑定不上。我曾经踩过这个坑,排查了半天才发现是class名字写错了。
3.2 StorageClass:动态供给的魔法
手动创建PV的方式,在开发环境还行。到了生产环境,几十上百个应用,每个都要手动配PV?那运维得累死。StorageClass就是来解决这个问题的。
StorageClass相当于一个「存储模板」。它告诉K8s:当用户创建PVC时,自动调用存储后端(比如云厂商的API)去创建对应的存储卷。这就是动态供给。
我习惯把StorageClass比作「自动售货机」。用户投币(提交PVC),机器自动吐出饮料(创建PV)。整个过程不需要管理员手动干预。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
fsType: ext4
encrypted: "true"
reclaimPolicy: Delete
allowVolumeExpansion: true
这个例子用的是AWS EBS的provisioner。你换成GCP就用pd.csi.storage.gke.io,换成Azure就用kubernetes.io/azure-disk。每个云厂商都有自己的CSI驱动。
我的建议:生产环境一定要用动态供给。手动管理PV不仅效率低,还容易出错。我见过一个团队因为PV回收策略没配好,导致数据泄露的事故。
3.3 访问模式:ReadWriteOnce vs ReadWriteMany
访问模式决定了存储卷能被多少个Pod以什么方式挂载。这是存储选型时最容易忽略的点,也是坑最多的地方。
| 访问模式 | 缩写 | 含义 | 典型场景 |
|---|---|---|---|
| ReadWriteOnce | RWO | 单节点读写 | 数据库、有状态应用 |
| ReadOnlyMany | ROX | 多节点只读 | 配置文件、静态资源 |
| ReadWriteMany | RWX | 多节点读写 | 共享文件系统、日志聚合 |
ReadWriteOnce(RWO)是最常用的模式。一个PV只能被一个节点上的Pod挂载读写。MySQL、PostgreSQL这类数据库都用它。为什么?因为数据库不允许两个实例同时写同一份数据,会出大问题。
ReadWriteMany(RWX)就灵活多了。多个Pod可以同时读写同一个PV。但要注意——不是所有存储后端都支持RWX。NFS支持,CephFS支持,但大多数云厂商的块存储(如AWS EBS、GCP Persistent Disk)不支持。
避坑指南:我曾经在生产环境用AWS EBS配了RWX,结果Pod一直Pending。查了半天才发现EBS根本不支持RWX。后来换成EFS才解决。所以选存储后端前,一定要先确认它支持哪些访问模式。
还有一个容易混淆的点——访问模式是PV级别的属性,不是PVC级别的。PVC只能声明它需要什么模式,最终能不能满足,取决于PV支持什么。
3.4 知识体系总览
下面这张图把本章的核心逻辑串起来了。你可以看到从PVC发起请求,到StorageClass动态创建PV,再到Pod挂载使用的完整流程。
从图中可以看到,整个流程其实就三步:用户提需求(PVC)→ 系统找资源(PV或自动创建)→ 绑定使用。嗯,就是这么简单。但简单背后藏着不少细节,比如回收策略、扩容支持、CSI驱动版本兼容性等等。
个人经验:在vLLM项目中,我通常用ReadWriteOnce配合本地SSD做模型缓存。推理任务对IO延迟敏感,RWO模式能保证单节点独占磁盘带宽。如果多个推理副本需要共享同一个模型文件,那就得上RWX了,这时候NFS或JuiceFS是不错的选择。
最后说一句——存储选型没有银弹。RWO简单可靠,但限制了扩展性。RWX灵活,但性能和一致性要打折扣。你想想看,你的vLLM推理服务到底需要什么?是低延迟,还是多副本共享?想清楚了,再选。
公众号:蓝海资料掘金营,微信deep3321