4、Kubeflow PVC 实战:Notebook 挂载 PVC、跨 Pod 共享数据、PVC 扩容与快照、使用 ReadWriteMany 卷
这一章,我们直接动手。PVC 在 Kubeflow 里到底怎么用?我见过不少团队,YAML 写得飞起,结果 Notebook 一重启数据丢了,或者两个 Pod 抢同一个盘直接报错。说白了,PVC 用不好,你的 ML 工作流就是纸糊的。
咱们今天就把四个核心场景讲透:Notebook 挂载、跨 Pod 共享、动态扩容、快照恢复。最后再聊聊 ReadWriteMany 这个“神器”到底怎么用。
4.1 Notebook 挂载 PVC:你的代码和数据不会丢
先看最常用的场景。你在 Kubeflow 里启动一个 Notebook,最怕什么?怕写了一半的代码,重启后全没了。我个人习惯,所有 Notebook 都挂载独立的 PVC。
创建 PVC 的 YAML 很简单:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-notebook-pvc
namespace: kubeflow-user
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
然后在 Kubeflow 的 Notebook UI 里,创建 Notebook 时,在 “Data Volumes” 部分添加这个 PVC。挂载路径我建议用 /home/jovyan/data。为什么?因为 Jupyter 镜像默认用户是 jovyan,挂载到 home 目录下,权限问题最少。
/ 或者 /home 本身。我曾经有个同事直接挂载到 /home,结果把系统配置文件都覆盖了,Notebook 直接起不来。挂载到一个子目录,干净又安全。
启动后,你在 Notebook 里执行:
!ls /home/jovyan/data/
就能看到你的持久化数据了。写个文件试试:
with open('/home/jovyan/data/test.txt', 'w') as f:
f.write('Hello Kubeflow PVC!')
重启 Notebook 实例,这个文件还在。嗯,这就是 PVC 的基本功。
4.2 跨 Pod 共享数据:ReadWriteMany 登场
单个 Notebook 挂载 PVC 太简单了。真正考验人的是:两个 Pod 怎么共享同一份数据?
比如你有一个训练任务,数据预处理 Pod 写数据,训练 Pod 读数据。如果用 ReadWriteOnce,两个 Pod 不能同时挂载同一个 PVC。怎么办?
答案就是 ReadWriteMany (RWX)。
但注意,不是所有存储后端都支持 RWX。我列个表给你看:
| 存储后端 | 支持 RWX? | 说明 |
|---|---|---|
| NFS | ✅ 是 | 最经典方案,性能一般但稳定 |
| GlusterFS | ✅ 是 | 适合大文件,小文件性能差 |
| CephFS | ✅ 是 | 性能好,但部署复杂 |
| HostPath | ❌ 否 | 仅单节点,别用于生产 |
| AWS EBS | ❌ 否 | 只能 ReadWriteOnce |
如果你在本地测试,最简单的办法是部署一个 NFS 服务。然后创建 PVC 时指定 accessModes: [ "ReadWriteMany" ]。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-data-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Gi
storageClassName: nfs-client
两个 Pod 都挂载这个 PVC,就能同时读写同一份数据了。我在项目中遇到过一个问题:两个 Pod 同时写同一个文件,导致数据损坏。解决办法是让每个 Pod 写自己的子目录,或者用文件锁。说白了,RWX 只是解决了“能同时挂载”的问题,不解决“并发写冲突”的问题。
4.3 PVC 扩容:数据不够了怎么办?
训练数据越来越大,PVC 不够用了。你怎么办?删了重建?那数据不就丢了?
Kubernetes 1.11 之后支持 PVC 在线扩容。前提是你的 StorageClass 开启了 allowVolumeExpansion: true。
先检查一下:
kubectl get storageclass standard -o yaml
看输出里有没有这一行:
allowVolumeExpansion: true
如果没有,你需要修改 StorageClass。我个人习惯在部署集群时就加上这个配置,省得后面抓狂。
扩容操作非常简单。直接编辑 PVC:
kubectl edit pvc my-notebook-pvc
把 spec.resources.requests.storage 从 10Gi 改成 20Gi。保存退出,Kubernetes 会自动触发扩容。
你可以用这个命令观察状态:
kubectl get pvc my-notebook-pvc -w
等状态变成 Bound,容量显示 20Gi,就搞定了。Pod 不需要重启,数据也不会丢。
4.4 PVC 快照:后悔药你得备着
扩容是正向操作。那万一你误删了数据呢?或者模型训练到一半,发现数据预处理错了,想回滚到之前的状态?
这时候就需要 VolumeSnapshot。它是 Kubernetes 1.12 之后引入的功能,相当于给 PVC 拍个照片。
首先,你得确保集群里有 VolumeSnapshotClass:
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: csi-snapclass
driver: csi-hostpath
deletionPolicy: Delete
然后创建快照:
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: my-pvc-snapshot-20240601
spec:
volumeSnapshotClassName: csi-snapclass
source:
persistentVolumeClaimName: my-notebook-pvc
创建后,你可以用这个快照恢复数据。恢复的方式是从快照创建一个新的 PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc-restored
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
dataSource:
name: my-pvc-snapshot-20240601
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
这个新 PVC 里的数据,就是拍快照那一刻的状态。你可以把它挂载到新的 Pod 里,把数据拷出来。
4.5 实战:用 ReadWriteMany 卷搭建数据流水线
最后,咱们串一个完整的例子。假设你要搭建一个 ML 数据流水线:
- 数据采集 Pod 从外部拉取数据,写入共享 PVC
- 数据清洗 Pod 读取数据,清洗后写回同一个 PVC
- 训练 Pod 读取清洗后的数据,开始训练
三个 Pod 需要同时挂载同一个 PVC。这就是 ReadWriteMany 的典型场景。
共享 PVC 的 YAML 前面已经给了。三个 Pod 的挂载配置类似:
volumes:
- name: shared-data
persistentVolumeClaim:
claimName: shared-data-pvc
containers:
- name: data-collector
volumeMounts:
- name: shared-data
mountPath: /data
每个 Pod 写不同的子目录:
- 采集 Pod 写
/data/raw/ - 清洗 Pod 读
/data/raw/,写/data/clean/ - 训练 Pod 读
/data/clean/
这样既共享了存储,又避免了文件冲突。我在一个客户现场就是这么干的,跑了半年没出过问题。
好了,这一章的内容就是这些。PVC 的四个核心操作——挂载、共享、扩容、快照——你都亲手实践过了。下一章我们聊聊更高级的话题:如何在 Kubeflow 里管理多个 PVC 的生命周期。
公众号:蓝海资料掘金营,微信deep3321