备份工具报告「快照
Ready」并不等于「你以为的那一层时间点」。在 Rook 上,K8s
VolumeSnapshot API、RBD image snap、CephFS
subvolume snap,以及用户在目录里看到的
.snap,共享「快照」一词,却不共享同一套保证。再叠上
external-snapshotter sidecar 与集群 CRD
的版本错位,会出现「普通单卷快照也不 ready」的编排级故障——与
Ceph 数据面无关。
本文是「Rook / CSI」系列第 9 篇(共 16 篇)。→ 系列目录
篇目 核心内容 第 8 篇 · CephFS CSI subvolume / RWX 第 9 篇 · 快照与克隆 VolumeSnapshot 语义;expand;CRD 错位 第 10 篇 · 对象与 NFS RGW / NFS 边界
版本锚定:Rook v1.20.4;Ceph-CSI v3.17.0;K8s v1.31–v1.36。RBD/CephFS 快照机制外链 ceph/12、ceph/13。ceph/18 点名的「目录级 snap vs VolumeSnapshot 卷级语义」在此展开。
一、三件套与驱动名
K8s 快照控制面(需安装 snapshot CRD +
snapshot-controller):
| 对象 | 角色 |
|---|---|
VolumeSnapshotClass |
类比 StorageClass:指定
driver、删除策略、Secret |
VolumeSnapshot |
命名空间内的快照声明,指向 PVC |
VolumeSnapshotContent |
集群级实体,承载快照句柄 |
RBD 示例语义(驱动名必须与 StorageClass provisioner 一致):
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: rook-ceph-block-vsc
driver: rook-ceph.rbd.csi.ceph.com
deletionPolicy: Delete
parameters:
# 按 Rook/Ceph-CSI 示例填写 clusterID 与 snapshot SecretCephFS 则把 driver 换成
rook-ceph.cephfs.csi.ceph.com。前缀随 Operator
命名空间变化时,SC 与 SnapshotClass
必须一起改。
动态供给链路:
flowchart LR
vs["VolumeSnapshot"] --> vsc["VolumeSnapshotClass"]
vs --> pvc["源 PVC"]
vsc --> snapctl["snapshot-controller"]
snapctl --> side["csi-snapshotter sidecar"]
side --> csi["CSI CreateSnapshot"]
csi --> back["RBD snap / CephFS subvolume snap"]
任一层 CRD/控制器缺失或版本错位,CSI 驱动可能根本收不到 CreateSnapshot——表现为 VolumeSnapshot 长期不 Ready,Events 含 reflector / rate limit 一类错误。
二、三种「快照」各保证什么
这是本篇的核心对照表,也是 ceph/18 停损线的展开:
| 机制 | 粒度 | 谁协作 | 典型用途 | 常见误解 |
|---|---|---|---|---|
RBD VolumeSnapshot |
整 image | 应用/fsfreeze/qemu-ga 决定是否 crash-consistent | PVC 备份、整卷还原 | 以为等于文件系统一致快照 |
CephFS CSI VolumeSnapshot |
整 subvolume(该 PVC 对应子树) | MDS 协调持 cap 客户端 flush(实现依赖 CSI/Ceph 路径) | 卷级备份/还原 | 以为等于任意目录的 .snap |
CephFS .snap 目录快照 |
目录子树(用户在 FS 内创建) | 客户端 flush 协作;硬链接跨 snap 有已知限制 | 用户自助目录时间点 | 以为 Velero/VolumeSnapshot 做了同一件事 |
补充:
- RBD snap 的 COW 落在 PrimaryLogPG;创建本身几乎不复制数据,税在后续首次覆盖写——见 ceph/12。
.snap更贴近「用户可见目录时间点」,也更依赖客户端诚实;与「存储层自闭」的 RBD snap 不能互相替代——见 ceph/13 · MDS 快照对照。- VolumeSnapshot Ready ≠ 应用一致:块/文件层都不自动知道数据库事务边界。需要一致备份时,仍要应用级 quiesce 或逻辑备份。
平台若把「目录级恢复」写进 SLA,却只提供 VolumeSnapshot API,会在事故复盘时发现语义空窗——这是编排与内核交接处的真实摩擦,不是文档笔误。
三、从快照恢复与克隆
3.1 从 VolumeSnapshot 建卷
常见模式:新 PVC 的 dataSource 指向已有
VolumeSnapshot(或兼容的快照内容)。CSI 侧对
RBD 走 clone/从 snap 建 image 一类路径;对 CephFS 走
subvolume 快照克隆语义。父子依赖、protect/flatten、COW
放大等 RBD 内核账单仍适用(ceph/12);CSI
只负责 RPC 与 PV 绑定。
3.2 PVC clone
dataSource 指向另一 PVC(同
StorageClass/驱动支持时)可做卷克隆。注意:
- 静态 PV / 跨 Namespace 手工共享的 CephFS 卷,Rook 文档写明:不支持对静态副本做 snapshot/clone/resize/delete 一类动态操作——必须在原始动态 PVC 上做。
- 克隆链过深会叠加读放大;生产模板卷策略仍建议:只读 snap + 受控 clone + 必要时 flatten(机制在 ceph/12,不在本篇重写)。
3.3 静态 PV
RBD 与 CephFS 均支持把已有 image/subvolume 做成静态 PV(Rook「Static Provisioning」)。用于迁入存量数据或跨集群挂载句柄。静态路径下,动态快照/扩容能力以驱动与文档边界为准;不要假设「有 PV 就有全套 CSI 控制器操作」。
四、扩容(allowVolumeExpansion)
StorageClass 需:
allowVolumeExpansion: truecsi.storage.k8s.io/controller-expand-secret-*指向 provisioner Secret
操作是调大 PVC
spec.resources.requests.storage。控制器走
ControllerExpandVolume,后端扩大
image/subvolume,再视文件系统做 online resize。前提(Rook
文档):
- 文件系统类型在支持集合内(常见 ext4/xfs 等;具体以 CSI/K8s 支持矩阵为准)。
- 节点与驱动版本匹配;缩容通常不在支持面——生产默认只扩不缩。
扩容失败时分层看:SC 未开 expand → Secret → CSI expand RPC → 后端配额/池容量 → 文件系统 resize。不要把「PVC 事件里容量未变」直接写成「OSD 满」而不看 expand 日志。
五、external-snapshotter 与 group snapshot CRD 错位
这是编排失败模式,值得单独成节。
5.1 现象
- VolumeSnapshot 长期不 Ready;
- CSI provisioner / snapshotter 容器日志出现对
VolumeGroupSnapshot*的Failed to watch/could not find the requested resource(常点名v1beta2); - 普通单卷快照也受牵连——sidecar 在 group CRD 监视失败时可能拖垮工作队列(社区在 external-snapshotter issue、Rook issue 如 #17043 等路径上有复现叙述)。
5.2 机制梗概
kubernetes-csi/external-snapshotter
在较新发行线(社区讨论集中在 8.4+
sidecar)对 Volume Group Snapshot API
的预期收紧:需要匹配的 v1beta2 group
snapshot CRD(及控制器/feature gate 配置)。若集群只装了旧的
v1beta1 group CRD、或 CRD 与
sidecar/controller
版本错位,监视失败会变成全局性快照功能障碍。
Rook 侧默认会跟随较新的 sidecar 镜像标签;集群里的 CRD 往往由发行版/其它 chart 安装,不一定与 Rook 捆绑升级。结果是:升 Rook/CSI 后「Ceph 很健康,快照全坏」。
5.3 处置原则(不写逐步黑客操作)
- 核对:snapshot CRD
版本、
snapshot-controller版本、CSI Pod 内csi-snapshotter镜像标签是否属于同一支持组合(以上游 external-snapshotter 发布说明为准)。 - 若启用或残留 group snapshot CRD,确保 served 版本满足当前 sidecar 要求(社区常见修复是补齐上游 v1beta2 CRD,或暂时对齐较旧 sidecar——以官方兼容说明为准)。
- 把「快照 CRD/控制器」列入 Rook 升级检查单(第 11 篇),与 Ceph 镜像升级同等对待。
这不是 CephFS 或 RBD 的 COW bug;用 ceph -s
查不出来。
六、谱系、争论与开放问题
谱系:卷快照 API 是 SIG Storage
把「厂商快照」收成声明式资源的结果;CSI
CreateSnapshot/DeleteSnapshot
是最小面。Ceph 侧则早有 RBD snap 与 CephFS 目录 snap
两套用户故事。三者在「时间点」口语下合流,在「粒度与协作」上从未合流。
争论:备份该不该默认挂 VolumeSnapshot?一派认为编排一致、可进 GitOps;一派指出语义教育成本高,逻辑备份更可控。对数据库类负载,机制上更稳的是:VolumeSnapshot 当 crash-consistent 底线 + 应用一致策略,而不是单押 Ready 条件。
开放问题:
- 平台能否在 VolumeSnapshotClass 注解层强制区分「image/subvolume」与「禁止暗示目录级恢复」?
- Rook/CSI 默认镜像与发行版自带 snapshot CRD 的兼容矩阵,能否变成安装时的准入检查,而不是事故后读 issue?
七、备份链路里的责任切割
一套常见生产链路是:Velero / 自研控制器创建 VolumeSnapshot → 等 Ready → 另存或复制快照内容。责任切割应写成:
| 角色 | 负责 | 不负责 |
|---|---|---|
| 快照控制器 + CSI | 卷级时间点对象创建成功 | 应用事务一致 |
| Ceph | 按 RBD/CephFS 语义保留 snap 可见性 | 解释业务含义 |
| 应用所有者 | quiesce / 逻辑备份 / 恢复演练 | 假装 Ready 即一致 |
| 平台 | CRD/sidecar 版本对齐、容量与保留策略 | 替每个应用定义 RPO 语义 |
缺少「应用所有者」一行时,所有 Ready 快照都会在恢复演练中暴露缺口。平台可以用策略强制「数据库命名空间必须有逻辑备份注解」,但不能用 VolumeSnapshot 代替那一行。
保留策略也要切清:deletionPolicy: Delete
在删 VolumeSnapshot 时回收后端 snap,可能影响仍依赖该 snap
的 clone 链;Retain
则留下需垃圾回收的后端对象。RBD 的 protect/flatten
纪律(ceph/12)在 CSI
克隆大量涌现时更容易被忘记——模板盘删不掉,往往是子 clone
未清理,不是 Ceph「坏了」。
八、扩容与快照叠加时的顺序问题
生产上常见组合操作:先快照,再扩容,再从快照恢复到新大小,或在已有 snap 的 image 上反复扩缩。RBD 层对「有 snap 时的容量边界与 OID 生命周期」更敏感(ceph/12 提醒生产少做有 snap 缩容再扩容)。CSI 扩容 API 不会自动替你教育这些内核约束。
建议操作纪律:
- 扩容前确认是否存在需要长期保留的 VolumeSnapshot;理解 COW 与 snaptrim 对池的影响。
- 恢复演练使用「新 PVC + dataSource」而不是假设原地魔法变回。
- 大规模克隆后安排 flatten 或生命周期清理,避免父盘无法删除。
CephFS 侧,subvolume 配额随扩容调整后,应用是否立即看见新大小取决于客户端与配额实现;不要在自动化里假设「patch PVC 后下一秒 df 已变」而不加等待与校验步骤。静态跨 NS 卷更是明确不支持在静态句柄上 resize——自动化若对所有 PVC 盲目 expand,会在静态副本上持续失败并产生噪音告警。
关于 group snapshot:即便你「不用」组快照功能,只要 CRD 与 sidecar 版本错位,仍可能伤到单卷快照。因此升级检查单不能写「我们未启用 group snapshot故跳过 CRD 检查」——第 11 篇把该项列为必填,原因在此。
开放问题补一句:在混合 RBD 与 CephFS 的命名空间里,同一套 Velero 配置能否安全默认?机制上两者 Ready 的含义不同,平台或许应按 StorageClass 拆备份策略,而不是一套注解打天下。
九、把语义差写进恢复演练脚本的标题
恢复演练名称若叫「Ceph 快照恢复」,参与者会对齐到不同对象。建议标题直接写机制:
- 「RBD VolumeSnapshot 整卷恢复演练」
- 「CephFS subvolume VolumeSnapshot 恢复演练」
- 「CephFS 目录
.snap用户自助恢复演练」(若平台提供)
三种演练的前置、成功标准、数据校验方法都不同。例如 RBD
恢复后要校验文件系统 journal;CephFS .snap
要校验目录子树与硬链接预期。用同一份检查清单只会得到虚假通过。
平台文档若只能维护一种,优先维护 VolumeSnapshot
卷级,并显式写「不覆盖目录级
.snap」。这比假装三者等价更负责任,也直接回应
ceph/18 的停损点名。
工程间隙再补一句:论文与规范里的「快照」常假设单一实现者与清晰粒度;K8s 生态把厂商快照、CSI、组快照、应用备份控制器叠在同一集群后,失败模式转向版本组合。Ceph 数据面再健康,也救不了 CRD 错位。把「存储升级」与「快照控制面升级」拆成两行风险登记,是便宜的流程改进。
对 clone 链的成本沟通,应用负责人常只看见「秒级创建新 PVC」。平台应在自助文档写明:创建快、第一次写与 flatten 可能很慢,池容量与父盘删除受限。没有这句,CSI 的便利会变成容量事故的伪装。
参考资料
规范 / 官方 / issue(A/B)
- Kubernetes Volume Snapshot API;CSI Snapshot 相关规范
- Rook v1.20 — CSI Drivers(扩容、静态供给);RBD/CephFS
快照示例目录
deploy/examples/csi/ - kubernetes-csi/external-snapshotter — group snapshot 与 CRD 要求说明
- Rook #17043;external-snapshotter #1385(sidecar 与 group CRD 错位导致单卷快照失败的失败模式)
站内
→ 上一篇:CephFS CSI · 系列目录 · 下一篇:对象与 NFS
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
Rook / CSI:K8s 上的 Ceph 编排内核
补齐站内 Ceph RADOS 内核之上的编排层:CSI 规范与 sidecar、Rook Operator/CRD、Ceph-CSI Operator、RBD/CephFS 供给与挂载、VolumeSnapshot 语义差、升级闸门,以及排障与选型收束。
【Rook / CSI】RBD 供给路径:StorageClass 到 CreateVolume 到 image
拆解 Rook 默认 RBD CSI 如何把 StorageClass 参数与 Secret 转成 CreateVolume,再落到 Format 2 image;钉死 provisioner 命名前缀、池与 imageFeatures 边界,并外链 ceph/12 的对象命名——不重写 BlueStore。
【Rook / CSI】挂载与 features:NodeStage、krbd 错位与 read affinity
拆解 RBD 的 NodeStageVolume/NodePublishVolume、map 路径与 imageFeatures 对 krbd 的依赖;说明失败为何常表现为挂上但怪;钉死 csi.readAffinity 与 Tentacle v20.2.0 损坏警告,并简述 network fencing。
【Rook / CSI】CephFS CSI:subvolume、RWX 与编排侧 MDS 税
拆解 Rook 上 CephFS CSI 如何用 subvolume 兑现 ReadWriteMany;钉死 provisioner 命名、StorageClass 与配额边界,并说明编排侧为 MDS/caps 付出的税——外链 ceph/13,不重写 journal 内核。