需要多个 Pod 同时读写同一份数据时,RBD 的 RWO
模型不够用。Rook 给出的文件系统答案是 CephFS
CSI:Provisioner 名默认
rook-ceph.cephfs.csi.ceph.com,每个 PVC
对应文件系统上的 subvolume,AccessMode 可走
ReadWriteMany。编排看起来「开箱即用」,账单却写在
MDS、capability 与元数据池上——这些税不在 StorageClass YAML
里出现。
本文是「Rook / CSI」系列第 8 篇(共 16 篇)。→ 系列目录
篇目 核心内容 第 7 篇 · 挂载与 features RBD NodeStage / krbd 第 8 篇 · CephFS CSI subvolume、RWX、MDS 编排税 第 9 篇 · 快照与克隆 VolumeSnapshot 语义差
版本锚定:Rook v1.20.4;Ceph-CSI v3.17.0;K8s v1.31–v1.36。CephFS/MDS 机制钉站内 ceph/13(Squid);本篇只写 CSI/Rook 编排面。
一、先有文件系统,再有 StorageClass
与 RBD「先有 BlockPool」对称,CephFS CSI 要求先有
CephFilesystem(元数据池、数据池、MDS
active/standby)。Rook 文件系统存储文档示例语义:
apiVersion: ceph.rook.io/v1
kind: CephFilesystem
metadata:
name: myfs
namespace: rook-ceph
spec:
metadataPool:
replicated:
size: 3
dataPools:
- name: replicated
replicated:
size: 3
preserveFilesystemOnDelete: true
metadataServer:
activeCount: 1
activeStandby: trueOperator 拉起 MDS Pod 后,再创建 StorageClass:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: rook-cephfs
provisioner: rook-ceph.cephfs.csi.ceph.com
parameters:
clusterID: rook-ceph
fsName: myfs
pool: myfs-replicated
csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner
csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
csi.storage.k8s.io/controller-expand-secret-name: rook-csi-cephfs-provisioner
csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
csi.storage.k8s.io/controller-publish-secret-name: rook-csi-cephfs-provisioner
csi.storage.k8s.io/controller-publish-secret-namespace: rook-ceph
csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node
csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
reclaimPolicy: Delete命名规则与 RBD 相同:前缀跟随 Operator
命名空间;VolumeSnapshotClass 的 driver
必须一致。Secret 对为
rook-csi-cephfs-provisioner /
rook-csi-cephfs-node。
二、CreateVolume 产物是 subvolume,不是「整个 CephFS」
动态供给时,Ceph-CSI 在指定 fsName 下创建
subvolume(常见名形如
csi-vol-...),并把 subvolumePath
等写入 PV volumeAttributes。应用 Pod
挂载的是该子树,不是文件系统根。
含义:
| 预期 | 实际 |
|---|---|
| 「共享整个 CephFS」 | 默认每个 PVC 一个隔离 subvolume |
| 跨 Namespace 直接共用同一 PVC | PVC 是命名空间对象;跨 NS 需静态 PV 配方(Rook 文档有 Retain + staticVolume 流程) |
| 配额可有可无 | CSI 用配额落实 PVC 声明大小;内核过旧时配额行为受限 |
Rook 文档:CephFS CSI 用配额强制 PVC
大小;内核至少约 4.17 才较好支持
CephFS 配额。更旧内核若必须强制配额,可改走 FUSE
客户端(v1.20 配置面在 Ceph-CSI Operator /
cephFsClientType,历史键名
CSI_FORCE_CEPHFS_KERNEL_CLIENT)——并接受升级时
FUSE 挂载断开、需重启应用 Pod 的已知代价。
三、RWX 的编排承诺与 POSIX 账单
accessModes: [ReadWriteMany] 在 K8s
里只表示「多个写者被 API 允许」。真正的一致性由
CephFS capability
协议保证:谁缓存、谁缓冲写、谁必须在 revoke 时
flush——见 ceph/13 ·
Capability。
编排侧因此付出的税(本篇只列「会在 K8s 事故里冒出来」的部分):
- MDS 可用性:active MDS 抖动 → 多副本 Deployment 同时卡住,比单 RBD 卷故障面更大。
- 元数据池延迟:大量小文件 create/unlink、目录 listing,把延迟推到 MDS journal,而不是数据池 OSD 平均延迟。
- 多 active
MDS:
activeCount > 1只在元数据真成瓶颈且热点可空间切开时值得;否则先买到 subtree thrashing(ceph/13)。 - 频繁 fsync / 强同步库:机制结论是「别把这类负载直接放 CephFS」——与是否用了 CSI 无关。
把「RWX StorageClass」理解成「免费 NFS」会低估 caps 税。Rook 示例用 kube-registry 多副本挂同一 PVC,演示的是共享文件系统可行,不是「任意 POSIX 密集负载都合适」。
四、挂载客户端:kclient 与 fuse
| 客户端 | 配置入口(v1.20) | 要点 |
|---|---|---|
| 内核客户端(kclient) | 默认优先 | POSIX/性能通常更好;能力随内核版本 |
| ceph-fuse | cephFsClientType 等 |
便携、易调试;多一层 FUSE;升级断开风险 |
多文件系统 + 过旧内核(文档举过 < 4.7)时,指定文件系统命名空间可能不一致——属于节点内核矩阵问题,不是改 SC 名字能修好的。
NodeStage/Publish 对 CephFS 是 mount 子树路径,不是 RBD
的 rbd map。排障时看 node plugin 日志与节点上的
CephFS 挂载选项;features/krbd 那套叙事不要硬套过来。
五、与 RBD CSI 的对照(编排视角)
| 维度 | RBD CSI | CephFS CSI |
|---|---|---|
| Provisioner | *.rbd.csi.ceph.com |
*.cephfs.csi.ceph.com |
| 后端对象 | Format 2 image | subvolume |
| 典型 AccessMode | RWO | RWX |
| 节点附着 | map 块设备 + fs | mount 文件系统路径 |
| 主要税 | features/krbd、exclusive-lock | MDS/caps、元数据池 |
| 快照语义 | image 级(第 9 篇) | subvolume 级 vs .snap 目录级(第 9
篇) |
数据面在 Bound 之后仍归 RADOS:文件内容直访 OSD,元数据走 MDS——这是 OSDI 2006 以来的分叉,不因 CSI 改变。
六、常见编排失败模式
| 现象 | 优先检查 |
|---|---|
| PVC Pending | CephFilesystem 是否
Ready;fsName/pool 是否与 SC
一致;cephfs provisioner Secret |
| Bound 但 Pod MountFailed | 节点内核;kclient vs fuse;MDS 是否 online |
| 多 Pod 同时卡在同一目录 | caps revoke / MDS;不要先扩 OSD |
| 配额不生效 | 内核是否支持 CephFS quota |
| 跨 NS「共享失败」 | 是否误以为 PVC 可跨 NS;应走静态 PV 文档路径 |
六、跨 Namespace 共享:静态 PV 的编排税
Rook 文件系统文档给出「同一 subvolume、多个
Namespace」的静态配方:原始动态 PVC/PV 改
Retain,再复制 PV 并加
staticVolume / rootPath,在目标
Namespace 建指向该 PV 的 PVC。这能工作,但代价是:
- 动态快照、克隆、扩容、删除要回到原始 PVC;静态副本是挂载句柄,不是第二套控制器生命周期。
- 删除必须按文档顺序,否则留下孤儿 subvolume 或误删仍在用的路径。
- 已知问题:同一节点多次挂载时全局 mount 可能残留,日志噪音与挂载泄漏需运维手工清理(文档 Pending Issue 叙述)。
平台若把「跨 NS 共享目录」做成自助工单,应默认提供受控静态模板与回收 runbook,而不是让每个应用团队复制半份 PV YAML。更干净的产品化路径往往是:同 NS 内 RWX,或对象存储,而不是无限复制静态 PV。
七、配额、容量展示与「假满」
PVC 的 requests.storage 经 CSI 落到 CephFS
配额后,df 在 Pod
内看到的是配额视图,不一定等于数据池真实占用。运维若只盯池容量百分比,可能与租户「我的卷还有空间」观感冲突;反之,租户写满配额而池仍空,会表现为
ENOSPC 类错误但集群 HEALTH_OK。
排障时同时看:PVC 容量、subvolume 配额、数据池 USED、元数据池延迟。把四者塌缩成「CephFS 满了」会误修。
八、谱系、争论与开放问题
谱系:Weil et al.(OSDI 2006)定义「MDS 权威元数据 + 客户端直访数据 + 动态 subtree」。CSI 只是把 subvolume 生命周期接到 PVC。站内深度在 ceph/13;本篇不重写 journal 结构与 Migrator。相对 GFS 单 master(Ghemawat et al., SOSP 2003),Ceph 选动态分区换扩展性,也把 thrashing 与跨 rank rename 税留在工程现实里——这些税在 K8s 多副本同时写同一 PVC 时更容易被业务感知。
争论:共享存储该不该在 K8s 里用「真正的
POSIX FS」?一派坚持 RWX+CephFS;一派用对象存储 +
应用级协调,或每个副本独立 RBD。争论焦点是
caps/fsync 税是否可接受,不是 provisioner
字符串好看不好看。另一争论是默认 kclient 还是
fuse:可移植与调试 vs 升级断开与性能——Rook 把选择收成
cephFsClientType,要求平台显式选边。
开放问题:
- CSI 能否把 MDS 延迟与 cap 等待导出为与 kubelet Mount 失败同级的、可告警的稳定信号?(见第 12 篇观测方向。)
- VolumeSnapshot(subvolume 级)与用户在应用内使用
.snap目录快照的语义教育,如何在平台层默认防呆?(第 9 篇展开。) - 跨 NS 静态共享能否变成一等 CR,而不是文档级 YAML 复制,以降低误删面?
九、本篇收束
CephFS CSI 兑现的是「声明式 subvolume + RWX 挂载」,不是「免费消除 POSIX 分布式税」。选这条路径前,先用 ceph/13 的判据问清:是否频繁 fsync、元数据是否热点、编制是否看得懂 MDS。下一篇把快照语义差一次说清。
十、何时不该把 CephFS CSI 当默认 StorageClass
给出可执行的负向清单(机制来自 ceph/13 与本篇编排税,不是口味):
- 数据库或其它依赖频繁
fsync/O_SYNC的引擎把数据目录放在 CephFS 上; - 单目录百万级小文件创建、又计划靠「多开 active MDS」硬扛,却未评估 thrashing;
- 团队只会看 PVC Bound,不会看 MDS 与 cap 指标;
- 需要「目录级任意时间点恢复」却只准备了 VolumeSnapshot 操作手册(语义差见第 9 篇)。
正向清单更短:多副本只读配置树、制品缓存、需要 POSIX 共享但不把同步写放在关键路径上的工作负载——并且接受元数据池与 MDS 的编制成本。
把 CephFS CSI 设成集群默认 SC「图省事」,会把不适合的负载一并吸进来,事故复盘时再争论「是不是 Ceph 不行」。排除应发生在 StorageClass 分层与准入,而不是发生在客户怒火里。
与 RBD 默认 SC 并存时,用命名与文档写清:块给有状态单写者,文件给共享读写;不要靠口头传统。
十一、编排侧如何「看见」MDS 税
K8s 仪表盘默认不显示 cap revoke、journal 积压或 subtree export。结果是:CephFS PVC 的用户按「磁盘满/网络差」开单,存储值班按「OSD 很好」结单,中间的 MDS 层无人认领。编排层至少要补三类信号入口(具体面板在第 12 篇):
- MDS Pod 就绪与 failover 次数;
- 元数据池 commit/apply 延迟;
- 与 cap 相关的驱逐或卡住客户端计数(名称以所用 Ceph 版本指标为准)。
没有这三类,RWX 工作负载的 SLO 只能写成「尽力而为」。把 CephFS 当默认共享盘的团队,等于在没有仪表的情况下承诺 POSIX。
另一常见编排失误是:为了「高可用」把
activeCount
调大,却不改业务目录布局。热点仍在单个目录树时,多 active
只增加 migration barrier 概率。决策顺序应是:先证明单 active
+ 更快元数据池不够,再证明热点可切开,再改
activeCount。Rook CR 里把数字改大很容易,回滚
thrashing 现场很难。
安全上,CephFS 的只读挂载与 POSIX 权限是另一层;CSI 供给的 Secret 是集群级客户端身份。租户隔离若只靠目录权限而不靠 subvolume/Namespace 边界,会在「某个 Pod 被攻破」时扩大爆炸半径。第 15 篇展开;本篇提醒:RWX 便利与隔离强度负相关。
与 NFS CSI(第 10 篇)比较:CephFS CSI 是成熟路径,NFS CSI 是实验路径。需要 NFS 协议本身(集群外客户端、特定锁行为)时才评估 NFS;只是要共享目录,优先 CephFS CSI。
十二、供给失败与 MDS 无关的那些坑
不是所有 CephFS PVC Pending 都值得去看 MDS。先排除:
fsName与CephFilesystemmetadata.name 不一致;pool参数写成数据池逻辑名错误(Rook 示例里常是{fs}-replicated一类,以实际池名为准);- provisioner 前缀与 Namespace 不一致;
- cephfs 的 Secret 尚未生成(文件系统未就绪时过早建 SC/PVC)。
这些是第 6 篇同构的编排错误。只有 Bound 成功、多客户端同时卡住或元数据操作超时,才把主战场切到 ceph/13 的 journal/caps/subtree。把顺序反了,会在健康的 MDS 上空转。
另:kube-registry 示例用三副本挂同一 PVC,适合演示 RWX,不适合当「所有有状态应用模板」。复制示例时删掉业务无关的 registry 环境变量很容易,复制「多写者共享一块盘」的架构假设却很难删——代码评审应盯后者。
写进架构决策时,建议附否证条件:若主业务开始把同步写数据库放在 CephFS PVC 上,或元数据创建速率使单目录 export 在观测窗口内反复发生,则本篇「可选用 CephFS CSI」的结论必须重开,而不是靠「我们已经 RWX 很久了」延用。机制允许长期正确,也允许负载变迁后突然错误——编制要能触发重评。
参考资料
官方文档(A)
- Rook v1.20 — Filesystem Storage Overview — SC 示例、配额、跨 NS 静态共享
- Rook v1.20 — Ceph CSI Drivers
- Rook v1.20 — CSI
Configuration —
cephFsClientType - Ceph Squid — CephFS 文档(机制以站内 ceph/13 为准)
论文(A)
- Weil, S. et al.「Ceph: A Scalable, High-Performance Distributed File System」OSDI 2006
站内
→ 上一篇:挂载与 features · 系列目录 · 下一篇:快照与克隆
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【Rook / CSI】RBD 供给路径:StorageClass 到 CreateVolume 到 image
拆解 Rook 默认 RBD CSI 如何把 StorageClass 参数与 Secret 转成 CreateVolume,再落到 Format 2 image;钉死 provisioner 命名前缀、池与 imageFeatures 边界,并外链 ceph/12 的对象命名——不重写 BlueStore。
【Rook / CSI】快照与克隆:VolumeSnapshot 语义、扩容与 CRD 错位
拆解 VolumeSnapshot/VolumeSnapshotClass/VolumeSnapshotContent 在 RBD 与 CephFS 上的保证;对照目录级 .snap 的语义差;覆盖 expand、静态 PV、clone/restore,以及 external-snapshotter 与 group snapshot CRD 版本错位失败模式。
【Rook / CSI】对象与 NFS:RGW 暴露边界与实验性 NFS CSI
划清 CephObjectStore/RGW 对 K8s 应用的暴露边界;说明 Rook NFS CSI 的 experimental 地位与依赖(CephFilesystem+CephNFS,非 RGW);本系列不写成 S3 教程——机制外链 ceph/14。
【Rook / CSI】编排全景:五轴坐标系与 16 篇路线
相对 ceph/ RADOS 内核与 storage/ 云块选型,钉清 Rook/CSI 编排层缺口;定义 CSI RPC、sidecar、Operator/CRD、数据面归属、升级闸门五条坐标系,给出 16 篇阅读路线与 PVC Bound 之后 I/O 仍走 krbd→PG→BlueStore 的边界。