

集群里跑着训练任务和日志管道,PVC 块存储越堆越多:扩容量要等重建、多个 Pod 抢同一份数据时还要自己处理锁和拷贝。你查了一圈,发现这类工作负载真正需要的是一个 S3 兼容的对象存储后端------对象不上锁、随便共享、还能挂生命周期策略自动归档。于是你在集群里起了个 MinIO,但 AGPL 的许可条款让法务皱了眉,镜像里那些遥测也让数据主权强迫症难受。
RustFS 是另一个选择:Rust 写的分布式对象存储、100% S3 兼容、Apache 2.0 协议,官方还带了 Helm Chart 可以直接把集群部署进 Kubernetes。这篇我把它从零装进集群、让应用接上,全程用官方真实的命令和参数,也把几个"网上没人提醒你"的边界讲清楚。
1. 先分清:你要的是 S3 后端,不是又一个 CSI 块存储
很多人一听到"K8s 里加存储"就想装 CSI 驱动。但对象存储和块存储解决的是两码事:
| 维度 | 块存储(PVC/CSI) | 对象存储(S3 后端) |
|---|---|---|
| 挂载方式 | 单节点可写,POSIX 文件系统 | 走 S3 API,任意 Pod 同时访问 |
| 共享 | 需要 RWX 方案和锁处理 | 天然多读多写,无锁 |
| 扩容 | 扩 PVC 要处理挂载/重建 | 加节点即扩,无需停机 |
| 数据治理 | 靠文件系统工具 | 生命周期/版本/对象锁原生支持 |
| 典型场景 | 数据库、中间件数据盘 | AI 训练、日志、备份、数据湖 |
训练集、模型产物、日志归档、数据库备份这些负载,用 S3 后端是更自然的选择。这里有一个要老实交代的边界:RustFS 官方目前没有"对象存储 CSI 驱动"------它定位是 S3 兼容的存储服务,K8s 里的应用通过 S3 SDK 或命令行工具接入(下面第 3 节就是这么接的)。如果你有应用必须走 POSIX 挂载,可以用 csi-s3 这类第三方 S3 CSI 方案或挂载网关桥接,但这不是 RustFS 官方提供的组件,自己评估风险。RustFS 官方在 K8s 里提供的,是把存储集群本身跑起来的 Helm Chart 和 Operator。
2. Helm 三步把 RustFS 集群装进 K8s
先看整体结构:应用 Pod 走 Service 的 9000 端口访问 RustFS,数据落在每个节点 Pod 挂载的 PVC 上,节点之间再通过纠删码跨 Pod 冗余。整个链路由 Helm Chart 自动编排,你不需要手工配 StatefulSet:

官方 Helm Chart 在仓库 helm/ 目录,直接用源码目录安装(也可以先 git clone 仓库)。三行命令:
bash
git clone https://github.com/rustfs/rustfs.git && cd rustfs/helm
helm install rustfs -n rustfs --create-namespace ./ \
--set ingress.className="nginx"
kubectl -n rustfs get pods -w
装完的状态:replicaCount 默认 4 ,也就是一个 4 节点的 RustFS 集群;每个 Pod 的数据盘是自动创建的 PVC。官方文档明确分布式模式下节点数要 >= 2。数据 PVC 默认只给 256Mi,这是为了快速验证,生产必须调大------装的时候就带上:
bash
helm install rustfs -n rustfs --create-namespace ./ \
--set ingress.className="nginx" \
--set storageclass.dataStorageSize=1Ti \
--set storageclass.logStorageSize=1Gi
storageclass.name 默认用集群里的 local-path,可以换成你们自己的存储类(比如 --set storageclass.name=standard)。数据最终落在 PVC 对应的块存储上,RustFS 层再做纠删码跨节点冗余,两层都得管。
默认端口和访问方式(Helm README 原文):
| 参数 | 默认值 | 说明 |
|---|---|---|
service.type |
ClusterIP | 集群内访问 |
service.endpoint.port |
9000 | S3 API 端口 |
service.endpoint.nodePort |
32000 | 对外 NodePort |
service.console.port |
9001 | 控制台端口 |
service.console.nodePort |
32001 | 控制台 NodePort |
| 探活 | /health、/health/ready |
liveness / readiness |
| 运行用户 | UID/GID 10001 | 非 root,drop ALL capabilities |
最后这点值得单独说:Chart 默认以 UID 10001 的非 root 用户 跑容器,fsGroup: 10001 保证 PVC 挂载卷可写,runAsNonRoot: true 直接卡死 root 运行。这套安全基线和官方 Docker 镜像一致,不是后加的加固。
3. 应用接入:建桶、配凭证、跑一个备份任务
集群内应用通过 Service 走 9000 端口,命令如下(默认账号 rustfsadmin/rustfsadmin,上线前必须改掉):
bash
export AWS_ACCESS_KEY_ID=rustfsadmin
export AWS_SECRET_ACCESS_KEY=rustfsadmin
export AWS_ENDPOINT_URL=http://rustfs-endpoint.rustfs.svc:9000
aws --endpoint-url $AWS_ENDPOINT_URL s3 mb s3://ml-datasets
echo "hello" | aws --endpoint-url $AWS_ENDPOINT_URL s3 cp - s3://ml-datasets/hello.txt
应用侧的标准做法是建一个 Secret 存凭证,Pod 里用环境变量或 aws s3 sync 直接读写。下面这个 Deployment 就是"把 MySQL 备份目录每天同步进 RustFS"的常见形态,可以直接复制改:
yaml
apiVersion: v1
kind: Secret
metadata:
name: rustfs-creds
type: Opaque
stringData:
AWS_ACCESS_KEY_ID: rustfsadmin
AWS_SECRET_ACCESS_KEY: "换成你的强密码"
AWS_ENDPOINT_URL: http://rustfs-endpoint.rustfs.svc:9000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-backup-sync
spec:
replicas: 1
selector:
matchLabels: { app: mysql-backup-sync }
template:
metadata:
labels: { app: mysql-backup-sync }
spec:
containers:
- name: sync
image: amazon/aws-cli:latest
command: ["/bin/sh", "-c"]
args:
- |
while true; do
aws --endpoint-url $$AWS_ENDPOINT_URL s3 sync \
/backup s3://ml-datasets/mysql/ --delete
sleep 3600
done
envFrom:
- secretRef: { name: rustfs-creds }
volumeMounts:
- { name: backup, mountPath: /backup }
volumes:
- name: backup
persistentVolumeClaim:
claimName: mysql-backup-pvc
注意 YAML 里 $$AWS_ENDPOINT_URL 的 $$ 是给 Helm 模板转义用的,如果你直接 kubectl apply 就写单个 $。验证是否真的写进去了:进容器跑 aws s3 ls s3://ml-datasets/,或者去控制台(NodePort 32001)看对象列表。
4. 进阶:把块卷快照也备份进 RustFS(LINBIT 官方方案)
如果你还想给集群里的块存储卷加一层"备份到对象存储",有个现成的官方集成:LINBIT 的 LINSTOR CSI 驱动支持把卷快照直接写到 S3 兼容存储,RustFS 是它明确支持的远端之一。LINBIT 官方博客有一篇完整的《Disaster Recovery With RustFS & LINSTOR in Kubernetes》,核心就三步:
- 建一个存 RustFS 凭证的 Secret(类型
linstor.csi.linbit.com/s3-credentials.v1); - 建
VolumeSnapshotClass,snap.linstor.csi.linbit.com/type: S3、s3-endpoint指向 RustFS(如http://your-rustfs.lan:9000)、s3-bucket指定备份桶; - 之后对任何 PVC 打快照,快照数据就落在 RustFS 里,支持增量(
allow-incremental: "true")。
这意味着数据库这类"必须用块存储"的工作负载,也能把历史快照沉淀到对象存储里做长期保留------对象存储的便宜大容量 + 生命周期归档,正好补上块存储快照长期堆叠的账单问题。这条链路是 LINBIT 官方维护的,属于"厂商官方的跨项目集成",比自己去拼一个备份脚本可靠。
5. 上线前必看的几个边界
部署这套东西之前,有几件事不提醒你,迟早要踩:
- 固定版本,别用 latest :RustFS 目前处于 rc 阶段(
1.0.0-rc.x),镜像 tag 用你验证过的固定版本,latest只适合本地试玩。升级前看官方 release 说明。 - 数据在 PVC 上,storageClass 决定持久性 :删掉 StatefulSet 或重建命名空间前先确认 PVC 策略,Helm 卸载
helm uninstall rustfs -n rustfs默认会连带删 PVC------要保留数据得先把 PVC 保护起来。 - 改 drivesPerNode 要重建 :Kubernetes 不允许改 StatefulSet 的 volumeClaimTemplates,调磁盘数量只能
--cascade=orphan重建或重装,别在生产上随意改。 - 默认账号必须改 :
rustfsadmin/rustfsadmin是官方默认值,暴露到外网等于裸奔。 - 对象存储不是万金油:随机写、强一致单点数据库这类负载还是留给块存储;需要 POSIX 挂载的应用走第三方 S3 CSI,自行评估。
这些都是中性事实,不是"RustFS 不好"------任何对象存储上 K8s 都有这几条功课。RustFS 官方文档、Helm Chart 和 Discussions 都公开可查,动手前翻一遍不亏。
6. 总结与下一步
装完、接完、验证完,核心参数一张表收走:

- K8s 里跑训练/日志/备份,S3 对象存储后端比堆 PVC 更顺手;RustFS 用官方 Helm Chart 就能装进集群。
- 关键参数记牢:默认 4 节点、数据 PVC 256Mi 起步要调大、端口 9000/9001(NodePort 32000/32001)、UID 10001 非 root、探活走
/health。 - 应用接入 = 建桶 + Secret 存凭证 + S3 工具同步,示例 Deployment 可直接改。
- 想要块卷快照备份,用 LINBIT LINSTOR CSI 的官方 S3 集成,快照直接进 RustFS。
- 上线前:固定 rc 版本、改默认密码、确认 PVC 回收策略。
下一步直接复制第 2 节的 helm install 命令跑一遍,跑通后把 rustfsadmin 密码换掉,再按第 3 节接你的第一个桶。
以下是深入学习 RustFS 的推荐资源:RustFS
官方文档: RustFS 官方文档- 提供架构、安装指南和 API 参考。
GitHub 仓库: GitHub 仓库 - 获取源代码、提交问题或贡献代码。
社区支持: GitHub Discussions- 与开发者交流经验和解决方案。
意见反馈:GitHub Issues