土法炼钢 · 系统与基础设施

【Rook / CSI】RBD 供给路径:StorageClass 到 CreateVolume 到 image

文章导航

分类入口
storagekubernetes
标签入口
#rook#csi#rbd#storageclass#createvolume#provisioner#squid#v1.20.4

目录

PVC 卡在 Pending 时,值班最常问的是「调度坏了还是存储坏了」。对 Rook 上的 RBD 来说,真正要回答的是:声明式的 StorageClass 参数,如何经 external-provisioner 变成 Ceph-CSI 的 CreateVolume,再变成池里的 Format 2 image。 挂载与 features 错位留给下一篇;本篇只钉供给路径。

本文是「Rook / CSI」系列第 6 篇(共 16 篇)。→ 系列目录

篇目 核心内容
第 5 篇 · Ceph-CSI Operator OperatorConfig / Driver
第 6 篇 · RBD 供给 StorageClass → CreateVolume → image
第 7 篇 · 挂载与 features NodeStage/Publish;krbd 错位

版本锚定:Rook v1.20.4;Ceph-CSI v3.17.0;K8s v1.31–v1.36。后端机制叙述对齐站内 ceph/12 · RBD(Squid);Ceph 集群支持 Squid v19.2.x / Tentacle v20.2.1+。无真实 Rook 集群时不粘贴伪造 kubectl 输出;配置片段取自 Rook v1.20 官方示例语义。


一、供给路径的坐标系

一次动态供给最少穿过四层:

对象 失败时常见表象
API PVC / StorageClass Pending,Events 无 CSI 日志
Sidecar external-provisioner 一直重试、leader 选主异常
CSI Controller Ceph-CSI RBD CreateVolume mon 不可达、Secret 错误、池不存在
RADOS Format 2 image + header OID toolbox 里 rbd ls 看不到期望 image
flowchart LR
  pvc["PVC Bound request"] --> sc["StorageClass\nprovisioner + params"]
  sc --> ep["external-provisioner\nsidecar"]
  ep --> cv["CSI CreateVolume"]
  cv --> img["RBD Format 2 image\nin pool"]
  img --> pv["PV + volumeHandle"]

I/O 尚未开始:PVC Bound 只保证「有一块可挂的 image」。对象如何按 order 切 OID、写如何进 PG/BlueStore,见 ceph/12ceph/08。本篇不重写 BlueStore。


二、provisioner 命名:命名空间前缀不是装饰

Rook 默认把 CSI 驱动名做成「Operator 命名空间 + 驱动后缀」。官方块存储示例(deploy/examples/csi/rbd/storageclass.yaml,Rook v1.20 文档):

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: rook-ceph-block
provisioner: rook-ceph.rbd.csi.ceph.com
parameters:
  clusterID: rook-ceph
  pool: replicapool
  imageFormat: "2"
  imageFeatures: layering
  csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
  csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
  csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner
  csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
  csi.storage.k8s.io/controller-publish-secret-name: rook-csi-rbd-provisioner
  csi.storage.k8s.io/controller-publish-secret-namespace: rook-ceph
  csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
  csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
  csi.storage.k8s.io/fstype: ext4
reclaimPolicy: Delete
allowVolumeExpansion: true

要点:

  1. provisioner: rook-ceph.rbd.csi.ceph.com:前缀 rook-ceph 必须与 Rook Operator / CSI 所在命名空间一致。Operator 装在 my-namespace 时,应写成 my-namespace.rbd.csi.ceph.com(Rook「Ceph CSI Drivers」文档硬条件)。
  2. v1.20:驱动名由 Ceph-CSI Operator 的 Driver CR metadata.name 决定,不再靠改 rook-ceph-operator-config 里的 CSI 键来「偷偷改名」。Helm 路径用 ceph-csi-drivers chart 的推荐 values.yaml,显式写出带命名空间前缀的驱动名。
  3. VolumeSnapshotClass 的 driver 字段必须与 StorageClass 的 provisioner 同名。只改一边会导致快照 RPC 找不到驱动。

把前缀当成可随便起的 DNS 名,是多集群联邦或「复制粘贴 SC」时最常见的 Pending 根因之一:API 对象合法,但集群里根本没有该名的 CSIDriver。


三、StorageClass 参数如何映射到 CreateVolume

3.1 必填语义

参数 含义 错了会怎样
clusterID Rook 文档口径:通常为 CephCluster 所在命名空间 mon endpoint / CSI config 对不上
pool image 所在的 CephBlockPool CreateVolume 失败:池不存在
Secret 四元组 provisioner / expand / publish / node-stage auth 失败或挂载时无 node 凭据
imageFormat 默认 "2" Format 1 已弃用;生产只谈 Format 2
imageFeatures Format 2 特性位的符号列表 供给成功但后续 map 失败或行为怪(见第 7 篇)

CephBlockPool 必须先存在。示例里 replicapoolfailureDomain: hostreplicated.size: 3 要求至少三个不同节点上的 OSD;这是池放置约束,不是 CSI 本身的问题。池创建失败时,PVC 会在 CreateVolume 阶段报错,而不是在调度阶段。

3.2 Secret 分工

Rook Operator 在集群命名空间生成:

凭据对应 Ceph 客户端 cap(通常是 profile rbd 一类)。Secret 命名空间写错、或手工轮换 keyring 后未同步 CSI Pod,表现为间歇性 CreateVolume / map 失败。排障时先对 Secret 存在性与命名空间,再怀疑 mon。

3.3 fstype 与扩容


四、CreateVolume 落成什么

Ceph-CSI RBD 在 CreateVolume 中(语义对齐 ceph-csi RBD 文档与 Rook 块存储章):

  1. 用 provisioner Secret 连 mon,确认 pool 可用。
  2. 按 PVC 请求容量创建 Format 2 image(名称通常由 CSI 生成,带 csi-vol- 一类前缀;以实际 rbd ls / PV volumeHandle 为准)。
  3. 写入 StorageClass 声明的 imageFeatures
  4. 返回 volume_id / 上下文,供 K8s 写成 PV 的 CSI volumeHandlevolumeAttributes

image 一经创建,RADOS 侧就有:

偏移到对象序号的公式、striping、与 Exclusive Lock 的关系,见 ceph/12 · image 到对象映射。编排层只需记住:PVC 容量是 image 逻辑大小;实际占用随写入与快照 COW 增长,不是「一创建就占满 GiB」。


五、imageFeatures:供给时就要为挂载买单

Rook 官方示例对内核版本给出两档建议:

内核 建议 imageFeatures 对应社区叙述
≥ 5.4 layering,fast-diff,object-map,deep-flatten,exclusive-lock(位掩码叙述为 63) krbd 支持较完整特性集
≤ 5.3 layering(位掩码叙述为 2) 避免 map 时特性闸门失败

ceph/18 点名的摩擦之一是:CSI 声明的 features 与节点 krbd 能力不一致。供给阶段往往成功——Controller 节点不一定是将来挂载的节点,异构内核集群尤其如此。失败被推迟到 NodeStage:有时是干净的 unsupported krbd Feature,有时表现为「挂上但怪」(第 7 篇展开)。

工程纪律:


六、Pending 归因:先分清层再下刀

观察 更可能落点
PVC Events 无 provisioner 相关信息 StorageClass 名错、无默认 SC、调度器未处理到供给
provisioner 日志反复 CreateVolume mon endpoint、clusterID、Secret、池名
CreateVolume 成功但 Pod 不调度 与存储无关的调度约束
Bound 后 MountVolume 失败 第 7 篇:map / features / Secret node

无集群截图时,仍可用命令语义自检(需可调度集群与 Rook toolbox):

kubectl get sc,pvc -A
kubectl -n rook-ceph get pods -l app=csi-rbdplugin
# toolbox 内:
# rbd ls -p replicapool
# rbd info replicapool/<image>

不要用「Ceph 慢」概括所有 Pending:供给路径上多数是配置与身份,不是 BlueStore 延迟。


七、谱系、争论与开放问题

谱系:块设备作为「RADOS 上的对象序列」可追溯到 Weil 的 Ceph 设计叙述与 RBD Format 2;K8s 侧则从 in-tree plugin / FlexVolume 迁到 CSI(规范定义 Controller CreateVolume 与 Node 服务的最小面,见 container-storage-interface/spec)。Rook 把 CephBlockPool + StorageClass 钉成声明式入口;v1.20 再把驱动配置所有权交给 Ceph-CSI Operator(第 5、11 篇)。

争论:StorageClass 应暴露多少 Ceph 细节?一端要求「应用只看见 storageClassName」;另一端要求运维能直接读到 pool、features、fstype。Rook 选择显式参数——可读、可 diff,也更容易复制粘贴出错。没有文献证明「隐式默认永远更安全」;生产上更稳的是:少数经过内核矩阵验证的 SC,而不是每个租户一份私货 features。

开放问题

  1. 调度前能力探测:能否在 CreateVolume 或调度器扩展里拒绝「将来无法在候选节点 map」的 PVC,而不是 Bound 后再挂载失败?(ceph-csi 有挂载时 feature 检测与 tryOtherMounters;调度前闭环仍弱。)
  2. 多 CephCluster / 多前缀:同一 API Server 上多个 Rook 命名空间时,provisioner 前缀与 clusterID 的可观测错位如何做成准入策略,而不是靠文档提醒?

八、与 CephBlockPool、回收策略的交接

供给路径上还有两个常被当成「CSI 细节」、实际是 RADOS 放置与生命周期 的开关。

池的 failureDomain 与副本数决定 CreateVolume 成功之后,image 的对象能不能按预期分散故障域。三副本却只备了两个节点的 OSD 时,池可能一直不干净或根本建不出来;PVC 侧只会看到 CreateVolume 重试。这时应回到 CephBlockPool / ceph osd tree 一类坐标系,而不是调大 provisioner 并发。

reclaimPolicy

多租户平台若默认 Retain 却没有回收工单,半年后会出现「容量监控显示池将满,但活跃 PVC 并不多」——根因在编排回收策略,不在 BlueStore 碎片。

EC 池作 RBD 数据池时,Rook 文档要求独立 replicated 元数据池 + dataPool 参数,且挂载节点内核有下限叙述。本篇不展开 EC 条带;要点是:StorageClass 参数必须与池拓扑一致,否则 CreateVolume 或后续 I/O 在错误层失败。


九、工程间隙:论文式「动态供给」与生产异构

CSI 规范把 CreateVolume 写成相对干净的 RPC:给容量与参数,回 volume id。生产 Rook 集群里,同一 StorageClass 会被:

规范假设「集群内驱动与节点能力同质」;异构是默认现实。因此第 6 篇的验收不应停在「示例 Wordpress PVC Bound」,而应包括:用计划中的最旧节点可调度类跑一次完整挂载(完整路径见第 7 篇)。只在新内核跳板机上验收供给,是把失败外包给上线当晚。

相对云盘 CSI:云厂商把 features 谈判收进控制面黑盒;Rook 把谈判摊开成 YAML。摊开可读,也要求平台自己维持内核矩阵——这是自建税,不是文档缺陷。


十、本篇边界

不写:BlueStore 写路径、PG peering、完整 Helm values 百科、云厂商托管块 API。
下一篇从 Bound 之后的 NodeStageVolume / NodePublishVolume 讲起,专钉 features 与 krbd。

把本篇收成一句话:Pending 时先问 provisioner 名、Secret、池与 CreateVolume 日志;Bound 只说明 image 在,不说明节点能 map。 对象命名与 COW 账单去 ceph/12;编排层到此交棒。


十一、供给并发、限流与「假死」

external-provisioner 与 CSI Controller 对 CreateVolume 有并发与重试行为(具体旗标随 sidecar 版本变化,以部署清单为准)。池或 mon 短暂抖动时,大量 PVC 同时 Pending 会放大重试风暴:日志看起来像「存储彻底坏了」,实际是控制面自激。

工程上可做的分层:

这些都不改变 RADOS 语义,却决定「人为故障」是否被误报成 Ceph 事故。第 12–13 篇会把指标与事件字段收成坐标;本篇先强调:供给路径的尾延迟包含 API Server 与 sidecar 队列,不是只有 OSD commit。

与云盘对照:托管控制面通常把重试与配额错误翻译成明确的 PVC Event 原因码;Rook 自建则要求值班会读 CSI 容器日志。编制不足时,这本身就是选型负分(见系列第 14–16 篇排除树方向)。

再补一条身份轮换纪律:Ceph 客户端 key 轮换后,必须确认 provisioner/node 两类 Secret 与 CSI Pod 已加载新内容,再宣布「轮换完成」。只改 mon 侧用户、不重启/不滚动 CSI,会造成「旧卷还能挂、新卷 CreateVolume 失败」的撕裂态,排障时极像随机故障。

十二、从系列阅读路径看本篇位置

必读核心路径(见 系列目录)把第 6 篇放在「知道 Operator 与 CSI Operator 之后、真正碰 PVC 之前」的位置。没有第 2 篇的 RPC 坐标系,CreateVolume 只是黑盒函数名;没有第 5 篇,你会在 v1.20 上继续改已经失效的 ConfigMap 键。本篇往下交给第 7 篇,是因为供给成功是挂载失败的必要非充分条件。

若读者只运维 RBD、不碰 CephFS,仍建议至少浏览第 9 篇的 VolumeSnapshot 与 CRD 错位:备份链路坏掉时,症状常被误报成「Rook 块存储坏了」。第 11 篇的升级闸门则决定你是否会在跳版本后同时失去供给能力与快照能力。

站内 ceph/12 与本篇的分工再强调一次:那边回答 image 如何变成 OID 与 COW 如何触发;这边回答 K8s 如何决定「该创建一个多大、带哪些 features 的 image」。两边都读完,才能在「挂上但怪」时判断该看内核还是该看 PG。

容量规划上,动态供给会让「池里有多少 image」变成 API 速率的函数。缺少配额(Namespace ResourceQuota / 存储配额策略)时,一个 CI Namespace 就可以用循环 PVC 打满池。这不是 Ceph 特有问题,但在自建 Rook 上没有云账单熔断,崩溃来得更沉默。平台侧应把 PVC 数量与请求容量的上限写成与 StorageClass 绑定的策略,而不是靠事后 rbd ls | wc

最后,关于「示例配置能否直接生产」:Rook 官方 imageFeatures: layering 示例偏保守,适合作为默认起点;把注释里的完整特性集复制进生产 SC 而不做内核矩阵,是把文档里的「可选优化」误读成「推荐必开」。保守默认 + 按工作负载开第二套 SC,通常比一套激进 SC 更安全。

参考资料

规范 / 官方文档(A)

站内

上一篇:Ceph-CSI Operator · 系列目录 · 下一篇:挂载与 features

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。

2026-08-15 · storage / kubernetes

【Rook / CSI】CephFS CSI:subvolume、RWX 与编排侧 MDS 税

拆解 Rook 上 CephFS CSI 如何用 subvolume 兑现 ReadWriteMany;钉死 provisioner 命名、StorageClass 与配额边界,并说明编排侧为 MDS/caps 付出的税——外链 ceph/13,不重写 journal 内核。


By .