4716 lines
224 KiB
Markdown
4716 lines
224 KiB
Markdown
# 07 · RBD 块存储篇
|
||
|
||
> 基于 Ceph 官方文档整理 | 文档版本:**Tentacle v20.2.4** | 抓取日期:2026-09-17 | 源文:ceph/ceph@v20.2.4 `doc/rbd/`
|
||
> 官网入口:https://docs.ceph.com/en/tentacle/rbd/
|
||
|
||
---
|
||
|
||
## 本册导读
|
||
|
||
本册覆盖 Ceph 官方文档 `doc/rbd/` 目录下的**全部 38 个 rst 页面**(含 `index.rst` 与 `man/index.rst`),按"概念 → 基本操作 → 高级特性 → 配置参考 → 平台集成 → 协议网关"的顺序重排,便于从零到生产级使用逐章推进。
|
||
|
||
| 阅读顺序 | 章节 | 覆盖的官方页面 | 建议读者 |
|
||
|---|---|---|---|
|
||
| 0 | 本册导读 | `index.rst` | 全部 |
|
||
| 1 | 一、RBD 是什么 | `index.rst` | 全部 |
|
||
| 2 | 二、核心概念 | `index.rst`、`rbd-config-ref.rst` | 全部 |
|
||
| 3 | 三、基本操作 | `rados-rbd-cmds.rst` | 全部(必读) |
|
||
| 4 | 四、内核模块与客户端 | `rbd-ko.rst`、`rbd-windows.rst` | 需要裸机映射的场景 |
|
||
| 5 | 五、快照与克隆 | `rbd-snapshot.rst` | 全部(必读) |
|
||
| 6 | 六、exclusive lock 与 object map | `rbd-exclusive-locks.rst` | 全部 |
|
||
| 7 | 七、缓存机制 | `rbd-persistent-read-only-cache.rst`、`rbd-persistent-write-log-cache.rst`、`rbd-config-ref.rst` | 性能调优 |
|
||
| 8 | 八、加密 | `rbd-encryption.rst` | 合规/安全场景 |
|
||
| 9 | 九、实时迁移 | `rbd-live-migration.rst` | 存储迁移、异构导入 |
|
||
| 10 | 十、镜像与灾备 | `rbd-mirroring.rst`(27KB,本册最大页面) | 灾备/双活 |
|
||
| 11 | 十一、配置参考 | `rbd-config-ref.rst` + `src/common/options/*.yaml.in` | 全部(查阅) |
|
||
| 12 | 十二、平台与集成 | `qemu-rbd.rst`、`libvirt.rst`、`rbd-kubernetes.rst`、`rbd-openstack.rst`、`rbd-cloudstack.rst`、`rbd-nomad.rst`、`rbd-windows.rst` | 云平台/虚拟化 |
|
||
| 13 | 十三、iSCSI | `iscsi-*.rst`(11 个页面) | 无原生 Ceph 客户端的场景 |
|
||
| 14 | 十四、NVMe-oF | `nvmeof-*.rst`(6 个页面) | 新部署的高性能场景 |
|
||
| 15 | 十五、其他 | `rbd-replay.rst`、`rbd-ko.rst` | 压测/内核映射 |
|
||
| 16 | 十六、命令速查表 | 汇总 | 全部 |
|
||
|
||
**重要提示(官方原文)**:iSCSI gateway 自 2022 年 11 月起进入 **maintenance(仅维护)** 状态,不再新增特性。新部署建议优先考虑 NVMe-oF gateway 或原生 `librbd`/`krbd`。
|
||
|
||
---
|
||
|
||
## 一、RBD 是什么
|
||
|
||
### 1.1 定位
|
||
|
||
块(block)是一串字节序列(通常 512 字节)。基于块的存储接口是一种成熟且通用的数据存取方式,广泛用于 HDD、SSD、CD、软盘乃至磁带。块设备接口的普适性,使其非常适合与 Ceph 这样的海量数据存储系统对接。
|
||
|
||
Ceph 块设备(Ceph Block Device,简称 RBD)具备三个基础属性:
|
||
|
||
1. **thin-provisioned(精简配置)**——创建时不占用物理空间,实际写入才分配;
|
||
2. **resizable(可调整大小)**——支持在线扩容与缩容;
|
||
3. **striped over multiple OSDs(跨 OSD 条带化)**——数据被切分并散布到集群内多个 OSD 上。
|
||
|
||
RBD 直接复用 RADOS(Reliable Autonomic Distributed Object Store)的能力,包括**快照(snapshotting)**、**复制(replication)**与**强一致性(strong consistency)**。
|
||
|
||
Ceph 块存储客户端通过两条路径访问集群:
|
||
|
||
```text
|
||
+------------------------+ +------------------------+
|
||
| Kernel Module | | librbd |
|
||
+------------------------+-+------------------------+
|
||
| RADOS Protocol |
|
||
+------------------------+-+------------------------+
|
||
| OSDs | | Monitors |
|
||
+------------------------+ +------------------------+
|
||
```
|
||
|
||
- **内核模块(krbd)**:可以使用 Linux page cache。
|
||
- **librbd**:用户态库,无法利用 Linux page cache,因此 Ceph 为其提供了独立的 **RBD Caching** 机制。
|
||
|
||
RBD 交付高性能与高可扩展性,服务对象包括内核模块、KVM(如 QEMU),以及依赖 libvirt 与 QEMU 集成 Ceph 块设备的云计算系统(OpenStack、OpenNebula、CloudStack)。同一个集群可以同时运行 RGW(对象网关)、CephFS(文件存储)和 Ceph 块设备。
|
||
|
||
> ⚠️ **前置条件(官方 important)**:使用 Ceph Block Devices 之前,你必须有一个**正在运行的 Ceph 集群**。
|
||
|
||
### 1.2 与本地磁盘 / 其他块存储形态对比
|
||
|
||
> 💡 补充:官方 `doc/rbd/index.rst` **没有提供**与其他存储形态的对比表。下表为便于选型而补充,其中「Ceph RBD」列的每一条均来自本册源文;「本地磁盘」「传统 SAN LUN」两列属于通用存储常识,非官方文档内容,请仅作定性参考,不要当作官方口径引用。
|
||
|
||
| 维度 | Ceph RBD | 本地磁盘(直连 HDD/SSD) | 传统 SAN LUN(FC/iSCSI 阵列) |
|
||
|---|---|---|---|
|
||
| 数据分布 | 条带化散布到多个 OSD(`index.rst`) | 单盘,无分布 | 集中在阵列控制器后端 |
|
||
| 容量分配 | thin-provisioned,写入才占空间 | 预分配/整盘 | 多为厚置备或阵列级精简 |
|
||
| 扩容 | `rbd resize` 在线扩/缩(`--allow-shrink`) | 换盘 / LVM 扩展 | 阵列侧扩容,主机侧 rescan |
|
||
| 副本与故障域 | RADOS 多副本/纠删码,跨节点、跨机架 | 无(依赖 RAID) | 依赖阵列双控与 RAID |
|
||
| 一致性 | RADOS 强一致性 | 本地顺序一致 | 阵列保证 |
|
||
| 快照 | image 级快照 + COW 克隆(layering) | 需 LVM/VSS 等 | 阵列快照(数量常受限、可能收费) |
|
||
| 克隆效率 | 快照 protect 后可秒级创建 COW 克隆 | 全量拷贝 | 依赖阵列克隆能力 |
|
||
| 远程复制 | 内建 `rbd-mirror`(journal / snapshot 两种模式) | 无 | 需阵列级远程复制许可 |
|
||
| 客户端形态 | krbd(内核)/ librbd(QEMU、ceph-csi)/ NBD / iSCSI GW / NVMe-oF GW | 本地 | 需 FC HBA 或 iSCSI initiator |
|
||
| 无原生客户端的机器 | 可通过 iSCSI GW / NVMe-oF GW 接入 | — | — |
|
||
| 多客户端并发写 | 需外部协调;`exclusive-lock` 只做线性化不做互斥(`rbd-exclusive-locks.rst`) | 不适用(单机) | 依赖集群文件系统/阵列锁 |
|
||
| 文件系统的坑 | 缓存开启时不能跑 GFS/OCFS(`rbd-config-ref.rst`) | 无 | 同左 |
|
||
|
||
### 1.3 适用场景
|
||
|
||
依据本册源文,RBD 的适用场景可归纳为:
|
||
|
||
| 场景 | 依据(源文出处) |
|
||
|---|---|
|
||
| 虚拟机/云主机系统盘与数据盘(OpenStack Nova/Cinder/Glance、CloudStack Primary Storage) | `rbd-openstack.rst`、`rbd-cloudstack.rst` |
|
||
| 容器持久化卷(Kubernetes PVC/PV、Nomad CSI volume) | `rbd-kubernetes.rst`、`rbd-nomad.rst` |
|
||
| VDI(大量 VM 克隆自同一 base image,配合只读父镜像缓存) | `rbd-persistent-read-only-cache.rst` |
|
||
| 数据库/低延迟写(配合 PWL 持久写日志缓存,PMEM/SSD) | `rbd-persistent-write-log-cache.rst` |
|
||
| 需要静态加密的合规场景(LUKS1/LUKS2) | `rbd-encryption.rst` |
|
||
| 跨机房灾备(单向/双向镜像) | `rbd-mirroring.rst` |
|
||
| 无 Ceph 客户端的操作系统(Windows / VMware ESXi / 老 Linux) | `rbd-windows.rst`、`iscsi-*`、`nvmeof-*` |
|
||
| 异构数据导入(raw / qcow / HTTP / S3 / NBD → RBD) | `rbd-live-migration.rst` |
|
||
| 存储池/布局在线重整(换 pool、换 image format、换 layout) | `rbd-live-migration.rst` |
|
||
| 工作负载录制与回放(性能回归测试) | `rbd-replay.rst` |
|
||
|
||
> 引自:[Ceph Block Device](https://docs.ceph.com/en/tentacle/rbd/)
|
||
|
||
---
|
||
|
||
## 二、核心概念
|
||
|
||
### 2.1 image(镜像/卷)
|
||
|
||
一个 RBD image 就是一个块设备:对客户端表现为一段可按 512B 块寻址的字节序列,在集群侧则被切分为多个 RADOS 对象。
|
||
|
||
- 创建:`rbd create --size {megabytes} {pool-name}/{image-name}`
|
||
- image 必须先有一个 pool,且该 pool 需先执行 `rbd pool init`。
|
||
- 默认 pool 名为 `rbd`(`rbd_default_pool`,默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`:`rbd`)。
|
||
|
||
官方还给出一条命名注意事项:除了 `{pool}/{image}`,`userid/<uuid>` 也是一种可能的 RBD image 命名方式,这类命名至少会造成混淆。
|
||
|
||
### 2.2 条带化(striping)
|
||
|
||
块设备 image 的数据被**条带化(striped)分布到多个 OSD 上**。这带来两点直接收益:
|
||
|
||
- 大 image 的性能优于独立服务器上的单块盘(`rbd-kubernetes.rst`、`rbd-openstack.rst` 均明确:large volumes/images 可以比 standalone server 上的本地盘性能更好);
|
||
- 顺序读写负载通过并行化获得吞吐提升(striping v2 feature 描述:*Striping helps with parallelism for sequential read/write workloads*)。
|
||
|
||
相关配置项(`src/common/options/rbd.yaml.in @ v20.2.4`):
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 |
|
||
|---|---|---|---|
|
||
| `rbd_default_order` | uint | `22` | 新建 image 的 object size 的幂次:`default_object_size = 2 ^ rbd_default_order`,取值 12–25(即 4KiB–32MiB),默认 2^22 = 4MiB |
|
||
| `rbd_default_stripe_count` | uint | `0` | 新建 image 的默认 stripe count |
|
||
| `rbd_default_stripe_unit` | size | `0` | 新建 image 的默认 stripe width |
|
||
|
||
(上表默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`)
|
||
|
||
> 💡 补充:源文未给出 `rbd_default_stripe_count = 0` / `rbd_default_stripe_unit = 0` 的具体语义展开(通常理解为沿用 object size / 不启用 fancy striping),此处不下结论。
|
||
|
||
### 2.3 精简配置(thin provisioned)
|
||
|
||
Ceph Block Device images 是 thin provisioned 的:**在真正写入数据之前不占用任何物理存储**,但有一个由 `--size` 设置的最大容量上限。
|
||
|
||
配套语义:
|
||
|
||
- `object-map` feature 的描述明确块设备是 *sparse* 的(只存实际写过的数据),object map 用来追踪哪些 object 真实存在;
|
||
- 删除快照后容量不会立刻释放:OSD 异步删除数据,该过程叫 **snaptrim**,在 `ceph status` 输出中以 "snaptrim" 显示。
|
||
|
||
### 2.4 快照(snapshot)
|
||
|
||
快照是 image 在某一时间点的**只读逻辑副本(read-only logical copy)**,即一个 checkpoint。
|
||
|
||
**关键限制(官方 note)**:RBD 不感知 image 内的文件系统,因此快照**仅仅是 crash-consistent**,除非在挂载/附加的操作系统内部做了协调。官方建议:
|
||
|
||
- 打快照前 **pause 或 stop I/O**;
|
||
- 若卷内有文件系统,文件系统应处于内部一致状态;未做 write quiescing 就拿的快照,重新挂载前可能需要 `fsck`;
|
||
- 可以用 `fsfreeze` 命令 quiesce I/O(详见 `fsfreeze(8)` man page);
|
||
- 对虚拟机,可以用 `qemu-guest-agent` 在打快照时自动冻结文件系统。
|
||
|
||
### 2.5 写时复制克隆(copy-on-write clone / layering)
|
||
|
||
Ceph 支持从一个块设备快照创建**多个 COW 克隆**。快照是只读的,克隆一个只读对象在语义上更简单,因此可以非常快速地创建克隆。
|
||
|
||
- 每个子 image(child)保存一个指向父快照(parent)的引用,从而可以打开父快照并读取它;
|
||
- 克隆引用中包含 **pool ID、image ID、snapshot ID**;由于包含 pool ID,**可以跨 pool 克隆**;
|
||
- **只有 "RBD format 2" image 支持克隆**(即创建时未指定 `--image-format 1`);Linux kernel client 从 **3.10** 开始支持克隆 image。
|
||
|
||
### 2.6 exclusive lock
|
||
|
||
见第六章。一句话概括:防止多个进程以不协调的方式访问同一个 RBD image;在虚拟化中防止 VM 互相覆盖写入,在 RBD mirroring 中是 journaling 的前置条件,也是 snapshot 模式快速生成增量 diff 的基础。
|
||
|
||
### 2.7 object map
|
||
|
||
- 依赖 `exclusive-lock`;
|
||
- 块设备是精简配置的(sparse),object map 用于追踪**哪些 object 真正存在(有数据)**;
|
||
- 启用后能加速:克隆、导入/导出稀疏 image、删除操作。
|
||
|
||
### 2.8 fast-diff
|
||
|
||
- 依赖 `object-map` 与 `exclusive-lock`;
|
||
- 在 object map 上增加一个属性,使**生成两个快照之间的 diff 快得多**,计算快照/卷的实际数据用量(`rbd du`)也快得多。
|
||
|
||
### 2.9 deep flatten
|
||
|
||
- 使 `rbd flatten` 能作用于 image 的**所有快照**,而不仅仅是 image 本身;
|
||
- 没有它时,image 的快照仍依赖 parent,必须先删除快照才能删除 parent;
|
||
- deep-flatten 让 parent 独立于其克隆(即使克隆有快照),代价是**额外占用 OSD 空间**。
|
||
|
||
### 2.10 image features 全表
|
||
|
||
RBD 的高级特性可在创建 image 时通过命令行指定,或通过 `rbd_default_features = <numeric values sum>` 或 `rbd_default_features = <comma-delimited list of CLI values>` 配置默认值。
|
||
|
||
| Feature | 内部值 | CLI 值 | 引入版本 | KRBD 支持 | 默认 | 说明 |
|
||
|---|---|---|---|---|---|---|
|
||
| `Layering` | 1 | `layering` | v0.52 (Bobtail) | since v3.10 | **yes** | 启用克隆能力 |
|
||
| `Striping v2` | 2 | `striping` | v0.55 (Bobtail) | since v3.10(仅 default striping;"fancy" striping 自 v4.17) | **yes** | 将数据散布到多个 object,提升顺序读写并行度 |
|
||
| `Exclusive locking` | 4 | `exclusive-lock` | v0.92 (Hammer) | since v4.9 | **yes** | 写前需先获取锁;仅在任意时刻只有单个客户端访问 image 时才应启用 |
|
||
| `Object map` | 8 | `object-map` | v0.93 (Hammer) | since v5.3 | **yes** | 依赖 exclusive lock;追踪真实存在的 object,加速克隆/导入导出/删除 |
|
||
| `Fast-diff` | 16 | `fast-diff` | v9.0.1 (Infernalis) | since v5.3 | **yes** | 依赖 object map + exclusive lock;加速快照间 diff 与 `rbd du` |
|
||
| `Deep-flatten` | 32 | `deep-flatten` | v9.0.2 (Infernalis) | since v5.1 | **yes** | 让 `rbd flatten` 作用于所有快照,使 parent 独立于克隆 |
|
||
| `Journaling` | 64 | `journaling` | v10.0.1 (Jewel) | **no** | **no** | 依赖 exclusive lock;按发生顺序记录所有修改,供 RBD mirroring 复制 crash-consistent image。**最好只让 `rbd-mirror` 按需管理**,长期开启会显著增加 OSD 空间占用 |
|
||
| `Data pool` | 128 | (无 CLI 值) | v11.1.0 (Kraken) | since v4.11 | **no** | 在纠删码 pool 上,image 数据块对象需要与 image 元数据分开存放 |
|
||
| `Operations` | 256 | (无 CLI 值) | v13.0.2 (Mimic) | since v4.16 | 文档未明确 | 用于限制旧客户端对 image 执行某些维护操作(如 clone、snap create) |
|
||
| `Migrating` | 512 | (无 CLI 值) | v14.0.1 (Nautilus) | no | 文档未明确 | image 处于迁移状态时,限制旧客户端打开它 |
|
||
| `Non-primary` | 1024 | (无 CLI 值) | v15.2.0 (Octopus) | no | 文档未明确 | 用于限制对 snapshot-based mirroring 中 non-primary image 的修改 |
|
||
|
||
(`rbd_default_features` 的实际默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`:`layering,exclusive-lock,object-map,fast-diff,deep-flatten`,即 1+4+8+16+32 = **61**)
|
||
|
||
#### 逐个 feature 的启用与关闭后果
|
||
|
||
**`layering`**
|
||
- 启用:可以创建 COW 克隆。
|
||
- 关闭:无法从快照克隆;`rbd clone` 不可用。
|
||
- 命令:`rbd feature enable|disable {pool}/{image} layering`
|
||
|
||
**`striping`(striping v2)**
|
||
- 启用:数据跨多个 object 条带化,顺序读写并行度提升。
|
||
- 关闭:image 按单一 object 序列布局,顺序大 IO 的并行度下降。
|
||
- 注意:krbd 从 v3.10 起只支持 default striping,"fancy" striping 需 v4.17+。**若 kernel < 4.17 且使用了 fancy striping,krbd 将无法映射。**
|
||
|
||
**`exclusive-lock`**
|
||
- 启用(默认):写前需获取锁;`object-map`、`fast-diff`、`journaling`、PWL cache 均依赖它。
|
||
- 关闭:上述依赖特性会被连带影响;官方明确 *Disabling the `exclusive-lock` feature will negatively affect the performance of some operations*。
|
||
- 注意:`exclusive-lock` **不阻止**两个及以上并发客户端打开同一 image 并轮流写入——它们的写只是被自动协作式地线性化(见第六章)。
|
||
- 与 RBD advisory lock(`rbd lock add` / `rbd lock rm`)**不兼容**。
|
||
|
||
**`object-map`**
|
||
- 启用:加速克隆、稀疏 image 的导入导出、删除。
|
||
- 关闭:上述操作需要扫描/遍历更多对象,变慢;`fast-diff` 也无法启用(依赖链断裂)。
|
||
|
||
**`fast-diff`**
|
||
- 启用:快照间 diff 生成快;`rbd du` 快。
|
||
- 关闭:需要全量扫描 image 才能生成 diff,导致 **snapshot-based mirroring 的增量同步显著变慢**、`rbd du` 变慢。
|
||
|
||
**`deep-flatten`**
|
||
- 启用:`rbd flatten` 覆盖所有快照,parent 可独立于克隆被删除。
|
||
- 关闭:image 的快照仍依赖 parent,必须先删快照才能删 parent;代价是省下 OSD 空间。
|
||
|
||
**`journaling`**
|
||
- 启用:journal-based mirroring 的前提;每次写先落 journal 再改 image,**写延迟几乎翻倍**(因为一次写变成两次写)。
|
||
- 关闭:无法做 journal-based mirroring;长期开启会显著消耗 OSD 空间,故官方建议只让 `rbd-mirror` 按需开关。
|
||
- **krbd 不支持**(KRBD support: no)。
|
||
- 依赖 `exclusive-lock`;若 `exclusive-lock` 未启用,应先启用它。
|
||
|
||
**`data-pool`**
|
||
- 启用:纠删码 pool 上,image 数据块对象存放到独立的数据 pool,元数据留在原 pool。
|
||
- 关闭/不适用:副本池无需此特性。
|
||
- 在 mirroring 中,目标集群选 data pool 的规则见第十章「Data Pools」。
|
||
|
||
**`operations` / `migrating` / `non-primary`**
|
||
- 这三个是"**限制旧客户端**"型的内部特性,官方未给出 CLI 值;日常运维不需要手工开关,由 `rbd-mirror` 与 live-migration 机制自动管理。
|
||
|
||
> 引自:[Config Settings](https://docs.ceph.com/en/tentacle/rbd/rbd-config-ref/)
|
||
|
||
---
|
||
|
||
## 三、基本操作(rados-rbd-cmds)
|
||
|
||
`rbd` 命令可以创建、列出、查看、删除块设备 image,也可以克隆 image、创建快照、回滚 image 到快照、查看快照等。
|
||
|
||
> 引自:[Basic Block Device Commands](https://docs.ceph.com/en/tentacle/rbd/rados-rbd-cmds/)
|
||
|
||
### 3.1 创建 Block Device Pool
|
||
|
||
```bash
|
||
# 1) 用 ceph 工具创建 pool(略,参见 Storage Pools 文档)
|
||
# 2) 用 rbd 工具初始化该 pool 供 RBD 使用
|
||
rbd pool init <pool-name>
|
||
```
|
||
|
||
> 注意:如果命令中未指定 pool 名,`rbd` 工具假定默认 pool 名为 `rbd`。
|
||
|
||
### 3.2 创建 Block Device User
|
||
|
||
除非另行指定,`rbd` 命令使用 Ceph user ID `admin` 访问集群,而 `admin` 拥有集群的完全管理权限。**官方建议**:使用一个权限更小的 Ceph user ID(称为 "block device user" 或 "Ceph user")。
|
||
|
||
```bash
|
||
ceph auth get-or-create client.{ID} mon 'profile rbd' osd 'profile {profile name} [pool={pool-name}][, profile ...]' mgr 'profile rbd [pool={pool-name}]'
|
||
```
|
||
|
||
示例:创建名为 `qemu` 的 Ceph user ID,对 pool `vms` 读写、对 pool `images` 只读:
|
||
|
||
```bash
|
||
ceph auth get-or-create client.qemu mon 'profile rbd' osd 'profile rbd pool=vms, profile rbd-read-only pool=images' mgr 'profile rbd pool=images'
|
||
```
|
||
|
||
`ceph auth get-or-create` 的输出即该 user ID 的 keyring,可写入 `/etc/ceph/ceph.client.{ID}.keyring`。
|
||
|
||
> 注意:使用 `rbd` 命令时通过 `--id {id}` 指定 Ceph user ID,该参数可选。
|
||
|
||
### 3.3 创建 image
|
||
|
||
```bash
|
||
rbd create --size {megabytes} {pool-name}/{image-name}
|
||
```
|
||
|
||
示例:在 `swimmingpool` pool 中创建 1GB 的 image `bar`:
|
||
|
||
```bash
|
||
rbd create --size 1024 swimmingpool/bar
|
||
```
|
||
|
||
不指定 pool 则落在默认 pool `rbd`:
|
||
|
||
```bash
|
||
rbd create --size 1024 foo
|
||
```
|
||
|
||
> 注意:必须先创建 pool,才能把它指定为 image 的存放位置。
|
||
|
||
### 3.4 列出 image
|
||
|
||
```bash
|
||
rbd ls # 列出默认 pool rbd
|
||
rbd ls {poolname} # 列出指定 pool
|
||
rbd ls swimmingpool
|
||
```
|
||
|
||
列出"延迟删除(deferred delete)"的 image:
|
||
|
||
```bash
|
||
rbd trash ls
|
||
rbd trash ls {poolname}
|
||
rbd trash ls swimmingpool
|
||
```
|
||
|
||
### 3.5 查看 image 信息
|
||
|
||
```bash
|
||
rbd info {image-name}
|
||
rbd info foo
|
||
|
||
rbd info {pool-name}/{image-name}
|
||
rbd info swimmingpool/bar
|
||
```
|
||
|
||
> 注意:官方文档提示存在其他可能的命名约定并可能与此处冲突,例如 `userid/<uuid>` 也可能是某个 RBD image 的名字,至少会造成混淆。
|
||
|
||
### 3.6 调整 image 大小
|
||
|
||
image 是精简配置的,但有由 `--size` 设定的最大容量。增大(或减小):
|
||
|
||
```bash
|
||
# 增大到 2048 MB
|
||
rbd resize --size 2048 foo
|
||
|
||
# 减小到 2048 MB,必须显式加 --allow-shrink
|
||
rbd resize --size 2048 foo --allow-shrink
|
||
```
|
||
|
||
### 3.7 删除 image
|
||
|
||
```bash
|
||
rbd rm {image-name}
|
||
rbd rm foo
|
||
|
||
rbd rm {pool-name}/{image-name}
|
||
rbd rm swimmingpool/bar
|
||
```
|
||
|
||
### 3.8 延迟删除(trash)与恢复
|
||
|
||
```bash
|
||
# 移动到 trash(延迟删除)
|
||
rbd trash mv {pool-name}/{image-name}
|
||
rbd trash mv swimmingpool/bar
|
||
|
||
# 从 trash 中彻底删除(注意这里用 image-id)
|
||
rbd trash rm {pool-name}/{image-id}
|
||
rbd trash rm swimmingpool/2bf4474b0dc51
|
||
|
||
# 恢复(默认 pool)
|
||
rbd trash restore {image-id}
|
||
rbd trash restore 2bf4474b0dc51
|
||
|
||
# 恢复(指定 pool)
|
||
rbd trash restore {pool-name}/{image-id}
|
||
rbd trash restore swimmingpool/2bf4474b0dc51
|
||
|
||
# 恢复的同时重命名
|
||
rbd trash restore swimmingpool/2bf4474b0dc51 --image new-name
|
||
```
|
||
|
||
**trash 相关规则(官方 note)**:
|
||
|
||
- 即使 image 有快照、或正被克隆使用,也**可以**把它移入 trash;但在这些条件下**不能**从 trash 中删除它;
|
||
- 可以用 `--expires-at` 设置延迟时间(默认为 `now`)。延迟时间未到时不能删除,除非使用 `--force`。
|
||
|
||
相关配置项(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`):
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 |
|
||
|---|---|---|---|
|
||
| `rbd_move_to_trash_on_remove` | bool | `false` | 删除 image 时自动移入 trash |
|
||
| `rbd_move_to_trash_on_remove_expire_seconds` | uint | `0` | 已删除 image 在 trash 中的默认保护秒数 |
|
||
| `rbd_move_parent_to_trash_on_remove` | bool | `false` | 删除时把带有 clone format v2 子 image 的 parent 也移入 trash |
|
||
|
||
### 3.9 cephx 认证下的 rbd 用法
|
||
|
||
启用 cephx(默认启用)时,必须指定用户名或 ID,以及包含对应 key 的 keyring 路径:
|
||
|
||
```bash
|
||
rbd --id {user-ID} --keyring /path/to/secret [commands]
|
||
rbd --name {username} --keyring /path/to/secret [commands]
|
||
|
||
# 示例
|
||
rbd --id admin --keyring /etc/ceph/ceph.keyring [commands]
|
||
rbd --name client.admin --keyring /etc/ceph/ceph.keyring [commands]
|
||
```
|
||
|
||
> Tip:可以把 user 和 secret 加到 `CEPH_ARGS` 环境变量中,避免每次重复输入。
|
||
|
||
> 引自:[Snapshots](https://docs.ceph.com/en/tentacle/rbd/rbd-snapshot/)(Cephx Notes 段)
|
||
|
||
---
|
||
|
||
## 四、内核模块与客户端(krbd)
|
||
|
||
> 引自:[Kernel Module Operations](https://docs.ceph.com/en/tentacle/rbd/rbd-ko/)
|
||
|
||
### 4.1 列出 image
|
||
|
||
挂载块设备 image 之前,先列出 image:
|
||
|
||
```bash
|
||
rbd list
|
||
```
|
||
|
||
### 4.2 map(映射)
|
||
|
||
使用 `rbd` 把 image 名映射到内核模块。必须指定 image 名、pool 名和用户名。如果 RBD 内核模块尚未加载,`rbd` 会代为加载:
|
||
|
||
```bash
|
||
sudo rbd device map {pool-name}/{image-name} --id {user-name}
|
||
sudo rbd device map rbd/myimage --id admin
|
||
```
|
||
|
||
启用 cephx 认证时还必须指定 secret,可以来自 keyring 或存放 secret 的文件:
|
||
|
||
```bash
|
||
sudo rbd device map rbd/myimage --id admin --keyring /path/to/keyring
|
||
sudo rbd device map rbd/myimage --id admin --keyfile /path/to/file
|
||
```
|
||
|
||
### 4.3 查看已映射设备
|
||
|
||
```bash
|
||
rbd device list
|
||
```
|
||
|
||
### 4.4 unmap(取消映射)
|
||
|
||
设备名按约定与块设备 image 名相同:
|
||
|
||
```bash
|
||
sudo rbd device unmap /dev/rbd/{poolname}/{imagename}
|
||
sudo rbd device unmap /dev/rbd/rbd/foo
|
||
```
|
||
|
||
### 4.5 内核版本要求
|
||
|
||
> ⚠️ **文档未明确**:`rbd-ko.rst` 页面**没有**给出 krbd 的通用最低内核版本要求。本册能确认的内核版本信息只有 image feature 表中的 KRBD 支持版本,汇总如下(引自 `rbd-config-ref.rst`):
|
||
|
||
| 能力 / Feature | 所需最低内核版本 |
|
||
|---|---|
|
||
| 支持克隆 image(clone) | v3.10 |
|
||
| `layering` | v3.10 |
|
||
| `striping`(default striping) | v3.10 |
|
||
| `striping`(fancy striping) | v4.17 |
|
||
| `exclusive-lock` | v4.9 |
|
||
| `data-pool` | v4.11 |
|
||
| `operations` | v4.16 |
|
||
| `deep-flatten` | v5.1 |
|
||
| `object-map` | v5.3 |
|
||
| `fast-diff` | v5.3 |
|
||
| `journaling` | **不支持** |
|
||
| `migrating` | 不支持 |
|
||
| `non-primary` | 不支持 |
|
||
|
||
### 4.6 已知限制(krbd)
|
||
|
||
| 限制 | 出处 |
|
||
|---|---|
|
||
| **不支持** image 级加密(LUKS1/LUKS2) | `rbd-encryption.rst` |
|
||
| **不支持** live-migration | `rbd-live-migration.rst` |
|
||
| **不支持** `journaling` feature | `rbd-config-ref.rst` |
|
||
| 不能在所有 Ceph CRUSH tunables / RBD image features 上都受支持(`ceph-csi` 默认使用 RBD 内核模块,因此这是一条对 Kubernetes/Nomad 也生效的限制) | `rbd-kubernetes.rst`、`rbd-nomad.rst` |
|
||
| 内核模块可以使用 Linux page cache(这是优势,也是与 librbd 行为差异的来源) | `index.rst` |
|
||
| Windows 上没有 krbd,改用 `rbd-wnbd`(WNBD 驱动),见第十二章 | `rbd-windows.rst` |
|
||
|
||
相关配置项:
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 |
|
||
|---|---|---|---|
|
||
| `rbd_default_map_options` | str | **文档未明确**(`rbd.yaml.in` 中无 `default:` 字段) | 默认 krbd map options |
|
||
|
||
(上表取自 `src/common/options/rbd.yaml.in @ v20.2.4`)
|
||
|
||
---
|
||
|
||
## 五、快照与克隆(rbd-snapshot)
|
||
|
||
> 引自:[Snapshots](https://docs.ceph.com/en/tentacle/rbd/rbd-snapshot/)
|
||
|
||
### 5.1 快照基础操作
|
||
|
||
| 操作 | 命令 | 示例 |
|
||
|---|---|---|
|
||
| 创建快照 | `rbd snap create {pool-name}/{image-name}@{snap-name}` | `rbd snap create rbd/foo@snapname` |
|
||
| 列出快照 | `rbd snap ls {pool-name}/{image-name}` | `rbd snap ls rbd/foo` |
|
||
| 回滚快照 | `rbd snap rollback {pool-name}/{image-name}@{snap-name}` | `rbd snap rollback rbd/foo@snapname` |
|
||
| 删除快照 | `rbd snap rm {pool-name}/{image-name}@{snap-name}` | `rbd snap rm rbd/foo@snapname` |
|
||
| 清除全部快照 | `rbd snap purge {pool-name}/{image-name}` | `rbd snap purge rbd/foo` |
|
||
| 保护快照 | `rbd snap protect {pool-name}/{image-name}@{snapshot-name}` | `rbd snap protect rbd/foo@snapname` |
|
||
| 取消保护 | `rbd snap unprotect {pool-name}/{image-name}@{snapshot-name}` | `rbd snap unprotect rbd/foo@snapname` |
|
||
| 克隆快照 | `rbd clone {pool-name}/{parent-image}@{snap-name} {pool-name}/{child-image-name}` | `rbd clone rbd/foo@snapname rbd/bar` |
|
||
| 列出快照的子 image | `rbd children {pool-name}/{image-name}@{snapshot-name}` | `rbd children rbd/foo@snapname` |
|
||
| flatten 克隆 | `rbd flatten {pool-name}/{image-name}` | `rbd flatten rbd/bar` |
|
||
|
||
### 5.2 回滚 vs 克隆(性能提示)
|
||
|
||
> 官方 note:回滚 image 到快照意味着用快照数据**覆盖** image 的当前版本,**执行时间随 image 大小增长**。因此**从快照克隆比回滚到快照更快**,官方推荐用"克隆"作为回到某个已有状态的首选方法。
|
||
|
||
### 5.3 删除快照不会立刻释放空间
|
||
|
||
Ceph OSD 异步删除数据,所以删除快照不会立刻释放底层 OSD 容量。这个过程叫 **snaptrim**,在 `ceph status` 输出中就显示为该名称。
|
||
|
||
### 5.4 Layering 原理
|
||
|
||
Ceph 支持从一个块设备快照创建**多个写时复制(COW)克隆**。快照是只读的,克隆一个只读对象在语义上更简单,因此可以非常快速地创建克隆。
|
||
|
||
```text
|
||
+-------------+ +-------------+
|
||
| {s} c999 | | {s} |
|
||
| Snapshot | Child refers | COW Clone |
|
||
| of Image |<------------*| of Snapshot |
|
||
| | to Parent | |
|
||
| (read only) | | (writable) |
|
||
+-------------+ +-------------+
|
||
|
||
Parent Child
|
||
```
|
||
|
||
- "parent" = Ceph 块设备快照;"child" = 从该快照克隆出来的 image;
|
||
- 每个克隆 image(child)保存一个指向父快照的引用,使其可以打开并读取父快照;
|
||
- 克隆的引用包含 **pool ID、image ID、snapshot ID**。因为包含 pool ID,**可以从一个 pool 的快照克隆到另一个 pool 的 image**;
|
||
- COW 克隆的行为与其他任何 Ceph 块设备 image 完全一致:可以读、写、克隆、resize,没有任何特殊限制;
|
||
- 但 COW 克隆**依赖**该快照,因此克隆前**必须保护(protect)快照**;
|
||
- **只有 "RBD format 2" image 支持克隆**(创建时未指定 `--image-format 1`);Linux kernel client 从 **3.10** 起支持克隆 image。
|
||
|
||
### 5.5 使用 layering 的标准流程
|
||
|
||
```text
|
||
+----------------------------+ +-----------------------------+
|
||
| Create Block Device Image |------->| Create a Snapshot |
|
||
+----------------------------+ +-----------------------------+
|
||
|
|
||
+--------------------------------+
|
||
v
|
||
+----------------------------+ +-----------------------------+
|
||
| Protect the Snapshot |------->| Clone the Snapshot |
|
||
+----------------------------+ +-----------------------------+
|
||
```
|
||
|
||
四种典型用法(官方原文列举):
|
||
|
||
1. **Image Template(镜像模板)**:创建一个基础 image 并打快照作为克隆模板。例如为某个 Linux 发行版(如 Ubuntu 22.04)创建 image 并做快照;偶尔更新 image 并创建新快照(`sudo apt-get update` / `upgrade` / `dist-upgrade` 后跟 `rbd snap create`);随着 image 成熟,可以克隆其中任意一个快照。
|
||
2. **Extended Template(扩展模板)**:在模板 image 之上继续扩展,安装数据库、CMS、分析系统等软件,然后对扩展后的 image 打快照,并像基础 image 一样持续更新。
|
||
3. **Template Pool(模板池)**:建一个 pool 存放 (1) 模板基础 image 和 (2) 它们的快照,然后只给用户**只读权限**,这样用户可以克隆快照,但无法在该 pool 内写入或执行。
|
||
4. **Image Migration/Recovery(迁移/恢复)**:用 layering 把数据从一个 pool 迁移或恢复到另一个 pool。
|
||
|
||
### 5.6 保护与取消保护
|
||
|
||
```bash
|
||
rbd snap protect rbd/foo@snapname # 保护后该快照无法被删除
|
||
rbd snap unprotect rbd/foo@snapname # 删除快照前必须先取消保护
|
||
```
|
||
|
||
**规则**:
|
||
|
||
- 克隆会访问父快照;如果用户误删父快照,所有克隆都会损坏。为防止数据丢失,克隆前**必须**保护快照;
|
||
- **受保护的快照无法删除**;
|
||
- 删除快照前必须先 `unprotect`;
|
||
- 如果有克隆引用了该快照,则**无法 unprotect**:必须先 flatten 或删除该快照的每一个克隆。
|
||
|
||
### 5.7 flatten
|
||
|
||
```bash
|
||
rbd flatten {pool-name}/{image-name}
|
||
rbd flatten rbd/bar
|
||
```
|
||
|
||
- 克隆 image 保留对父快照的引用;移除该引用时,就相当于把快照中的数据拷贝到克隆中,从而"展平(flatten)"该克隆;
|
||
- **flatten 耗时随快照大小增长**;
|
||
- 要删除快照,必须先 flatten(或删除)其子 image;
|
||
- **flatten 后的 image 包含快照中的全部数据,因此比分层克隆占用更多存储空间**。
|
||
|
||
### 5.8 clone format
|
||
|
||
配置项 `rbd_default_clone_format`(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`):
|
||
|
||
| 配置项 | 类型 | 默认值 | 枚举值 | 含义 |
|
||
|---|---|---|---|---|
|
||
| `rbd_default_clone_format` | str | `auto` | `1` / `2` / `auto` | 处理克隆的内部格式。`1`:必须挂到受保护快照上,克隆删除或 flatten 前不能删除该快照;`2`:克隆可挂到任意快照,允许删除正在使用的父快照,但要求 Mimic 或更新的客户端;`auto`:若集群要求 Mimic 或更新客户端,则使用 v2 格式 |
|
||
|
||
(`flags: runtime`,可运行时生效)
|
||
|
||
### 5.9 快照数量与性能影响
|
||
|
||
> ⚠️ **文档未明确**:`rbd-snapshot.rst` **没有**给出"单个 image 建议的快照数量上限"或"快照数量对性能影响的量化数据"。
|
||
|
||
本册能从源文中确认的相关事实只有:
|
||
|
||
- 删除快照不会立即释放空间,靠异步 **snaptrim** 回收(`rbd-snapshot.rst`);
|
||
- 快照过多时,`fast-diff` / `object-map` 会显著影响 diff 生成与 `rbd du` 的速度(`rbd-config-ref.rst` 的 feature 描述);
|
||
- 快照数量与 RADOS 侧 `snaptrim` 的关系由 `mon_max_snap_prune_per_epoch` 控制(默认值取自 `src/common/options/global.yaml.in @ v20.2.4`:`100`,含义为单个 OSDMap epoch 内处理的已剪枝快照最大数量)——此项属于 RADOS 侧参数,不在 `doc/rbd/` 源文范围内。
|
||
|
||
> 💡 补充:基于上述事实可以给出的实践建议是——**保留 `object-map` + `fast-diff`,并控制长生命周期快照链的深度**;但"具体保留多少个"官方未给数字,本册不臆造。
|
||
|
||
---
|
||
|
||
## 六、exclusive lock 与 object map
|
||
|
||
> 引自:[RBD Exclusive Locks](https://docs.ceph.com/en/tentacle/rbd/rbd-exclusive-locks/)
|
||
|
||
### 6.1 什么是 exclusive lock
|
||
|
||
Exclusive locks 是一种机制,用于**防止多个进程以不协调的方式访问同一个 RBD**。它被大量用于:
|
||
|
||
- **虚拟化**:防止多个 VM 互相覆盖(clobber)对方的写入;
|
||
- **RBD mirroring**:在 journal-based mirroring 中,它是 journaling 的**前置条件**;在 snapshot-based mirroring 中,它是快速生成增量 diff 的基础。
|
||
|
||
`exclusive-lock` feature **在新创建的 image 上默认启用**。该默认可通过配置项 `rbd_default_features`,或 `rbd create` 的 `--image-feature` / `--image-shared` 选项覆盖。
|
||
|
||
> 官方 note:许多 image feature(包括 `object-map` 和 `fast-diff`)**依赖** exclusive locking。禁用 `exclusive-lock` 会对某些操作的性能产生负面影响。
|
||
|
||
### 6.2 协作式锁转移(automatic cooperative lock transitions)
|
||
|
||
为了维持多客户端访问,`exclusive-lock` 实现了客户端之间的**自动协作式锁转移**,保证任意时刻只有一个客户端能写入 RBD image,从而保护 image 的内部结构(object map、journal、PWL cache)不被并发修改。
|
||
|
||
对用户基本透明,行为如下:
|
||
|
||
1. 当某个客户端(`librbd` 进程;对 `krbd` 来说是客户端节点的内核)需要写入一个启用了 exclusive locking 的 RBD image 时,它首先获取该 image 的 exclusive lock。如果该锁已被其他客户端持有,则**请求**那个客户端释放锁。
|
||
2. 持有锁的客户端收到释放请求后,**停止处理写操作、刷写其缓存、然后释放锁**。
|
||
3. 持有锁的客户端优雅终止时,锁也被优雅释放。
|
||
4. 一次优雅释放(无论是被请求还是因客户端终止)使得另一个后续客户端可以获取锁并开始处理写入。
|
||
|
||
### 6.3 ⚠️ 关键警告:它不阻止并发写入
|
||
|
||
> 官方 warning:默认情况下,`exclusive-lock` feature **不会阻止**两个或更多并发运行的客户端打开同一个 RBD image 并**轮流**写入(无论是否在同一节点)。实际上,它们的写只是随着锁的自动来回转移被**线性化(linearized)**了。
|
||
|
||
这意味着:如果你需要真正的互斥,必须在 RBD 之上由外部机制(如集群文件系统、Pacemaker、应用层仲裁)来保证。
|
||
|
||
关闭自动锁转移的方法:获取 exclusive lock 时指定 `RBD_LOCK_MODE_EXCLUSIVE` 标志。该标志通过 `rbd device map` 命令的 **`--exclusive`** 选项暴露给用户。
|
||
|
||
> 官方 note:`exclusive-lock` feature 与 **RBD advisory locks**(`rbd lock add` 和 `rbd lock rm` 命令)**不兼容**。
|
||
|
||
### 6.4 Blocklisting(存储级 fencing)
|
||
|
||
有时先前持有 exclusive lock 的客户端不会优雅终止,而是突然死掉:进程收到 `KILL`/`ABRT` 信号、节点硬重启或掉电。此时锁永远不会被优雅释放,任何新客户端要写入该 image 就必须**打破(break)**之前持有的锁。
|
||
|
||
但另一种情形是:进程(或内核线程)只是**挂起**或**临时**失去到 Ceph 集群的网络连接。这时打破锁可能是灾难性的——挂起的进程或网络问题可能自行恢复,原进程就会与新起的进程竞争,从而以不协调、破坏性的方式访问 RBD 数据。
|
||
|
||
因此,当锁无法以标准优雅方式获取时,**接管进程不仅会打破锁,还会把先前的持锁者加入 blocklist**。这个过程在新客户端进程与 Ceph Monitor 之间协商:
|
||
|
||
1. Monitor 收到 blocklist 请求后,指示相关 OSD **不再服务**来自旧客户端进程的请求;
|
||
2. 相关的 OSD map 更新完成后,新客户端才能打破先前持有的锁;
|
||
3. 新客户端获得锁后,才能开始写入 image。
|
||
|
||
**Blocklisting 因此是一种存储级的资源 fencing。**
|
||
|
||
> 官方 note:为了让 blocklisting 生效,客户端必须拥有 **`osd blocklist` capability**。该 capability 已包含在 **`profile rbd`** capability profile 中,应当为所有使用 RBD 的 Ceph 客户端身份(client identities)普遍设置。
|
||
|
||
### 6.5 与 blocklist / lock 相关的配置项
|
||
|
||
(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`)
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_blocklist_on_break_lock` | bool | `true` | 锁被打破时是否 blocklist 对应客户端 | 保持 `true`,这是 fencing 生效的前提 |
|
||
| `rbd_blocklist_expire_seconds` | uint | `0` | blocklist 持续秒数;`0` 表示使用 OSD 默认值 | 一般保持 `0`;仅在需要缩短隔离窗口时调整 |
|
||
| `rbd_request_timed_out_seconds` | uint | `30` | 维护类请求的超时秒数 | 大集群/慢网络可适当增大 |
|
||
| `rbd_auto_exclusive_lock_until_manual_request` | bool | `true` | 在显式请求之前,自动获取/释放 exclusive lock | 保持默认 |
|
||
| `rbd_invalidate_object_map_on_timeout` | bool(dev 级) | `true` | 加载或更新超时时是否使 object map 失效 | 保持默认 |
|
||
|
||
参见:`mon_osd_blocklist_default_expire`(默认值取自 `src/common/options/mon.yaml.in @ v20.2.4`:`1_hr`,即 1 小时),是 `rbd_blocklist_expire_seconds = 0` 时实际生效的 OSD 侧默认值。
|
||
|
||
### 6.6 object map 补充要点
|
||
|
||
- 依赖 `exclusive-lock`;
|
||
- 因为块设备是 thin provisioned(sparse),只存实际写过的数据;object map 用来追踪**哪些 object 真实存在(已写入数据)**;
|
||
- 启用 object map 会加速:克隆、导入稀疏 image、导出稀疏 image、删除。
|
||
|
||
---
|
||
|
||
## 七、缓存机制
|
||
|
||
RBD 有三层不同的"缓存",容易混淆,先分清:
|
||
|
||
| 缓存 | 作用层 | 位置 | 页面 |
|
||
|---|---|---|---|
|
||
| Linux page cache | krbd(内核模块) | 客户端内核 | `index.rst` 提及 |
|
||
| RBD Caching(librbd 内存缓存) | librbd | 客户端进程内存 | `rbd-config-ref.rst` |
|
||
| Shared Read-only Parent Image Cache | librbd + `ceph-immutable-object-cache` 守护进程 | 客户端本地磁盘 | `rbd-persistent-read-only-cache.rst` |
|
||
| Persistent Write Log Cache (PWL) | librbd | PMEM / SSD 持久设备 | `rbd-persistent-write-log-cache.rst` |
|
||
|
||
### 7.1 RBD Caching(librbd 内存缓存)
|
||
|
||
> 引自:[Config Settings](https://docs.ceph.com/en/tentacle/rbd/rbd-config-ref/)
|
||
|
||
用户态实现(`librbd`)无法利用 Linux page cache,因此自带内存缓存,称为 **"RBD caching"**。行为类似表现良好的硬盘缓存:当 OS 发送 barrier 或 flush 请求时,所有脏数据写入 OSD。这意味着**使用 write-back 缓存与使用一块会正确发送 flush 的、表现良好的物理硬盘同样安全**(Linux kernel >= 2.6.32)。
|
||
|
||
- 缓存使用 **LRU** 算法;在 write-back 模式下可以**合并连续请求**以获得更好的吞吐;
|
||
- librbd 缓存**默认启用**,支持三种策略:**write-around、write-back、write-through**;
|
||
|
||
| 策略 | 写返回时机 | 读是否可从缓存命中 |
|
||
|---|---|---|
|
||
| `write-around` | 立即返回(除非未写字节超过 `rbd_cache_max_dirty`) | **否**(不从缓存服务读)——因此对高性能写负载更快 |
|
||
| `write-back` | 立即返回(除非未写字节超过 `rbd_cache_max_dirty`) | 是 |
|
||
| `write-through` | **仅当数据已落到所有副本的磁盘上**才返回 | 是 |
|
||
|
||
- 在收到 flush 请求之前,缓存表现为 write-through,以确保对不发送 flush 的老操作系统也能崩溃一致;
|
||
- 如果禁用 librbd 缓存,读写直达存储集群,写仅在数据落到所有副本磁盘后返回;
|
||
- **Read-ahead(预读)**:librbd 支持 read-ahead/prefetching 以优化小的顺序读。通常由 VM 的 guest OS 处理,但 boot loader 可能发不出高效读。缓存被禁用或策略为 write-around 时,read-ahead 自动禁用。
|
||
|
||
> ⚠️ 官方 note:缓存位于客户端内存中,**每个 RBD image 各有自己的一份**。由于缓存是客户端本地的,若还有其他方访问该 image,则**没有一致性保证**。在开启缓存的 RBD 上运行 **GFS 或 OCFS 是不行的**。
|
||
|
||
RBD 的选项应设置在配置文件的 `[client]` 段或 central config store 中。
|
||
|
||
#### 缓存相关配置项逐项
|
||
|
||
(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`)
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_cache` | bool | `true` | 是否启用缓存(writeback,除非 `rbd_cache_max_dirty` 为 0) | 一般保持 `true`;需要跨客户端强一致或跑 GFS/OCFS 时关闭 |
|
||
| `rbd_cache_policy` | str | `writearound` | 处理写的缓存策略,枚举:`writethrough` / `writeback` / `writearound` | 默认 `writearound` 偏重写;需要读命中时改 `writeback` |
|
||
| `rbd_cache_writethrough_until_flush` | bool | `true` | 在收到 flush 之前以 writethrough 方式工作,确保使用方会发 flush,之后 writeback 才安全 | 保持 `true`(对老 virtio 驱动尤其重要,Linux < 2.6.32 不发 flush) |
|
||
| `rbd_cache_size` | size | `32_M` | 每个卷的 RBD 客户端缓存大小(字节) | 内存充裕可增大;必须大于 `rbd_cache_max_dirty` |
|
||
| `rbd_cache_max_dirty` | size | `24_M` | 触发 write-back 的 `dirty` 上限;为 `0` 则使用 write-through 缓存 | 约束:必须小于 `rbd_cache_size` |
|
||
| `rbd_cache_target_dirty` | size | `16_M` | 缓存开始向数据存储写数据前的 `dirty target`;不阻塞对缓存的写入 | 约束:必须小于 `rbd_cache_max_dirty` |
|
||
| `rbd_cache_max_dirty_age` | float | `1` | 脏数据在缓存中停留多少秒后开始 writeback | 低延迟场景可调小 |
|
||
| `rbd_cache_max_dirty_object` | uint | `0` | 对象级脏数据上限;`0` 表示由 `rbd_cache_size` 自动计算 | 保持 `0` |
|
||
| `rbd_cache_block_writes_upfront` | bool | `false` | 是否在 `aio_write` 调用完成前阻塞对缓存的写 | 保持 `false` |
|
||
|
||
> 💡 补充:`rbd-cache-config-settings` 是 `qemu-rbd.rst` 中对本节的锚点引用名(见第十二章 QEMU 缓存选项),官方页面上这一节的标题即为 "Cache Settings"。
|
||
|
||
#### Read-ahead 配置项逐项
|
||
|
||
(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`)
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_readahead_trigger_requests` | uint | `10` | 触发 readahead 所需的连续请求数 | 默认即可 |
|
||
| `rbd_readahead_max_bytes` | size | `512_K` | 单次 read-ahead 请求的最大大小;为 `0` 则禁用 read-ahead | 顺序读场景可增大 |
|
||
| `rbd_readahead_disable_after_bytes` | size | `50_M` | 从某个 RBD image 累计读取多少字节后禁用该 image 的 read-ahead(关闭再打开 image 会重置)。为 `0` 则 read-ahead 一直启用 | 默认 `50_M`:让 guest OS 启动后接管 read-ahead |
|
||
|
||
### 7.2 Persistent Read-only Cache(共享只读父镜像缓存)
|
||
|
||
> 引自:[RBD Persistent Read-only Cache](https://docs.ceph.com/en/tentacle/rbd/rbd-persistent-read-only-cache/)
|
||
|
||
#### 原理
|
||
|
||
**克隆的 RBD image** 通常只修改父 image 的一小部分。例如在 VDI 场景中,VM 都从同一个 base image 克隆而来,初始时只有 hostname 和 IP 地址不同。**启动过程中,所有这些 VM 都会读取同一份父 image 数据的某些部分**。如果在本地缓存父 image,就能加速该缓存主机上的读,同时**减少客户端到集群的网络流量**。
|
||
|
||
> **RBD cache 必须在 `ceph.conf` 中显式启用**(不同于 librbd 内存缓存默认开启)。`ceph-immutable-object-cache` 守护进程负责把父内容缓存到本地磁盘,后续对这些数据的读将由本地缓存服务。
|
||
|
||
> 官方 note:RBD shared read-only parent image cache 需要 **Ceph Nautilus 或更新版本**。
|
||
|
||
```text
|
||
+--------------------------------------------------------+
|
||
| QEMU |
|
||
+--------------------------------------------------------+
|
||
| librbd (cloned images) |
|
||
+-------------------+-+----------------------------------+
|
||
| librados | | ceph--immutable--object--cache |
|
||
+-------------------+ +----------------------------------+
|
||
| OSDs/Mons | | local cached parent image |
|
||
+-------------------+ +----------------------------------+
|
||
```
|
||
|
||
#### 启用
|
||
|
||
在 `ceph.conf` 的 `[client]` 段添加:
|
||
|
||
```ini
|
||
rbd parent cache enabled = true
|
||
rbd plugins = parent_cache
|
||
```
|
||
|
||
对应配置项(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`):
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 |
|
||
|---|---|---|---|
|
||
| `rbd_parent_cache_enabled` | bool | `false` | 是否启用 rbd shared read-only cache |
|
||
| `rbd_plugins` | str | **文档未明确**(`rbd.yaml.in` 中无 `default:` 字段,通常理解为空) | 逗号分隔的、要启用的 librbd 插件列表 |
|
||
|
||
#### Immutable Object Cache 守护进程
|
||
|
||
`ceph-immutable-object-cache` 守护进程负责在其本地缓存目录中缓存父 image 内容。**建议使用 SSD 作为底层存储**以获得更好性能。
|
||
|
||
三大关键组件:
|
||
|
||
1. **Domain socket based IPC**:守护进程启动时监听本地 domain socket,等待来自 librbd 客户端的连接;
|
||
2. **LRU based promotion/demotion policy**:守护进程在内存中维护每个缓存文件的命中统计;容量达到配置阈值时降级(淘汰)冷缓存;
|
||
3. **File-based caching store**:守护进程维护一个简单的基于文件的缓存存储;提升(promotion)时从 RADOS 集群取回 RADOS 对象,存放到本地缓存目录。
|
||
|
||
**交互流程**:每个克隆 RBD image 被打开时,`librbd` 尝试通过 Unix domain socket 连接缓存守护进程;连接成功后,后续每次读都与守护进程协调。未缓存的读:守护进程把该 RADOS 对象提升(promote)到本地缓存目录,下一次读该对象由缓存服务。守护进程维护简单的 LRU 统计,用于在需要时(例如缓存已满、有压力时)淘汰冷缓存文件。
|
||
|
||
守护进程位于可选的 **`ceph-immutable-object-cache`** 发行包中。
|
||
|
||
> ⚠️ 官方 important:`ceph-immutable-object-cache` 守护进程**必须具备连接 RADOS 集群的能力**。
|
||
|
||
#### 运行守护进程
|
||
|
||
守护进程应使用**唯一的 Ceph user ID**:
|
||
|
||
```bash
|
||
ceph auth get-or-create client.ceph-immutable-object-cache.{unique id} mon 'allow r' osd 'profile rbd-read-only'
|
||
```
|
||
|
||
用 systemd 管理(以 user ID 作为守护进程实例名):
|
||
|
||
```bash
|
||
systemctl enable ceph-immutable-object-cache@ceph-immutable-object-cache.{unique id}
|
||
```
|
||
|
||
也可以前台运行:
|
||
|
||
```bash
|
||
ceph-immutable-object-cache -f --log-file={log_path}
|
||
```
|
||
|
||
#### 守护进程配置项逐项
|
||
|
||
(默认值取自 `src/common/options/immutable-object-cache.yaml.in @ v20.2.4`;`rbd-persistent-read-only-cache.rst` 页面上也列出了同名默认值,两者一致)
|
||
|
||
| 配置项 | 类型 | 默认值 | 必需 | 含义 |
|
||
|---|---|---|---|---|
|
||
| `immutable_object_cache_sock` | str | `/var/run/ceph/immutable_object_cache_sock` | No | librbd 客户端与 `ceph-immutable-object-cache` 守护进程通信用的 domain socket 路径 |
|
||
| `immutable_object_cache_path` | str | `/tmp/ceph_immutable_object_cache` | No | immutable object cache 数据目录 |
|
||
| `immutable_object_cache_max_size` | size | `1G` | No | immutable cache 最大大小 |
|
||
| `immutable_object_cache_watermark` | float | `0.9` | No | 缓存高水位线,取值 (0, 1)。缓存大小达到该阈值时,守护进程开始按 LRU 统计删除冷缓存 |
|
||
| `immutable_object_cache_max_inflight_ops` | uint | `128` | No | 守护进程最大在途提升(promoting)请求数 |
|
||
| `immutable_object_cache_client_dedicated_thread_num` | uint | `2` | No | 每个 immutable object cache 客户端的专用线程数 |
|
||
|
||
> 💡 补充:后两项(`max_inflight_ops`、`client_dedicated_thread_num`)在 `rbd-persistent-read-only-cache.rst` 页面**未列出**,来自 `src/common/options/immutable-object-cache.yaml.in @ v20.2.4`。
|
||
|
||
#### QoS 配置项逐项
|
||
|
||
(默认值取自 `src/common/options/immutable-object-cache.yaml.in @ v20.2.4`)
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 |
|
||
|---|---|---|---|
|
||
| `immutable_object_cache_qos_schedule_tick_min` | millisecs | `50` | immutable object cache 的最小调度 tick(毫秒),min: 1 |
|
||
| `immutable_object_cache_qos_iops_limit` | uint | `0` | 期望的 immutable object cache 每秒 IO 操作数上限 |
|
||
| `immutable_object_cache_qos_iops_burst` | uint | `0` | 期望的 immutable object cache IO 操作突发上限 |
|
||
| `immutable_object_cache_qos_iops_burst_seconds` | secs | `1` | 期望的 immutable object cache IO 操作突发持续秒数,min: 1 |
|
||
| `immutable_object_cache_qos_bps_limit` | uint | `0` | 期望的 immutable object cache 每秒 IO 字节数上限 |
|
||
| `immutable_object_cache_qos_bps_burst` | uint | `0` | 期望的 immutable object cache IO 字节突发上限 |
|
||
| `immutable_object_cache_qos_bps_burst_seconds` | secs | `1` | 期望的 immutable object cache IO 字节突发持续秒数,min: 1 |
|
||
|
||
#### 适用场景与风险
|
||
|
||
- **适用**:VDI / 大量 VM 克隆自同一 base image、读多写少、客户端本地有 SSD、希望降低客户端到集群的网络流量。
|
||
- **风险 / 限制**:需 Nautilus+;必须显式在 `[client]` 段启用(默认 `false`);守护进程需要独立的 Ceph 用户与到集群的连接;缓存目录默认在 `/tmp`(生产环境必须改到 SSD 挂载点);只缓存**父 image 内容**,对克隆自身的新写数据无加速作用。
|
||
|
||
### 7.3 Persistent Write Log Cache(PWL)
|
||
|
||
> 引自:[RBD Persistent Write Log Cache](https://docs.ceph.com/en/tentacle/rbd/rbd-persistent-write-log-cache/)
|
||
|
||
#### 原理
|
||
|
||
PWL cache 为基于 librbd 的 RBD 客户端提供一个**持久的、容错的 write-back 缓存**。
|
||
|
||
- 采用 **log-ordered write-back** 设计,内部维护 checkpoint,使得**回刷到集群的写始终是崩溃一致的**;
|
||
- **即使客户端缓存整体丢失,磁盘 image 依然是一致的,只是数据会显得陈旧(stale)**。
|
||
|
||
缓存设备两种:
|
||
|
||
| 缓存模式 | 设备 | 说明 |
|
||
|---|---|---|
|
||
| `rwl`(replica write log) | PMEM | 目前**仅支持本地缓存**,replica(副本)功能仍在开发中 |
|
||
| `ssd` | SSD | — |
|
||
| `disabled` | — | 默认,缓存关闭 |
|
||
|
||
**两种持久化模式**:
|
||
|
||
| 模式 | 写完成时机 | 崩溃后可读性 |
|
||
|---|---|---|
|
||
| **persistent-on-write** | 写持久化到缓存设备后才完成 | 崩溃后可读 |
|
||
| **persistent-on-flush** | 不再需要调用方数据缓冲区即可完成,不保证崩溃后可读;收到 flush 请求时数据才持久化到缓存设备 | 不保证 |
|
||
|
||
**初始默认为 persistent-on-write 模式,在收到第一个 flush 请求后切换为 persistent-on-flush 模式。**
|
||
|
||
**依赖**:PWL cache **依赖 `exclusive-lock` feature**。只有在获取到 exclusive lock 之后,缓存才能被加载。
|
||
|
||
#### 启用
|
||
|
||
```ini
|
||
rbd_persistent_cache_mode = {cache-mode}
|
||
rbd_plugins = pwl_cache
|
||
```
|
||
|
||
`{cache-mode}` 取值:`rwl`、`ssd`、`disabled`。**默认缓存是禁用的。**
|
||
|
||
`rwl` 模式依赖 `libpmem` 库(PMDK 的一部分):在 x86_64 架构上应普遍可用,在 ppc64le 与 aarch64 上某些发行版也可获得,**在 s390x 架构上不可用**。
|
||
|
||
#### 配置项逐项
|
||
|
||
(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`)
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_persistent_cache_mode` | str | `disabled` | 为该卷启用持久 write-back 缓存;枚举:`disabled` / `rwl` / `ssd` | 有 PMEM 用 `rwl`;有 NVMe SSD 用 `ssd` |
|
||
| `rbd_persistent_cache_size` | uint | `1_G` | 每个 image 的持久 write-back 缓存大小;**最小 1 GB**(min: `1_G`) | 按单卷写工作集设置,不得低于 1G |
|
||
| `rbd_persistent_cache_path` | str | `/tmp` | 持久 write-back 缓存在持久内存上 DAX 启用文件系统中的位置 | 生产必须改为 PMEM/SSD 挂载点;**使用 `rwl` 模式时该目录必须启用 DAX**,否则性能下降 |
|
||
|
||
> 官方说明:上述配置可以 per-host、per-pool、per-image 等粒度设置。per-host:写到该主机 `ceph.conf` 的相应 section;per-pool / per-image:参见 `rbd config` 命令(man page `rbd(8)` 的 "commands" 部分)。
|
||
|
||
#### 缓存状态查看
|
||
|
||
PWL cache 在获取 exclusive lock 时启用,在 exclusive lock 释放时关闭。用 `rbd status` 查看:
|
||
|
||
```bash
|
||
rbd status {pool-name}/{image-name}
|
||
```
|
||
|
||
输出示例(含 present、clean、cache size、location 以及一些基础指标):
|
||
|
||
```text
|
||
$ rbd status rbd/foo
|
||
Watchers:
|
||
watcher=10.10.0.102:0/1061883624 client.25496 cookie=140338056493088
|
||
Persistent cache state:
|
||
host: sceph9
|
||
path: /mnt/nvme0/rbd-pwl.rbd.101e5824ad9a.pool
|
||
size: 1 GiB
|
||
mode: ssd
|
||
stats_timestamp: Sun Apr 10 13:26:32 2022
|
||
present: true empty: false clean: false
|
||
allocated: 509 MiB
|
||
cached: 501 MiB
|
||
dirty: 338 MiB
|
||
free: 515 MiB
|
||
hits_full: 1450 / 61%
|
||
hits_partial: 0 / 0%
|
||
misses: 924
|
||
hit_bytes: 192 MiB / 66%
|
||
miss_bytes: 97 MiB
|
||
```
|
||
|
||
#### 刷写与失效
|
||
|
||
```bash
|
||
# 刷写缓存文件到 OSD
|
||
rbd persistent-cache flush {pool-name}/{image-name}
|
||
rbd persistent-cache flush rbd/foo
|
||
|
||
# 使缓存失效(丢弃)
|
||
rbd persistent-cache invalidate {pool-name}/{image-name}
|
||
rbd persistent-cache invalidate rbd/foo
|
||
```
|
||
|
||
- 如果应用异常死亡,`rbd persistent-cache flush` 也可用来把缓存刷回 OSD;
|
||
- `invalidate` 会**移除对应 image 的缓存元数据、禁用缓存特性,并删除本地缓存文件(如果存在)**。
|
||
|
||
#### 适用场景与风险
|
||
|
||
- **适用**:librbd 客户端(QEMU/KVM、ceph-csi 用户态模式)、有本地 PMEM 或 NVMe SSD、写密集且希望降低写延迟;需要崩溃一致保证(log-ordered 设计 + checkpoint)。
|
||
- **风险 / 限制**:
|
||
- 依赖 `exclusive-lock`;锁释放时缓存关闭;
|
||
- 默认 `disabled`;
|
||
- `rbd_persistent_cache_size` 最小 1 GB;
|
||
- `rwl` 模式要求目录启用 **DAX**,否则性能下降;且 s390x 架构不可用;
|
||
- **krbd 不使用此机制**(PWL 是 librbd 插件,通过 `rbd_plugins = pwl_cache` 加载);
|
||
- 缓存丢失时 image 一致但数据**陈旧**——这是设计保证,不是无数据丢失保证;
|
||
- `rbd exclusive-locks` 文档把 PWL cache 列为受 exclusive lock 保护的 image 内部结构之一。
|
||
|
||
---
|
||
|
||
## 八、加密(rbd-encryption)
|
||
|
||
> 引自:[Image Encryption](https://docs.ceph.com/en/tentacle/rbd/rbd-encryption/)
|
||
|
||
从 **Pacific** 版本开始,image 级加密可以由 RBD 客户端内部处理:你可以设置一个密钥,用于加密某个特定的 RBD image。
|
||
|
||
> ⚠️ 官方 note:**`krbd` 内核模块目前不支持加密。**
|
||
>
|
||
> 官方 note:外部工具(如 dm-crypt、QEMU)也可用于加密 RBD image,那种用法的功能集与限制集可能与此处描述的不同。
|
||
|
||
### 8.1 Encryption Format(格式化)
|
||
|
||
- 默认情况下 RBD image **不加密**。要加密,需要把它格式化(format)为某种受支持的加密格式;
|
||
- format 操作会把**加密元数据持久化到 image 上**。元数据通常包括:加密格式与版本、密码算法与模式规范,以及用于保护加密密钥的信息;
|
||
- **加密密钥本身由用户保管的 secret(通常是 passphrase)保护,且该 secret 永不被持久化**;
|
||
- 基本的 format 操作需要指定:加密格式 + 一个 secret;
|
||
- 部分加密元数据可能作为 image 数据的一部分存储——通常在**原始 image 数据的开头写入一个加密头**。这意味着**加密后 image 的有效(effective)大小会小于原始 image 大小**(详见 Supported Formats)。
|
||
|
||
**规则(官方 note 汇总)**:
|
||
|
||
- 除非显式(重新)格式化,**加密 image 的克隆会以相同的格式与 secret 天然加密**;
|
||
- **加密 image 的克隆始终是加密的**;**不支持重新格式化为明文(plaintext)**;
|
||
- format 之前写入 image 的任何数据可能变得不可读,尽管它可能仍占用存储资源;
|
||
- **启用了 `journal` feature 的 image 不能被 RBD 客户端格式化并加密。**
|
||
|
||
### 8.2 Encryption Load(加载)
|
||
|
||
- 格式化是启用加密的必要前提;但**格式化后的 image 在所有 RBD API 看来仍是原始未加密 image**:可以用同样的 API 打开,可以读写原始未加密数据。这类原始 IO **可能破坏加密格式的完整性**(例如覆盖了位于 image 开头的加密元数据);
|
||
- 要在格式化后的 image 上安全执行加密 IO,打开 image 之后还需要执行一次额外的 **encryption load** 操作。该操作需要为该 image 本身**以及每一个被显式格式化的祖先 image** 提供加密格式与用于解锁加密密钥的 secret;
|
||
- load 成功后,**该打开 image 的所有 IO 都会被加密/解密**;对克隆 image,这也包括对其祖先 image 的 IO;
|
||
- 加密密钥由 RBD 客户端保存在**内存**中,直到 image 关闭。
|
||
|
||
**load 之后的语义变化(官方 note 汇总)**:
|
||
|
||
- 一旦加载了加密,**不能**再对已打开 image 的上下文执行其他 encryption load / format 操作;
|
||
- 获取 image size 与 parent overlap 的 API 将返回**有效** image size 与**有效** parent overlap;
|
||
- resize API 会把指定的目标大小解释为**有效** image size;
|
||
- 如果**克隆** image 被显式格式化,则 **flatten 不再是透明操作**——从父快照拷贝过来的父数据必须按照克隆 image 的格式重新加密。**如果在发起 flatten 前没有加载加密,之前在克隆 image 中可访问的父数据可能变为不可读。**
|
||
- 同理,如果克隆 image 被显式格式化,**缩容(shrink)也不再透明**(某些情况下需要从父快照拷贝数据,如克隆有快照,或缩容到未按 object size 对齐的大小)。**若在发起 shrink 前未加载加密,父数据可能变为不可读。**
|
||
- 加密 load 可以在通过 **`rbd-nbd`** 挂载 RBD image 为块设备时**自动应用**。
|
||
|
||
### 8.3 支持的格式:LUKS / LUKS2
|
||
|
||
**LUKS1 与 LUKS2 均受支持**,数据布局完全符合 LUKS 规范。因此:
|
||
|
||
- RBD 格式化的 image 可以用外部支持 LUKS 的工具(如 dm-crypt 或 QEMU)加载;
|
||
- 在 RBD 之外创建的既有 LUKS 数据,也可以通过**把原始 LUKS 数据拷贝进 image** 的方式导入,并由 RBD encryption 加载。
|
||
|
||
> 官方 note:**LUKS 格式仅在基于 Linux 的系统上受支持。**
|
||
>
|
||
> 官方 note:目前**仅支持 AES-128 与 AES-256** 加密算法;且 **`xts-plain64` 是目前唯一支持的加密模式**。
|
||
|
||
#### 格式化命令
|
||
|
||
```bash
|
||
rbd encryption format [--cipher-alg {aes-128|aes-256}] {image-spec} {luks1|luks2} {passphrase-file}
|
||
```
|
||
|
||
- format 操作会生成一个 LUKS header 并写入 image 开头;header 后附加**单个 keyslot**,其中存放一个随机生成的加密密钥,并由从 `passphrase-file` 读出的 passphrase 保护;
|
||
- 默认使用 **AES-256 + xts-plain64**(当前推荐模式,也是其他工具的常见默认);也允许选择 AES-128;
|
||
- **RBD 目前不支持添加/删除 passphrase**,但可以用 `cryptsetup` 等兼容工具在原始 RBD 数据上操作;
|
||
- > 官方 note:在旧版本中,如果 `passphrase-file` 内容以换行符结尾,该换行符会被剥离。
|
||
|
||
#### 头部大小与性能
|
||
|
||
- LUKS header 大小可变(LUKS2 中最大可达 **136MiB**),但通常**最大 16MiB**,取决于安装的 `libcryptsetup` 版本;
|
||
- 为获得最优性能,encryption format 会把 **data offset 对齐到 image 的 stripe period size**;
|
||
- 例:使用 **8MiB object size** 配置的 image,预期**最小开销 8MiB**;
|
||
- 例:使用 **4MiB object size** 且 **stripe count 为 3** 的 image,预期**最小开销 12MiB**;
|
||
- **sector(最小加密单元)**:LUKS1 固定为 512 字节;LUKS2 支持更大的 sector,为获得更好性能,默认 sector size 设为**最大 4KiB**;
|
||
- **小于一个 sector、或未对齐到 sector 起始位置的写**,会在客户端触发一条 **guarded read-modify-write 链**,带来**可观的延迟惩罚**;一批这样的未对齐写可能导致 IO 竞争,进一步恶化性能。**因此在无法保证写入是对齐的场景下,建议避免使用 RBD 加密。**
|
||
|
||
#### 映射 LUKS 格式的 image
|
||
|
||
```bash
|
||
rbd device map -t nbd -o encryption-passphrase-file={passphrase-file} {image-spec}
|
||
```
|
||
|
||
> 安全提示(官方原文):出于安全原因,encryption format 与 encryption load 操作都是 **CPU 密集型**的,可能需要几秒才能完成。对于实际 image IO 的加解密操作,假设 AES-NI 已启用,应只增加相对较小的微秒级延迟,以及少量 CPU 使用率上升。
|
||
|
||
### 8.4 完整示例
|
||
|
||
**(1) 创建一个有效大小为 50GiB 的 LUKS2 格式 image:**
|
||
|
||
```bash
|
||
rbd create --size 50G mypool/myimage
|
||
rbd encryption format mypool/myimage luks2 passphrase.bin
|
||
rbd resize --size 50G --encryption-passphrase-file passphrase.bin mypool/myimage
|
||
```
|
||
|
||
> 最后的 `rbd resize` 用于把 image 增大,以补偿 LUKS2 header 带来的开销。
|
||
|
||
**(2) 给定一个 LUKS2 格式的 image,创建一个相同有效大小的 LUKS2 格式克隆:**
|
||
|
||
```bash
|
||
rbd snap create mypool/myimage@snap
|
||
rbd snap protect mypool/myimage@snap
|
||
rbd clone mypool/myimage@snap mypool/myclone
|
||
rbd encryption format mypool/myclone luks2 clone-passphrase.bin
|
||
```
|
||
|
||
**(3) 给定一个有效大小 50GiB 的 LUKS2 image,创建一个相同有效大小的 LUKS1 克隆:**
|
||
|
||
```bash
|
||
rbd snap create mypool/myimage@snap
|
||
rbd snap protect mypool/myimage@snap
|
||
rbd clone mypool/myimage@snap mypool/myclone
|
||
rbd encryption format mypool/myclone luks1 clone-passphrase.bin
|
||
rbd resize --size 50G --allow-shrink --encryption-passphrase-file clone-passphrase.bin --encryption-passphrase-file passphrase.bin mypool/myclone
|
||
```
|
||
|
||
> LUKS1 header 通常比 LUKS2 header 小,因此最后的 `rbd resize` 用于**缩小**克隆 image 以去掉多余的空间预留。
|
||
|
||
**(4) 给定一个有效大小 50GiB 的 LUKS1 image,创建一个相同有效大小的 LUKS2 克隆:**
|
||
|
||
```bash
|
||
rbd resize --size 51G mypool/myimage
|
||
rbd snap create mypool/myimage@snap
|
||
rbd snap protect mypool/myimage@snap
|
||
rbd clone mypool/myimage@snap mypool/myclone
|
||
rbd encryption format mypool/myclone luks2 clone-passphrase.bin
|
||
rbd resize --size 50G --allow-shrink --encryption-passphrase-file passphrase.bin mypool/myimage
|
||
rbd resize --size 50G --allow-shrink --encryption-passphrase-file clone-passphrase.bin --encryption-passphrase-file passphrase.bin mypool/myclone
|
||
```
|
||
|
||
> LUKS2 header 通常比 LUKS1 大,因此最开始的 `rbd resize` 临时**增大**父 image,以在父快照(进而克隆 image)中预留额外空间,这是为了让全部父数据在克隆中可访问所必需的。最后两条 `rbd resize` 把父 image 缩回原大小(**这不影响父快照**),并把克隆 image 也缩小以去掉未使用的预留空间。
|
||
|
||
> **同样的逻辑适用于从一个未格式化(plaintext)image 创建格式化克隆**——因为未格式化 image 根本没有 header。
|
||
|
||
**(5) 映射一个格式化的克隆**
|
||
|
||
需要为克隆自身**以及所有被显式格式化的父 image** 提供加密格式与 passphrase。`encryption-format` 与 `encryption-passphrase-file` 选项的提供顺序**基于 image 层级**:先是克隆 image 自己的,然后是其父 image 的,依次向上。
|
||
|
||
```bash
|
||
rbd device map -t nbd -o encryption-passphrase-file=clone-passphrase.bin,encryption-passphrase-file=passphrase.bin mypool/myclone
|
||
```
|
||
|
||
### 8.5 加密相关速查表
|
||
|
||
| 项 | 值 / 结论 |
|
||
|---|---|
|
||
| 引入版本 | Pacific |
|
||
| 支持格式 | `luks1`、`luks2` |
|
||
| 支持算法 | `aes-128`、`aes-256`(默认 `aes-256`) |
|
||
| 支持模式 | `xts-plain64`(唯一) |
|
||
| 平台 | 仅 Linux 系统(LUKS 格式) |
|
||
| krbd 支持 | **不支持** |
|
||
| `journaling` image | **不能**格式化并加密 |
|
||
| 克隆加密 image | 克隆**必然**加密;**不可**重新格式化为明文 |
|
||
| LUKS header 大小 | 通常 ≤ 16MiB,LUKS2 最大 136MiB(取决于 `libcryptsetup` 版本) |
|
||
| 对齐开销示例 | 8MiB object size → 最小 8MiB;4MiB object size + stripe count 3 → 最小 12MiB |
|
||
| LUKS1 sector | 固定 512 B |
|
||
| LUKS2 sector | 默认最大 4 KiB |
|
||
| 自动 load | 通过 `rbd-nbd` 挂载时可自动应用 |
|
||
| passphrase 增删 | RBD 不支持(可用 `cryptsetup` 在原始数据上做) |
|
||
|
||
---
|
||
|
||
## 九、实时迁移(rbd-live-migration)
|
||
|
||
> 引自:[Image Live-Migration](https://docs.ceph.com/en/tentacle/rbd/rbd-live-migration/)
|
||
|
||
### 9.1 能力概述
|
||
|
||
RBD image 可以被实时迁移(live-migrated):
|
||
|
||
- 在**同一 Ceph 集群内**的不同 pool、不同 image format 和/或不同 layout 之间;
|
||
- 从**另一个 Ceph 集群**的 image 迁移过来;
|
||
- 从**外部数据源**迁移过来。
|
||
|
||
迁移启动后,源会被**深度拷贝(deep-copied)**到目标 image,同时拉取全部快照历史,并尽可能保留数据的稀疏分配(sparse allocation)。
|
||
|
||
**默认行为(同集群内)**:源 image 被标记为**只读**,所有客户端的 IO 被重定向到新的目标 image。此外,这种模式可以:
|
||
|
||
- 可选地**保留到源 image 父镜像的链接**,以保留稀疏性;或
|
||
- 在迁移过程中 **flatten** 该 image,以去除对源 image 父镜像的依赖。
|
||
|
||
**import-only 模式**:源 image 保持不变,目标 image 可以链接到**另一个 Ceph 集群中的 image**,或链接到**外部数据源**,例如 backing file、HTTP(s) 文件、S3 对象或 NBD export。
|
||
|
||
拷贝过程可以在新目标 image **正在被使用**的同时安全地后台运行。**当不使用 import-only 模式时,目前有一个要求:在 prepare 迁移之前必须临时停止使用源 image**,以确保使用该 image 的客户端被更新为指向新的目标 image。
|
||
|
||
```text
|
||
+-------------+ +-------------+
|
||
| {s} c999 | | {s} |
|
||
| Live | Target refers | Live |
|
||
| migration |<-------------*| migration |
|
||
| source | to Source | target |
|
||
| | | |
|
||
| (read only) | | (writable) |
|
||
+-------------+ +-------------+
|
||
|
||
Source Target
|
||
```
|
||
|
||
> 官方 note:image live-migration 需要 **Ceph Nautilus 或更新版本**。对外部数据源的支持需要 **Ceph Pacific 或更新版本**。**`krbd` 内核模块目前不支持 live-migration。**
|
||
|
||
### 9.2 三步流程
|
||
|
||
| 步骤 | 命令 | 说明 |
|
||
|---|---|---|
|
||
| 1. Prepare | `rbd migration prepare` | 创建新的目标 image 并把它链接到源。非 import-only 模式下,源 image 也会被链接到目标 image 并被标记为只读 |
|
||
| 2. Execute | `rbd migration execute` | 后台操作:把源 image 中所有已初始化的块**深度拷贝**到目标。此步骤可在客户端正活跃使用新目标 image 时运行 |
|
||
| 3. Finish | `rbd migration commit` / `rbd migration abort` | commit:移除源与目标之间的交叉链接,并在非 import-only 模式下删除源 image。abort:移除交叉链接并删除目标 image |
|
||
|
||
> Prepare 之后的行为细节:与 layered image 类似,**对目标 image 中未初始化数据区段的读**会被内部重定向到源 image;**对目标中未初始化区段的写**会内部把源 image 中重叠的块深度拷贝到目标 image。
|
||
|
||
### 9.3 Prepare(同集群默认模式)
|
||
|
||
```bash
|
||
$ rbd migration prepare migration_source [migration_target]
|
||
```
|
||
|
||
- `rbd migration prepare` 接受与 `rbd create` **完全相同的 layout 可选参数**,因此可以改变不可变的 image on-disk layout;
|
||
- 如果目标只是改变 on-disk layout 并保留原 image 名,可以**省略 `migration_target`**;
|
||
- **所有使用源 image 的客户端必须在 prepare 之前停止**。如果发现任何运行中的客户端以读写模式打开了该 image,prepare 步骤会失败;
|
||
- prepare 完成后,客户端可以用**新的目标 image 名**重启;**试图用源 image 名重启客户端会失败**。
|
||
|
||
查看状态:
|
||
|
||
```bash
|
||
$ rbd status migration_target
|
||
Watchers: none
|
||
Migration:
|
||
source: rbd/migration_source (5e2cba2f62e)
|
||
destination: rbd/migration_target (5e2ed95ed806)
|
||
state: prepared
|
||
```
|
||
|
||
**注意:源 image 会被移动到 RBD trash**,以避免在迁移过程中被误用:
|
||
|
||
```bash
|
||
$ rbd info migration_source
|
||
rbd: error opening image migration_source: (2) No such file or directory
|
||
$ rbd trash ls --all
|
||
5e2cba2f62e migration_source
|
||
```
|
||
|
||
### 9.4 Prepare(import-only 模式)
|
||
|
||
```bash
|
||
$ rbd migration prepare --import-only --source-spec "<JSON>" migration_target
|
||
```
|
||
|
||
`source-spec` 是一个 JSON 编码的描述,说明如何访问源 image 数据。可以通过 `--source-spec` 直接传入,也可以通过 `--source-spec-path` 从文件或 STDIN 传入。
|
||
|
||
通用格式:
|
||
|
||
```json
|
||
{
|
||
"type": "<format-type>",
|
||
<format unique parameters>
|
||
"stream": {
|
||
"type": "<stream-type>",
|
||
<stream unique parameters>
|
||
}
|
||
}
|
||
```
|
||
|
||
**当前支持的 format**:`native`、`qcow`、`raw`
|
||
**当前支持的 stream**:`file`、`http`、`s3`、`nbd`
|
||
|
||
```bash
|
||
$ rbd status migration_target
|
||
Watchers: none
|
||
Migration:
|
||
source: {"stream":{"file_path":"/mnt/image.raw","type":"file"},"type":"raw"}
|
||
destination: rbd/migration_target (ac69113dc1d7)
|
||
state: prepared
|
||
```
|
||
|
||
#### format: `native`(另一个 Ceph 集群中的原生 RBD image)
|
||
|
||
```json
|
||
{
|
||
"type": "native",
|
||
["cluster_name": "<cluster-name>",] // 若 image 在另一个集群,需指定;要求存在 <cluster-name>.conf 文件
|
||
["client_name": "<client-name>",] // 用于连接另一个集群,默认 client.admin
|
||
"pool_name": "<pool-name>",
|
||
["pool_id": <pool-id>,] // pool_name 的可选替代
|
||
["pool_namespace": "<pool-namespace>",] // 可选
|
||
"image_name": "<image-name>",
|
||
["image_id": "<image-id>",] // 若 image 在 trash 中则指定
|
||
"snap_name": "<snap-name>",
|
||
["snap_id": "<snap-id>",] // snap_name 的可选替代
|
||
}
|
||
```
|
||
|
||
> `native` format **不包含 `stream` 对象**,因为它使用原生 Ceph 操作。
|
||
|
||
示例——导入 `rbd/ns1/image1@snap1`:
|
||
|
||
```json
|
||
{
|
||
"type": "native",
|
||
"pool_name": "rbd",
|
||
"pool_namespace": "ns1",
|
||
"image_name": "image1",
|
||
"snap_name": "snap1"
|
||
}
|
||
```
|
||
|
||
#### format: `qcow`
|
||
|
||
用于描述 QCOW(QEMU copy-on-write)块设备。**QCOW (v1) 与 QCOW2 均受支持**,但**不支持**压缩、加密、backing files、external data files 等高级特性(未来版本可能加入)。`qcow` 数据可以链接到下面任一受支持的 stream 源:
|
||
|
||
```json
|
||
{
|
||
"type": "qcow",
|
||
"stream": {
|
||
<stream unique parameters>
|
||
}
|
||
}
|
||
```
|
||
|
||
#### format: `raw`
|
||
|
||
用于描述厚置备(thick-provisioned)的 raw 块设备导出(即 `rbd export --export-format 1 <snap-spec>`)。`raw` 数据可链接到任一受支持的 stream 源:
|
||
|
||
```json
|
||
{
|
||
"type": "raw",
|
||
"stream": {
|
||
<stream unique parameters for HEAD, non-snapshot revision>
|
||
},
|
||
"snapshots": [
|
||
{
|
||
"type": "raw",
|
||
"name": "<snapshot-name>",
|
||
"stream": {
|
||
<stream unique parameters for snapshot>
|
||
}
|
||
},
|
||
] // 可选;快照按从旧到新排序
|
||
}
|
||
```
|
||
|
||
> `snapshots` 数组是可选的,目前**只支持厚置备的 `raw` 快照导出**。
|
||
> 更多格式(如 RBD export-format v2、RBD export-diff 快照)将在未来版本加入。
|
||
|
||
#### stream: `file`(本地 POSIX 文件)
|
||
|
||
```json
|
||
{
|
||
"type": "raw",
|
||
"stream": {
|
||
"type": "file",
|
||
"file_path": "/mnt/image.raw"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### stream: `http`(远程 HTTP/HTTPS)
|
||
|
||
```json
|
||
{
|
||
"type": "raw",
|
||
"stream": {
|
||
"type": "http",
|
||
"url": "https://download.ceph.com/image.raw"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### stream: `s3`(远程 S3 bucket)
|
||
|
||
```json
|
||
{
|
||
"type": "raw",
|
||
"stream": {
|
||
"type": "s3",
|
||
"url": "https://s3.ceph.com/bucket/image.raw",
|
||
"access_key": "NX5QOQKC6BH2IDN8HC7A",
|
||
"secret_key": "LnEsqNNqZIpkzauboDcLXLcYaWwLQ3Kop0zAnKIn"
|
||
}
|
||
}
|
||
```
|
||
|
||
> 官方 note:`access_key` 与 `secret_key` 参数支持把密钥存放在 **MON config-key store** 中——把值前缀设为 `config://`,后跟该值在 MON config-key store 中的路径。可用 `ceph config-key set <key-path> <value>` 存入,例如 `ceph config-key set rbd/s3/access_key NX5QOQKC6BH2IDN8HC7A`。
|
||
|
||
#### stream: `nbd`(远程 NBD export)
|
||
|
||
```json
|
||
{
|
||
"type": "raw",
|
||
"stream": {
|
||
"type": "nbd",
|
||
"uri": "nbd://nbd.ceph.com/image.raw",
|
||
}
|
||
}
|
||
```
|
||
|
||
> `nbd-uri` 参数应遵循 **NBD URI 规范**。默认 NBD 端口为 **`10809`**。
|
||
|
||
### 9.5 Execute
|
||
|
||
```bash
|
||
$ rbd migration execute migration_target
|
||
Image migration: 100% complete...done.
|
||
```
|
||
|
||
`rbd status` 也会给出块深度拷贝的进度:
|
||
|
||
```bash
|
||
$ rbd status migration_target
|
||
Watchers:
|
||
watcher=1.2.3.4:0/3695551461 client.123 cookie=123
|
||
Migration:
|
||
source: rbd/migration_source (5e2cba2f62e)
|
||
destination: rbd/migration_target (5e2ed95ed806)
|
||
state: executing (32% complete)
|
||
```
|
||
|
||
### 9.6 Commit
|
||
|
||
```bash
|
||
$ rbd status migration_target
|
||
Watchers: none
|
||
Migration:
|
||
source: rbd/migration_source (5e2cba2f62e)
|
||
destination: rbd/migration_target (5e2ed95ed806)
|
||
state: executed
|
||
$ rbd migration commit migration_target
|
||
Commit image migration: 100% complete...done.
|
||
```
|
||
|
||
- 如果 `migration_source` image 是一个或多个克隆的父,**在确认所有后代克隆 image 都未被使用之后,需要指定 `--force` 选项**;
|
||
- commit 会移除源与目标之间的交叉链接,并**删除源 image**:
|
||
|
||
```bash
|
||
$ rbd trash list --all
|
||
```
|
||
|
||
### 9.7 Abort
|
||
|
||
```bash
|
||
$ rbd migration abort migration_target
|
||
Abort image migration: 100% complete...done.
|
||
```
|
||
|
||
abort 会**删除目标 image** 并**恢复对原源 image 的访问**:
|
||
|
||
```bash
|
||
$ rbd ls
|
||
migration_source
|
||
```
|
||
|
||
### 9.8 限制汇总
|
||
|
||
| 限制 | 说明 |
|
||
|---|---|
|
||
| 版本 | live-migration 需 Nautilus+;外部数据源需 Pacific+ |
|
||
| krbd | **不支持** live-migration |
|
||
| 客户端停机 | 非 import-only 模式下,prepare 前**必须停止所有使用源 image 的客户端**;prepare 后发现读写模式的打开者会直接失败 |
|
||
| 源 image 名 | prepare 后源 image 被移入 RBD trash,用旧名字访问会失败 |
|
||
| 克隆父 | commit 时若源是克隆的父,需在确认后代克隆未被使用后用 `--force` |
|
||
| qcow 高级特性 | 压缩、加密、backing files、external data files **不支持** |
|
||
| raw snapshots | 仅支持厚置备 raw 快照导出 |
|
||
| 未来格式 | RBD export-format v2、RBD export-diff 快照尚未支持 |
|
||
|
||
---
|
||
|
||
## 十、镜像与灾备(rbd-mirroring)
|
||
|
||
> 引自:[RBD Mirroring](https://docs.ceph.com/en/tentacle/rbd/rbd-mirroring/)
|
||
|
||
RBD image 可以在两个 Ceph 集群之间**异步镜像**。有两种模式:
|
||
|
||
### 10.1 两种镜像模式对比
|
||
|
||
| 维度 | **Journal-based** | **Snapshot-based** |
|
||
|---|---|---|
|
||
| 机制 | 使用 RBD journaling image feature,确保**时间点、崩溃一致**的复制 | 使用周期性调度或手工创建的 RBD image **mirror-snapshots** 来复制崩溃一致的 RBD image |
|
||
| 数据路径 | 每次对 RBD image 的写**先记录到关联的 journal**,再修改实际 image;远端集群读取该 journal 并重放到本地副本 | 远端集群确定两个 mirror-snapshot 之间的数据/元数据更新,并把**增量(deltas)**拷贝到本地副本 |
|
||
| 一致性粒度 | 细(每次写) | 粗(两个快照之间的完整 delta) |
|
||
| 延迟影响 | 由于每次写变成两次写,**写延迟几乎翻倍** | 无 journal 双写开销 |
|
||
| 性能依赖 | — | 借助 RBD **`fast-diff`** feature,可以快速确定更新的数据块,**无需扫描整个 RBD image** |
|
||
| 故障切换 | 直接可用 | **故障切换前必须先把两个快照之间的完整 delta 同步完成** |
|
||
| 部分应用 | 不适用 | 故障切换时,**任何部分应用的 delta 集合会被回滚** |
|
||
| 版本要求 | **Ceph Jewel 或更新** | **Ceph Octopus 或更新** |
|
||
|
||
### 10.2 池 / 命名空间 / 单向 / 双向
|
||
|
||
- 镜像在**对端集群(peer clusters)的 pool 级别**配置,可以进一步配置到 pool 内的**命名空间**或**特定 image 子集**;
|
||
- 使用 journal-based mirroring 时,也可以镜像给定 pool 或命名空间内的**所有** image;
|
||
- 镜像用 `rbd` 命令配置;**`rbd-mirror` 守护进程**负责从远端对端集群拉取 image 更新并应用到本地集群的 image 上;
|
||
- **Pool 名在两个对端集群上必须相同**(重命名 pool 参见 RADOS 文档的 Renaming a Pool)。
|
||
|
||
| 复制方向 | 定义 | `rbd-mirror` 守护进程运行位置 |
|
||
|---|---|---|
|
||
| **One-way(单向)** | 数据只从 primary 集群镜像到 secondary 集群 | 仅在 **secondary** 集群上运行 |
|
||
| **Two-way(双向)** | 数据从一个集群的 primary image 镜像到另一个集群的 non-primary image(反之亦然) | **两个集群都运行** |
|
||
|
||
> ⚠️ 官方 important:每个 `rbd-mirror` 守护进程实例必须能够**同时连接本地与远端两个 Ceph 集群**(即所有 monitor 和 OSD 主机)。此外,两个数据中心之间必须有足够带宽承载镜像工作负载。
|
||
|
||
> 官方 note:本文档中所有 "namespace" 一词均指 **RBD 命名空间**。
|
||
|
||
### 10.3 Pool 配置
|
||
|
||
以下步骤应在**两个对端集群上**执行。示例假定两个集群名为 "site-a" 和 "site-b",并且都能从同一台主机访问(为表述清晰)。
|
||
|
||
> 官方 note:示例中的集群名对应同名的 Ceph 配置文件(如 `/etc/ceph/site-b.conf`)。**`rbd-mirror` 不要求源和目标集群有不同的内部名——两者都可以、也应该都叫 `ceph`。** `rbd-mirror` 所需的本地/远程集群配置文件可以任意命名,把守护进程容器化是避免 `/etc/ceph` 下命名混淆的一种策略。
|
||
|
||
#### 启用镜像
|
||
|
||
```bash
|
||
rbd mirror pool enable [--site-name {local-site-name}] {pool-name} {mode}
|
||
```
|
||
|
||
`mode` 取值:
|
||
|
||
| 模式 | 含义 |
|
||
|---|---|
|
||
| `image` | 必须对 pool 默认命名空间中**每个期望的 image 显式启用**镜像。其他命名空间不受影响,需单独配置 |
|
||
| `pool` | pool 默认命名空间中**所有启用了 journaling feature 的 image** 都会被镜像。其他命名空间不受影响,需单独配置 |
|
||
| `init-only` | pool 默认命名空间中的**任何 image 都不会**被镜像,但其他命名空间仍可配置。用于允许某个其他命名空间镜像到远端 pool 的默认命名空间,也可单独使用 |
|
||
|
||
```bash
|
||
$ rbd --cluster site-a mirror pool enable --site-name site-a image-pool image
|
||
$ rbd --cluster site-b mirror pool enable --site-name site-b image-pool image
|
||
```
|
||
|
||
- site name 也可以**在创建或导入 bootstrap token 时**指定;
|
||
- site name 之后可以用同一个 `mirror pool enable` 子命令更改,但注意**本地 site name 与远端集群使用的对应 site name 通常必须匹配**。
|
||
|
||
#### 禁用镜像
|
||
|
||
```bash
|
||
rbd mirror pool disable {pool-name}
|
||
```
|
||
|
||
> 以这种方式禁用 pool 上的镜像时,**pool 内所有显式启用了镜像的 image 上的镜像也会被禁用**。
|
||
|
||
```bash
|
||
$ rbd --cluster site-a mirror pool disable image-pool
|
||
$ rbd --cluster site-b mirror pool disable image-pool
|
||
```
|
||
|
||
#### Bootstrap Peers(引导对端)
|
||
|
||
为了让 `rbd-mirror` 守护进程发现其对端集群,必须注册对端并创建一个用户账户。该过程可用 `rbd` 的 `mirror pool peer bootstrap create` 与 `mirror pool peer bootstrap import` 命令自动化。
|
||
|
||
**创建 token(在 site-a):**
|
||
|
||
```bash
|
||
rbd mirror pool peer bootstrap create [--site-name {local-site-name}] {pool-name}
|
||
```
|
||
|
||
```bash
|
||
$ rbd --cluster site-a mirror pool peer bootstrap create --site-name site-a image-pool
|
||
eyJmc2lkIjoiOWY1MjgyZGItYjg5OS00NTk2LTgwOTgtMzIwYzFmYzM5NmYzIiwiY2xpZW50X2lkIjoicmJkLW1pcnJvci1wZWVyIiwia2V5IjoiQVFBUnczOWQwdkhvQmhBQVlMM1I4RmR5dHNJQU50bkFTZ0lOTVE9PSIsIm1vbl9ob3N0IjoiW3YyOjE5Mi4xNjguMS4zOjY4MjAsdjE6MTkyLjE2OC4xLjM6NjgyMV0ifQ==
|
||
```
|
||
|
||
输出是一个 token,应提供给 `mirror pool peer bootstrap import` 命令。
|
||
|
||
**导入 token(在 site-b):**
|
||
|
||
```bash
|
||
rbd mirror pool peer bootstrap import [--site-name {local-site-name}] [--direction {rx-only or rx-tx}] {pool-name} {token-path}
|
||
```
|
||
|
||
- `token-path` 可以是文件路径,或 `-`(从标准输入读取);
|
||
- `--direction` 默认为 **`rx-tx`(双向镜像)**,也可设为 **`rx-only`(单向镜像)**。
|
||
|
||
```bash
|
||
$ cat <<EOF > token
|
||
eyJmc2lkIjoiOWY1MjgyZGItYjg5OS00NTk2LTgwOTgtMzIwYzFmYzM5NmYzIiwiY2xpZW50X2lkIjoicmJkLW1pcnJvci1wZWVyIiwia2V5IjoiQVFBUnczOWQwdkhvQmhBQVlMM1I4RmR5dHNJQU50bkFTZ0lOTVE9PSIsIm1vbl9ob3N0IjoiW3YyOjE5Mi4xNjguMS4zOjY4MjAsdjE6MTkyLjE2OC4xLjM6NjgyMV0ifQ==
|
||
EOF
|
||
$ rbd --cluster site-b mirror pool peer bootstrap import --site-name site-b image-pool token
|
||
```
|
||
|
||
#### 手工添加集群对端(Add Cluster Peer Manually)
|
||
|
||
如果需要手工指定,或当前安装的 Ceph 版本没有上述 bootstrap 命令,可以手工添加。
|
||
|
||
先创建一个供远端守护进程使用的本地 Ceph 用户:
|
||
|
||
```bash
|
||
$ ceph auth get-or-create client.rbd-mirror-peer mon 'profile rbd-mirror-peer' osd 'profile rbd'
|
||
```
|
||
|
||
生成的 keyring 需要拷贝到对端集群的 `rbd-mirror` 守护进程主机(除非使用下述 monitor `config-key` store)。
|
||
|
||
```bash
|
||
rbd mirror pool peer add {pool-name} {client-name}@{cluster-name}
|
||
```
|
||
|
||
```bash
|
||
$ rbd --cluster site-a mirror pool peer add image-pool client.rbd-mirror-peer@site-b
|
||
$ rbd --cluster site-b mirror pool peer add image-pool client.rbd-mirror-peer@site-a
|
||
```
|
||
|
||
- 默认情况下,`rbd-mirror` 守护进程需要能访问 `/etc/ceph/{cluster-name}.conf`(提供对端集群 monitor 地址),以及在默认或已配置的 keyring 搜索路径中的 `{client-name}` keyring(如 `/etc/ceph/{cluster-name}.{client-name}.keyring`);
|
||
- 另一种方式:把对端集群的 monitor 和/或 client key 安全存放在**本地 Ceph monitor 的 `config-key` store** 中。添加镜像对端时用 `--remote-mon-host` 与 `--remote-key-file` 选项:
|
||
|
||
```bash
|
||
$ cat <<EOF > remote-key-file
|
||
AQAeuZdbMMoBChAAcj++/XUxNOLFaWdtTREEsw==
|
||
EOF
|
||
$ rbd --cluster site-a mirror pool peer add image-pool client.rbd-mirror-peer@site-b --remote-mon-host 192.168.1.1,192.168.1.2 --remote-key-file remote-key-file
|
||
$ rbd --cluster site-a mirror pool info image-pool --all
|
||
Mode: pool
|
||
Peers:
|
||
UUID NAME CLIENT MON_HOST KEY
|
||
587b08db-3d33-4f32-8af8-421e77abb081 site-b client.rbd-mirror-peer 192.168.1.1,192.168.1.2 AQAeuZdbMMoBChAAcj++/XUxNOLFaWdtTREEsw==
|
||
```
|
||
|
||
#### 移除集群对端
|
||
|
||
```bash
|
||
rbd mirror pool peer remove {pool-name} {peer-uuid} # peer-uuid 可从 rbd mirror pool info 获得
|
||
```
|
||
|
||
```bash
|
||
$ rbd --cluster site-a mirror pool peer remove image-pool 55672766-c02b-4729-8567-f13a66893445
|
||
$ rbd --cluster site-b mirror pool peer remove image-pool 60c0e299-b38f-4234-91f6-eed0a367be08
|
||
```
|
||
|
||
#### Data Pools
|
||
|
||
在目标集群创建 image 时,`rbd-mirror` 按以下顺序选择 data pool:
|
||
|
||
1. 如果目标集群配置了默认 data pool(配置项 **`rbd_default_data_pool`**),则使用它;
|
||
2. 否则,如果源 image 使用了独立的 data pool,且目标集群上存在**同名**的 pool,则使用该 pool;
|
||
3. 如果以上都不成立,**不设置 data pool**。
|
||
|
||
(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`:`rbd_default_data_pool` 无 `default:` 字段 → **文档未明确**具体默认值;仅能从 validator 推断其合法值为不含 `@` 与 `/` 的字符串,非法值时被重置为空字符串。)
|
||
|
||
### 10.4 命名空间(Namespace)配置
|
||
|
||
镜像可以在 pool 的**非默认命名空间**上启用,且独立于默认命名空间。**pool 必须已预先配置好镜像。** 一个命名空间可以镜像到远端 pool 中**同名或不同名**的命名空间,包括镜像到默认命名空间(记作 `''` 或 `""`)。
|
||
|
||
#### 启用
|
||
|
||
```bash
|
||
rbd mirror pool enable {pool-name}/{local-namespace-name} {mode} [--remote-namespace {remote-namespace-name}]
|
||
```
|
||
|
||
`mode` 只能是 `image` 或 `pool`:
|
||
|
||
| 模式 | 含义 |
|
||
|---|---|
|
||
| `image` | 必须为命名空间中每个期望的 image **显式启用**镜像 |
|
||
| `pool` | 命名空间中**所有启用了 journaling feature 的 image** 都被镜像 |
|
||
|
||
```bash
|
||
$ rbd --cluster site-a mirror pool enable image-pool/namespace-a image --remote-namespace namespace-b
|
||
$ rbd --cluster site-b mirror pool enable image-pool/namespace-b image --remote-namespace namespace-a
|
||
```
|
||
|
||
- **本地集群上配置的 namespace 与 remote-namespace 对,必须与远端集群上的 remote-namespace 与 namespace 分别匹配**;
|
||
- 若未提供 `--remote-namespace`,则镜像到远端 pool 中**同名**的命名空间。
|
||
|
||
**示例 A**:在 site-a 的 `image-pool`(默认命名空间)与 site-b 的 `image-pool/namespace-c` 之间建立 **pool 模式**镜像:
|
||
|
||
```bash
|
||
$ rbd --cluster site-a mirror pool enable image-pool pool --remote-namespace namespace-c
|
||
$ rbd --cluster site-b mirror pool enable image-pool init-only
|
||
$ rbd --cluster site-b mirror pool enable image-pool/namespace-c pool --remote-namespace ""
|
||
```
|
||
|
||
**示例 B**:site-a 的 `image-pool`(默认)与 site-b 的 `image-pool/namespace-d` 之间建立 pool 模式镜像,**同时** site-b 的 `image-pool`(默认)与 site-a 的 `image-pool/namespace-e` 之间建立 image 模式镜像:
|
||
|
||
```bash
|
||
$ rbd --cluster site-a mirror pool enable image-pool pool --remote-namespace namespace-d
|
||
$ rbd --cluster site-a mirror pool enable image-pool/namespace-e image --remote-namespace ""
|
||
$ rbd --cluster site-b mirror pool enable image-pool image --remote-namespace namespace-e
|
||
$ rbd --cluster site-b mirror pool enable image-pool/namespace-d pool --remote-namespace ""
|
||
```
|
||
|
||
#### 禁用
|
||
|
||
```bash
|
||
rbd mirror pool disable {pool-name}/{namespace-name}
|
||
```
|
||
|
||
> 在 `image` 模式下,命名空间中任何已启用镜像的 image 必须先被显式禁用,才能禁用该命名空间的镜像。
|
||
|
||
```bash
|
||
$ rbd --cluster site-a mirror pool disable image-pool/namespace-a
|
||
$ rbd --cluster site-b mirror pool disable image-pool/namespace-b
|
||
```
|
||
|
||
### 10.5 Image 配置
|
||
|
||
与 pool 配置不同,**image 配置只需要针对单个镜像对端集群执行**。
|
||
|
||
- 被镜像的 RBD image 被指定为 **primary** 或 **non-primary**。这是 **image 的属性,不是 pool 的属性**;
|
||
- 被指定为 non-primary 的 image **不能被修改**;
|
||
- 首次在 image 上启用镜像时,image 会被**自动提升为 primary**(如果 pool 镜像模式是 `pool` 且该 image 启用了 journaling feature,则隐式提升;如果 pool 镜像模式是 `image`,则由 `rbd` 命令显式启用时提升)。
|
||
|
||
#### 启用 image 镜像
|
||
|
||
如果 image 所在 pool 配置为 `image` 模式,则必须为 pool 内的**每个** image 显式启用镜像:
|
||
|
||
```bash
|
||
rbd mirror image enable {pool-name}/{image-name} {mode}
|
||
```
|
||
|
||
`mode` 取值:
|
||
|
||
| 模式 | 说明 |
|
||
|---|---|
|
||
| `journal`(**默认**) | 使用 RBD journaling image feature 复制 image 内容。如果该 image 尚未启用 journaling feature,会**自动启用** |
|
||
| `snapshot` | 使用 RBD image mirror-snapshots 复制 image 内容。启用后会自动创建**初始 mirror-snapshot**;可用 `rbd` 命令创建更多 mirror-snapshots |
|
||
|
||
```bash
|
||
$ rbd --cluster site-a mirror image enable image-pool/image-1 snapshot
|
||
$ rbd --cluster site-a mirror image enable image-pool/image-2 journal
|
||
```
|
||
|
||
#### 启用 image journaling feature
|
||
|
||
- `image` 镜像模式下,image 上启用镜像时会自动启用 journaling feature;
|
||
- `pool` 镜像模式下,在 image 能被镜像到对端集群之前,**必须已启用 RBD image journaling feature**。可以在创建 image 时通过 `--image-feature exclusive-lock,journaling` 启用;
|
||
|
||
也可以对既有 RBD image 动态启用:
|
||
|
||
```bash
|
||
rbd feature enable {pool-name}/{image-name} {feature-name}
|
||
$ rbd --cluster site-a feature enable image-pool/image-1 journaling
|
||
```
|
||
|
||
> 官方 note:journaling feature **依赖 exclusive-lock feature**。如果 exclusive-lock 尚未启用,应**先**启用它,再启用 journaling。
|
||
|
||
> 💡 Tip(官方原文):可以在 Ceph 配置文件中加入 `rbd default features = 125`,使**所有新建 image 默认启用 journaling**。(125 = 1 + 4 + 8 + 16 + 32 + 64 = layering + exclusive-lock + object-map + fast-diff + deep-flatten + journaling)
|
||
|
||
> 💡 Tip(官方原文):`rbd-mirror` 的可调参数默认值是为"镜像整个 pool"设定的。当用 `rbd-mirror` **在集群之间迁移单个卷**时,在本地或集中式配置的 `[client]` 段设置 **`rbd_journal_max_payload_bytes=8388608`** 可能获得显著的性能提升。注意该设置可能让 `rbd-mirror` 对目标集群呈现可观的写工作负载:迁移期间要**密切监控集群性能**,并行跑多个迁移前要**仔细测试**。
|
||
|
||
(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`:`rbd_journal_max_payload_bytes` 类型为 size,默认 **`16_K`**)
|
||
|
||
#### 创建 image mirror-snapshots
|
||
|
||
使用 snapshot-based mirroring 时,每当希望镜像 RBD image 的变化内容时,都需要创建 mirror-snapshot:
|
||
|
||
```bash
|
||
rbd mirror image snapshot {pool-name}/{image-name}
|
||
$ rbd --cluster site-a mirror image snapshot image-pool/image-1
|
||
```
|
||
|
||
- **默认情况下每个 image 最多创建 `5` 个 mirror-snapshot**。达到上限时,**最近的 mirror-snapshot 会被自动剪除**。该上限可通过配置项 **`rbd_mirroring_max_mirroring_snapshots`** 覆盖;
|
||
- image 被删除或镜像被禁用时,mirror-snapshots 会被自动删除。
|
||
|
||
**自动创建**:如果定义了 mirror-snapshot schedule,mirror-snapshots 也可以周期性地自动创建。调度可以在 **global、per-pool、per-image** 级别定义。任何级别都可以定义多个调度,但**只有匹配某个被镜像 image 的、最具体的(most-specific)调度会运行**。
|
||
|
||
```bash
|
||
rbd mirror snapshot schedule add [--pool {pool-name}] [--image {image-name}] {interval} [{start-time}]
|
||
```
|
||
|
||
- `interval` 可用 `d`(天)、`h`(小时)、`m`(分钟)后缀指定;
|
||
- 可选的 `start-time` 使用 **ISO 8601** 时间格式。
|
||
|
||
```bash
|
||
$ rbd --cluster site-a mirror snapshot schedule add --pool image-pool 24h 14:00:00-05:00
|
||
$ rbd --cluster site-a mirror snapshot schedule add --pool image-pool --image image1 6h
|
||
```
|
||
|
||
**移除调度**:用 `mirror snapshot schedule remove`,选项需与对应的 `add` 命令匹配。
|
||
|
||
**列出调度**(列出某一级别:global/pool/image 的所有调度;加 `--recursive` 可列出该级别及其以下的所有调度):
|
||
|
||
```bash
|
||
$ rbd --cluster site-a mirror snapshot schedule ls --pool image-pool --recursive
|
||
POOL NAMESPACE IMAGE SCHEDULE
|
||
image-pool - - every 1d starting at 14:00:00-05:00
|
||
image-pool image1 every 6h
|
||
```
|
||
|
||
**查看下次快照生成时间**:
|
||
|
||
```bash
|
||
rbd mirror snapshot schedule status [--pool {pool-name}] [--image {image-name}]
|
||
$ rbd --cluster site-a mirror snapshot schedule status
|
||
SCHEDULE TIME IMAGE
|
||
2020-02-26 18:00:00 image-pool/image1
|
||
```
|
||
|
||
#### 禁用 image 镜像
|
||
|
||
```bash
|
||
rbd mirror image disable {pool-name}/{image-name}
|
||
$ rbd --cluster site-a mirror image disable image-pool/image-1
|
||
```
|
||
|
||
### 10.6 Image Promotion / Demotion 与故障切换
|
||
|
||
**故障切换流程(官方描述)**:在需要把 primary 身份移到对端集群 image 的故障切换场景中,应当:
|
||
|
||
1. **停止对 primary image 的访问**(例如关闭 VM 电源或从 VM 上移除关联的驱动器);
|
||
2. **demote** 当前的 primary image;
|
||
3. **promote** 新的 primary image;
|
||
4. 在备用集群上恢复对该 image 的访问。
|
||
|
||
> ⚠️ 官方 note:**RBD 只提供促成 image 有序故障切换所必需的工具**。完整的故障切换过程需要**外部机制**来协调(例如在 demotion 之前关闭 image)。
|
||
|
||
| 操作 | 命令 | 示例 |
|
||
|---|---|---|
|
||
| demote 单个 image | `rbd mirror image demote {pool-name}/{image-name}` | `rbd --cluster site-a mirror image demote image-pool/image-1` |
|
||
| demote 整个 pool 的所有 primary image | `rbd mirror pool demote {pool-name}` | `rbd --cluster site-a mirror pool demote image-pool` |
|
||
| promote 单个 image | `rbd mirror image promote [--force] {pool-name}/{image-name}` | `rbd --cluster site-b mirror image promote image-pool/image-1` |
|
||
| promote 整个 pool 的所有 non-primary image | `rbd mirror pool promote [--force] {pool-name}` | `rbd --cluster site-a mirror pool promote image-pool` |
|
||
|
||
> 💡 Tip(官方原文):由于 primary / non-primary 状态是**按 image** 的,因此可以让两个集群分担 IO 负载,并编排 failover / failback。
|
||
|
||
> ⚠️ 官方 note:可以用 `--force` 强制提升。**当 demotion 无法传播到对端集群时(例如 Ceph 集群故障、通信中断)才需要强制提升。这将导致两个对端之间出现 split-brain(脑裂)场景,且在发出 force resync 命令之前,该 image 将不再处于 in-sync 状态。**
|
||
|
||
### 10.7 Force Image Resync(强制重新同步)
|
||
|
||
如果 `rbd-mirror` 守护进程检测到 split-brain 事件,它**不会**尝试镜像受影响的 image,直到问题被纠正。恢复镜像的步骤:
|
||
|
||
1. 先 **demote** 被判定为过期的 image;
|
||
2. 然后请求 resync 到 primary image。
|
||
|
||
```bash
|
||
rbd mirror image resync {pool-name}/{image-name}
|
||
$ rbd mirror image resync image-pool/image-1
|
||
```
|
||
|
||
- > 官方 note:`rbd` 命令**只是把该 image 标记为需要 resync**。本地集群的 `rbd-mirror` 守护进程负责**异步**执行 resync。
|
||
- > 官方 note:对于 **snapshot-based mirroring**,resync **只复制到最近的 mirror-snapshot 为止的 image 内容**。要同步最新更新,需要在 primary image 上**创建一个新的 mirror-snapshot**。
|
||
|
||
### 10.8 Mirror Status
|
||
|
||
对端集群的复制状态会为**每个 primary 被镜像 image** 保存。可用以下命令获取:
|
||
|
||
```bash
|
||
rbd mirror image status {pool-name}/{image-name}
|
||
$ rbd mirror image status image-pool/image-1
|
||
|
||
rbd mirror pool status {pool-name}
|
||
$ rbd mirror pool status image-pool
|
||
```
|
||
|
||
> 官方 note:给 `mirror pool status` 命令加 `--verbose` 选项,会额外输出 pool 中每个被镜像 image 的状态详情。
|
||
|
||
### 10.9 rbd-mirror 守护进程
|
||
|
||
- 两个 `rbd-mirror` 守护进程负责监视**远端对端集群**上的 image journal,并把 journal 事件重放到本地集群;
|
||
- 位于可选的 **`rbd-mirror`** 发行包中;
|
||
- > ⚠️ 官方 important:每个 `rbd-mirror` 守护进程**必须能够同时连接到两个集群**;
|
||
- > ⚠️ 官方 warning:**Luminous 之前的版本:每个 Ceph 集群只能运行一个 `rbd-mirror` 守护进程。**
|
||
|
||
每个 `rbd-mirror` 守护进程应使用**唯一的 Ceph user ID**:
|
||
|
||
```bash
|
||
ceph auth get-or-create client.rbd-mirror.{unique id} mon 'profile rbd-mirror' osd 'profile rbd'
|
||
```
|
||
|
||
用 systemd 管理(以 user ID 作为守护进程实例名):
|
||
|
||
```bash
|
||
systemctl enable ceph-rbd-mirror@rbd-mirror.{unique id}
|
||
```
|
||
|
||
也可以前台运行:
|
||
|
||
```bash
|
||
rbd-mirror -f --log-file={log_path}
|
||
```
|
||
|
||
### 10.10 镜像相关配置项(含从 options/*.yaml.in 查到的默认值)
|
||
|
||
#### 保存在 `src/common/options/rbd.yaml.in` 中的镜像相关项(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`)
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_mirroring_max_mirroring_snapshots` | uint | `5`(min: 3) | 每个 image 的 mirroring snapshots 上限 | 提高可获得更长历史,但占用更多空间;**不得低于 3** |
|
||
| `rbd_mirroring_resync_after_disconnect` | bool | `false` | 镜像因 laggy 而断开后,是否自动启动 image resync | 谨慎开启,可能造成非预期的全量 resync |
|
||
| `rbd_mirroring_delete_delay` | uint | `0` | `rbd-mirror` 删除操作的传播延迟秒数 | 防止误删快速传播时可设正值 |
|
||
| `rbd_mirroring_replay_delay` | uint | `0` | `rbd-mirror` 异步复制的时间延迟秒数 | 需要"延迟复制"以抵御误删/勒索时可设正值 |
|
||
|
||
#### `rbd-mirror` 守护进程配置项(默认值取自 `src/common/options/rbd-mirror.yaml.in @ v20.2.4`)
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_mirror_journal_commit_age` | float | `5` | journal commit 时间间隔(秒) | 默认即可 |
|
||
| `rbd_mirror_journal_poll_age` | float | `5` | 两次 journal poll 之间的最大间隔(秒) | 降低可减小复制延迟、提高开销 |
|
||
| `rbd_mirror_sync_point_update_age` | float | `30` | 更新 image sync point object number 的间隔秒数 | 默认即可 |
|
||
| `rbd_mirror_concurrent_image_syncs` | uint | `5` | 并行的 image sync 最大数量 | 带宽充裕且 image 多时可增大 |
|
||
| `rbd_mirror_pool_replayers_refresh_interval` | uint | `30` | `rbd-mirror` 守护进程刷新 peers 的间隔(秒) | 默认即可 |
|
||
| `rbd_mirror_concurrent_image_deletions` | uint | `1`(min: 1) | 并行的 image 删除最大数量 | 默认即可 |
|
||
| `rbd_mirror_delete_retry_interval` | float | `30` | 检查并重试失败删除请求的间隔(秒) | 默认即可 |
|
||
| `rbd_mirror_image_state_check_interval` | uint | `30`(min: 1) | 从 pool watcher 获取 image 并在 replayer 中设置来源的间隔(秒) | 默认即可 |
|
||
| `rbd_mirror_leader_heartbeat_interval` | uint | `5`(min: 1) | mirror leader 心跳间隔(秒) | 默认即可 |
|
||
| `rbd_mirror_leader_max_missed_heartbeats` | uint | `2` | 非锁持有者尝试获取锁所需的错过心跳数 | 默认即可 |
|
||
| `rbd_mirror_leader_max_acquire_attempts_before_break` | uint | `3` | 错过心跳后、打破锁之前尝试获取锁的失败次数上限 | 默认即可 |
|
||
| `rbd_mirror_image_policy_type` | str | `simple` | active/active 场景下把 image 映射到实例的策略类型;枚举:`none` / `simple` | 多实例 active/active 时启用 |
|
||
| `rbd_mirror_image_policy_migration_throttle` | uint | `300` | 一个 image 可以被再次 reshuffle(迁移)之前需等待的秒数 | 默认即可 |
|
||
| `rbd_mirror_image_policy_update_throttle_interval` | float | `1`(min: 1) | 为 mirror daemon peer 更新而对 image 做节流的间隔(秒) | 默认即可 |
|
||
| `rbd_mirror_image_policy_rebalance_timeout` | float | `0` | 策略空闲多少秒后触发 image 的 reshuffle(rebalance) | `0` 表示不自动 rebalance |
|
||
| `rbd_mirror_perf_stats_prio` | int | `5`(min: 0,max: 11) | mirror 守护进程复制 perf counter 的优先级;不低于 `mgr_stats_threshold` 时才会把数据发给 mgr | 需要采集镜像复制指标时调高 |
|
||
| `rbd_mirror_image_perf_stats_prio` | int | `5`(min: 0,max: 11) | mirror 守护进程**按 image** 的复制 perf counter 优先级 | 同上 |
|
||
| `rbd_mirror_memory_autotune` | bool(dev) | `true` | 在尊重 min 值的前提下自动调优缓存比例 | 保持默认 |
|
||
| `rbd_mirror_memory_target` | size | `4_G` | 启用 tcmalloc 与缓存自动调优时,尝试维持在内存中的字节数 | 按主机内存调整 |
|
||
| `rbd_mirror_memory_base` | size(dev) | `768_M` | 自动调优时,`rbd-mirror` 守护进程所需的最小内存估算 | 默认即可 |
|
||
| `rbd_mirror_memory_expected_fragmentation` | float(dev) | `0.15`(min: 0,max: 1) | 自动调优时的内存碎片率估算 | 默认即可 |
|
||
| `rbd_mirror_memory_cache_min` | size(dev) | `128_M` | 自动调优时用于缓存的最小内存量 | 默认即可 |
|
||
| `rbd_mirror_memory_cache_resize_interval` | float(dev) | `5` | 自动调优时两次缓存 resize 之间等待的秒数 | 默认即可 |
|
||
| `rbd_mirror_memory_cache_autotune_interval` | float(dev) | `30` | 启用缓存自动调优时,两次 rebalance 之间等待的秒数 | 默认即可 |
|
||
|
||
#### journal 相关配置项(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`)
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 |
|
||
|---|---|---|---|
|
||
| `rbd_journal_order` | uint | `24`(min: 12,max: 26) | journal 数据对象的 order(object size) |
|
||
| `rbd_journal_splay_width` | uint | `4` | 活跃的 journal 对象数量 |
|
||
| `rbd_journal_commit_age` | float | `5` | journal commit 时间间隔(秒) |
|
||
| `rbd_journal_object_writethrough_until_flush` | bool | `true` | 启用时,在收到第一个 flush 之前忽略 `rbd_journal_object_flush*` 配置,以便成批的 journal IO 被确认对一致性是安全的 |
|
||
| `rbd_journal_object_flush_interval` | uint | `0` | 每个 journal 对象的最大挂起 commit 数 |
|
||
| `rbd_journal_object_flush_bytes` | size | `1_M` | 每个 journal 对象的最大挂起字节数 |
|
||
| `rbd_journal_object_flush_age` | float | `0` | 挂起 commit 的最大存活时间(秒) |
|
||
| `rbd_journal_object_max_in_flight_appends` | uint | `0` | 每个 journal 对象的最大在途 append 数 |
|
||
| `rbd_journal_pool` | str | **文档未明确**(`rbd.yaml.in` 中无 `default:` 字段) | 存放 journal 对象的 pool |
|
||
| `rbd_journal_max_payload_bytes` | size | `16_K` | 拆分前的最大 journal payload 大小(迁移场景官方建议调为 `8388608`) |
|
||
| `rbd_journal_max_concurrent_object_sets` | uint | `0` | journal client 在被自动注销之前最多可以落后的 object set 数量 |
|
||
|
||
### 10.11 镜像命令速查表
|
||
|
||
| 命令 | 用途 |
|
||
|---|---|
|
||
| `rbd mirror pool enable [--site-name X] {pool} {image\|pool\|init-only}` | 在 pool(或命名空间)上启用镜像 |
|
||
| `rbd mirror pool disable {pool\|pool/ns}` | 禁用 pool / 命名空间上的镜像 |
|
||
| `rbd mirror pool peer bootstrap create [--site-name X] {pool}` | 创建 bootstrap token |
|
||
| `rbd mirror pool peer bootstrap import [--site-name X] [--direction rx-only\|rx-tx] {pool} {token-path}` | 导入对端 token |
|
||
| `rbd mirror pool peer add {pool} {client-name}@{cluster-name}` | 手工添加对端集群 |
|
||
| `rbd mirror pool peer remove {pool} {peer-uuid}` | 移除对端集群 |
|
||
| `rbd mirror pool info {pool} --all` | 查看 pool 镜像模式与对端信息 |
|
||
| `rbd mirror image enable {pool}/{image} {journal\|snapshot}` | 启用 image 镜像 |
|
||
| `rbd mirror image disable {pool}/{image}` | 禁用 image 镜像 |
|
||
| `rbd feature enable {pool}/{image} journaling` | 动态启用 journaling feature |
|
||
| `rbd mirror image snapshot {pool}/{image}` | 手工创建 mirror-snapshot |
|
||
| `rbd mirror snapshot schedule add [--pool P] [--image I] {interval} [{start-time}]` | 添加快照调度 |
|
||
| `rbd mirror snapshot schedule remove ...` | 移除快照调度(参数需与 add 匹配) |
|
||
| `rbd mirror snapshot schedule ls [--pool P] [--image I] [--recursive]` | 列出快照调度 |
|
||
| `rbd mirror snapshot schedule status [--pool P] [--image I]` | 查看下次快照时间 |
|
||
| `rbd mirror image demote {pool}/{image}` | demote 单个 image |
|
||
| `rbd mirror pool demote {pool}` | demote pool 内所有 primary image |
|
||
| `rbd mirror image promote [--force] {pool}/{image}` | promote 单个 image |
|
||
| `rbd mirror pool promote [--force] {pool}` | promote pool 内所有 non-primary image |
|
||
| `rbd mirror image resync {pool}/{image}` | 标记 image 需要 resync |
|
||
| `rbd mirror image status {pool}/{image}` | 查看 image 镜像状态 |
|
||
| `rbd mirror pool status {pool} [--verbose]` | 查看 pool 镜像汇总状态 |
|
||
|
||
---
|
||
|
||
## 十一、配置参考(rbd-config-ref)
|
||
|
||
> 引自:[Config Settings](https://docs.ceph.com/en/tentacle/rbd/rbd-config-ref/)
|
||
|
||
> 📌 说明:`rbd-config-ref.rst` 中的 `.. confval::` 指令在源文里**只有配置项名,没有默认值**(默认值由构建期从 `src/common/options/*.yaml.in` 生成)。本章所有"默认值"均标注了来源。凡在 `*.yaml.in` 中也找不到 `default:` 字段的,一律写「文档未明确」。
|
||
>
|
||
> RBD 的选项应设置在配置文件的 **`[client]`** 段,或 central config store 中。
|
||
|
||
### 11.1 Generic IO Settings
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_compression_hint` | str | `none` | 写操作时发给 OSD 的压缩提示。设为 `compressible` 且 OSD `bluestore_compression_mode` 为 `passive` 时,OSD 会尝试压缩;设为 `incompressible` 且 OSD 压缩设置为 `aggressive` 时,OSD 不会尝试压缩。枚举:`none` / `compressible` / `incompressible`。(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`;`flags: runtime`) | 配合 OSD 侧压缩策略使用;默认 `none` |
|
||
| `rbd_read_from_replica_policy` | str | `default` | 决定哪个 OSD 接收读操作的策略。`default`:始终用每个 PG 的 primary OSD;`balance`:发给副本集中随机选出的 OSD;`localize`:发给 CRUSH map 判定的最近 OSD。与 `rbd_balance_snap_reads` / `rbd_localize_snap_reads` / `rbd_balance_parent_reads` / `rbd_localize_parent_reads` 不同,它影响**所有**读操作,而不仅是 snap 或 parent。**要求集群 `minimum compatible OSD release` 为 Octopus。** 枚举:`default` / `balance` / `localize`。(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`;`flags: runtime`) | 读多副本分散可设 `balance`;跨机架/跨 AZ 降延迟可设 `localize` |
|
||
| `rbd_default_order` | uint | `22` | 新建 image 的默认 order(数据块 object size)。以 2 为底取幂:`default_object_size = 2 ^ rbd_default_order`。可配 12–25,即 4KiB–32MiB。默认 2^22 = **4MiB**。(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`) | 大顺序 IO 可增大到 23/24(8/16MiB);小随机 IO 保持 22 |
|
||
|
||
### 11.2 Cache Settings(逐项,详见第七章)
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_cache` | bool | `true` | 是否启用缓存(writeback,除非 `rbd_cache_max_dirty` 为 0) | 默认开启;跑 GFS/OCFS 必须关闭 |
|
||
| `rbd_cache_policy` | str | `writearound` | 处理写的缓存策略:`writethrough` / `writeback` / `writearound` | 需读命中改为 `writeback` |
|
||
| `rbd_cache_writethrough_until_flush` | bool | `true` | 收到 flush 前以 writethrough 方式工作 | 保持 `true` |
|
||
| `rbd_cache_size` | size | `32_M` | 每个卷的 RBD 客户端缓存大小 | 内存充裕可增大 |
|
||
| `rbd_cache_max_dirty` | size | `24_M` | 触发 write-back 的 dirty 上限;`0` = write-through | 必须小于 `rbd_cache_size` |
|
||
| `rbd_cache_target_dirty` | size | `16_M` | 开始写回的 dirty target | 必须小于 `rbd_cache_max_dirty` |
|
||
| `rbd_cache_max_dirty_age` | float | `1` | 脏数据在缓存中停留多少秒后开始 writeback | 低延迟场景可调小 |
|
||
| `rbd_cache_max_dirty_object` | uint | `0` | 对象级脏数据上限;`0` = 由 `rbd_cache_size` 自动计算 | 保持 `0` |
|
||
| `rbd_cache_block_writes_upfront` | bool | `false` | 是否在 `aio_write` 完成前阻塞对缓存的写 | 保持 `false` |
|
||
|
||
(后两项来自 `src/common/options/rbd.yaml.in @ v20.2.4`,`rbd-config-ref.rst` 未列出;前七项为 `rbd-config-ref.rst` 明确列出)
|
||
|
||
### 11.3 Read-ahead Settings(逐项,详见第七章)
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_readahead_trigger_requests` | uint | `10` | 触发 readahead 所需的连续请求数 | 默认即可 |
|
||
| `rbd_readahead_max_bytes` | size | `512_K` | 单次 read-ahead 请求的最大大小;`0` = 禁用 read-ahead | 顺序读场景可增大 |
|
||
| `rbd_readahead_disable_after_bytes` | size | `50_M` | 累计读取多少字节后禁用该 image 的 read-ahead(关闭再打开重置);`0` = 一直启用 | 默认 `50_M`(让 guest OS 启动后接管) |
|
||
|
||
### 11.4 Image Features
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_default_features` | str | `layering,exclusive-lock,object-map,fast-diff,deep-flatten` | 新建 v2 image 的默认 feature 集合。接受**整型 bitmask**或**逗号分隔的 feature 名列表**;内部始终以整型 bitmask 存储。映射:+1 layering、+2 striping、+4 exclusive-lock、+8 object-map、+16 fast-diff、+32 deep-flatten、+64 journaling、+128 data-pool(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`;`flags: runtime`) | 需要默认开启 journaling 时设为 `125`(官方 Tip) |
|
||
|
||
feature 逐项说明见第二章 2.10 全表。
|
||
|
||
### 11.5 Clone Settings
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_default_clone_format` | str | `auto` | 处理克隆的内部格式。`1`:必须挂到受保护快照上;`2`:可挂到任意快照、允许删除在用父快照,但要求 Mimic+ 客户端;`auto`:集群要求 Mimic+ 客户端时用 v2。枚举:`1` / `2` / `auto`(默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`;`flags: runtime`) | 保持 `auto` |
|
||
| `rbd_clone_copy_on_read` | bool | `false` | 读请求时把父 image 块 copy-up 到克隆 | 读密集型 VDI 可考虑开启,但会增加空间占用 |
|
||
|
||
### 11.6 QoS Settings(逐项)
|
||
|
||
librbd 支持以多种方式限制**单 image 的 IO**。这些限制**作用于给定进程内的给定 image**——同一个 image 在多个地方使用(例如两个独立 VM)会有**相互独立**的限制。
|
||
|
||
限制维度:
|
||
|
||
| 维度 | 说明 |
|
||
|---|---|
|
||
| IOPS | 每秒 I/O 数(任意类型) |
|
||
| read IOPS | 每秒读 I/O 数 |
|
||
| write IOPS | 每秒写 I/O 数 |
|
||
| bps | 每秒字节数(任意类型) |
|
||
| read bps | 每秒读取字节数 |
|
||
| write bps | 每秒写入字节数 |
|
||
|
||
- 每种限制**相互独立**;**全部默认关闭**;
|
||
- 所有类型的限制都使用 **token bucket(令牌桶)算法**限速,可配置限制值(一段时间内的平均速度)与短时间内的更高突发速率(`burst_seconds`);
|
||
- 达到任一限制且突发额度用尽时,librbd 会把该类型 IO 的速率降到限制值;
|
||
- 示例(官方原文):若配置了 100MB 的 read bps 限制而写未限流,则写可以尽可能快,而读平均被限到 100MB/s。若 read bps burst 设为 150MB 且 read burst seconds 设为 5 秒,则读可以以 150MB/s 持续最多 5 秒,然后回落到 100MB/s 的限制。
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_qos_iops_limit` | uint | `0` | 期望的每秒 IO 操作数上限 | `0` = 不限 |
|
||
| `rbd_qos_iops_burst` | uint | `0` | 期望的 IO 操作突发上限 | `0` = 无突发 |
|
||
| `rbd_qos_iops_burst_seconds` | uint | `1`(min: 1) | 期望的 IO 操作突发持续秒数 | 默认 `1` |
|
||
| `rbd_qos_read_iops_limit` | uint | `0` | 期望的每秒读操作上限 | `0` = 不限 |
|
||
| `rbd_qos_read_iops_burst` | uint | `0` | 期望的读操作突发上限 | `0` |
|
||
| `rbd_qos_read_iops_burst_seconds` | uint | `1`(min: 1) | 期望的读操作突发持续秒数 | 默认 `1` |
|
||
| `rbd_qos_write_iops_limit` | uint | `0` | 期望的每秒写操作上限 | `0` = 不限 |
|
||
| `rbd_qos_write_iops_burst` | uint | `0` | 期望的写操作突发上限 | `0` |
|
||
| `rbd_qos_write_iops_burst_seconds` | uint | `1`(min: 1) | 期望的写操作突发持续秒数 | 默认 `1` |
|
||
| `rbd_qos_bps_limit` | uint | `0` | 期望的每秒 IO 字节数上限 | `0` = 不限 |
|
||
| `rbd_qos_bps_burst` | uint | `0` | 期望的 IO 字节突发上限 | `0` |
|
||
| `rbd_qos_bps_burst_seconds` | uint | `1`(min: 1) | 期望的 IO 字节突发持续秒数 | 默认 `1` |
|
||
| `rbd_qos_read_bps_limit` | uint | `0` | 期望的每秒读取字节数上限 | `0` = 不限 |
|
||
| `rbd_qos_read_bps_burst` | uint | `0` | 期望的读取字节突发上限 | `0` |
|
||
| `rbd_qos_read_bps_burst_seconds` | uint | `1`(min: 1) | 期望的读取字节突发持续秒数 | 默认 `1` |
|
||
| `rbd_qos_write_bps_limit` | uint | `0` | 期望的每秒写入字节数上限 | `0` = 不限 |
|
||
| `rbd_qos_write_bps_burst` | uint | `0` | 期望的写入字节突发上限 | `0` |
|
||
| `rbd_qos_write_bps_burst_seconds` | uint | `1`(min: 1) | 期望的写入字节突发持续秒数 | 默认 `1` |
|
||
| `rbd_qos_schedule_tick_min` | uint | `50`(min: 1) | QoS 的最小调度 tick(毫秒)。决定命中限流后 IO 能被解除阻塞的最小时间间隔;用令牌桶的术语说,就是向桶中添加令牌的最小间隔 | 默认 `50` |
|
||
| `rbd_qos_exclude_ops` | str | **文档未明确**(`rbd.yaml.in` 中无 `default:` 字段) | 可选地把某些 op 排除在 QoS 之外。接受整型 bitmask 或逗号分隔的 op 名列表;内部以 bitmask 存储。映射:+1 read、+2 write、+4 discard、+8 write_same、+16 compare_and_write(`flags: runtime`) | 例如只限读写、不限 discard 时可用 |
|
||
|
||
(以上默认值取自 `src/common/options/rbd.yaml.in @ v20.2.4`)
|
||
|
||
### 11.7 默认参数与 image 布局(来自 `rbd.yaml.in`)
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_default_pool` | str | `rbd` | 存放新建 image 的默认 pool。校验规则:不含 `@` 与 `/`,否则重置为 `rbd` | 建议按业务建独立 pool |
|
||
| `rbd_default_data_pool` | str | **文档未明确**(无 `default:` 字段;validator 在非法值时置为空串) | 存放新建 image 数据块的默认 pool | 纠删码场景配置 |
|
||
| `rbd_default_format` | uint | `2` | 新建 image 的默认 image format | 保持 `2`(format 1 不支持克隆) |
|
||
| `rbd_default_stripe_count` | uint | `0` | 新建 image 的默认 stripe count | 见第二章 |
|
||
| `rbd_default_stripe_unit` | size | `0` | 新建 image 的默认 stripe width | 见第二章 |
|
||
| `rbd_default_map_options` | str | **文档未明确**(无 `default:` 字段) | 默认 krbd map options | 需要统一 krbd 挂载参数时配置 |
|
||
| `rbd_default_snapshot_quiesce_mode` | str | `required` | 默认的快照 quiesce 模式;枚举:`required` / `ignore-error` / `skip` | 无法安装 qemu-guest-agent 的环境可考虑 `skip`/`ignore-error` |
|
||
| `rbd_op_threads` | uint | `1` | 用于内部处理的线程数 | 大并发场景可增大 |
|
||
| `rbd_op_thread_timeout` | uint | `60` | 检测线程挂起的秒数 | 默认即可 |
|
||
| `rbd_concurrent_management_ops` | uint | `10`(min: 1) | 删除或 resize image 等管理类操作的最大在途数量 | 大批量运维可增大 |
|
||
| `rbd_plugins` | str | **文档未明确**(无 `default:` 字段) | 逗号分隔的、要启用的 librbd 插件列表 | 只读父缓存用 `parent_cache`;PWL 用 `pwl_cache` |
|
||
|
||
### 11.8 读路径 / 稀疏读 / discard 相关
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_balance_snap_reads` | bool | `false` | 把 snap 读请求分发到随机 OSD | 与 `rbd_read_from_replica_policy` 二选一思路;后者更通用 |
|
||
| `rbd_localize_snap_reads` | bool | `false` | 把 snap 读请求定位到最近的 OSD | 同上 |
|
||
| `rbd_balance_parent_reads` | bool | `false` | 把 parent 读请求分发到随机 OSD | 同上 |
|
||
| `rbd_localize_parent_reads` | bool | `false` | 把 parent 请求定位到最近的 OSD | 同上 |
|
||
| `rbd_sparse_read_threshold_bytes` | size | `64_K` | 触发 sparse-read 的阈值:对某个对象连续读取达到该字节数才向集群发 sparse-read 请求。`0` 表示必须是整对象读才发;`1` 表示总是用 sparse-read;任何大于最大 object size 的值会禁用所有请求的 sparse-read | 默认即可 |
|
||
| `rbd_skip_partial_discard` | bool | `true` | 跳过对 object 内未对齐区段的 discard(zero) | 保持 `true`,避免小块 RMW |
|
||
| `rbd_discard_granularity_bytes` | uint | `64_K`(min: `4_K`,max: `32_M`) | discard 操作的最小对齐大小 | **必须是 2 的幂**(validator 强制) |
|
||
| `rbd_discard_on_zeroed_write_same` | bool | `true` | 对 zeroed write same,执行 discard 而不是写零 | 保持 `true` |
|
||
| `rbd_enable_alloc_hint` | bool | `true` | 写对象时向 OSD 后端发出预期对象大小的提示 | 保持 `true` |
|
||
| `rbd_disable_zero_copy_writes` | bool | `true` | 禁用零拷贝写,以确保客户端的不稳定写不会引起 CRC 不匹配 | 保持 `true` |
|
||
| `rbd_non_blocking_aio` | bool | `true` | 从 dispatch 线程处理 AIO 操作以避免阻塞 | 保持 `true` |
|
||
|
||
### 11.9 Trash 相关
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_move_to_trash_on_remove` | bool | `false` | 删除 image 时自动移入 trash | 生产建议开启,防误删 |
|
||
| `rbd_move_to_trash_on_remove_expire_seconds` | uint | `0` | 已删除 image 在 trash 中的默认保护秒数 | 与上一项配合设置一个宽限期 |
|
||
| `rbd_move_parent_to_trash_on_remove` | bool | `false` | 删除时把带有 clone format v2 子 image 的 parent 也移入 trash | 使用大量克隆的环境建议开启 |
|
||
|
||
### 11.10 时间戳与 IO 调度
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_mtime_update_interval` | uint | `60`(min: 0) | RBD image modify timestamp 刷新间隔(秒);`0` = 禁用 modify timestamp 更新 | 默认即可 |
|
||
| `rbd_atime_update_interval` | uint | `60`(min: 0) | RBD image access timestamp 刷新间隔(秒);`0` = 禁用 access timestamp 更新 | 不需要 atime 时设 `0` 可省开销 |
|
||
| `rbd_io_scheduler` | str | `simple` | RBD IO 调度器;枚举:`none` / `simple` | 默认即可 |
|
||
| `rbd_io_scheduler_simple_max_delay` | uint | `0`(min: 0) | simple io scheduler 的最大 IO 延迟(毫秒);设为 `0` 时延迟基于延迟统计计算 | 默认 `0` |
|
||
|
||
### 11.11 排障与调试相关
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 | 建议 |
|
||
|---|---|---|---|---|
|
||
| `rbd_tracing` | bool | `false` | 是否启用 LTTng-UST tracepoints | 排障时临时开启 |
|
||
| `rbd_blkin_trace_all` | bool | `false` | 为所有 RBD 请求创建 blkin trace | 排障时临时开启 |
|
||
| `rbd_validate_pool` | bool(dev 级) | `true` | 校验空 pool 是否与 RBD 兼容 | 保持 `true` |
|
||
| `rbd_validate_names` | bool | `true` | 校验新 image 名是否与 RBD 兼容 | 保持 `true` |
|
||
| `rbd_invalidate_object_map_on_timeout` | bool(dev 级) | `true` | 加载或更新超时时是否使 object map 失效 | 保持 `true` |
|
||
| `rbd_auto_exclusive_lock_until_manual_request` | bool | `true` | 在显式请求之前自动获取/释放 exclusive lock | 保持 `true` |
|
||
| `rbd_blocklist_on_break_lock` | bool | `true` | 锁被打破时是否 blocklist 对应客户端 | 保持 `true` |
|
||
| `rbd_blocklist_expire_seconds` | uint | `0` | blocklist 持续秒数;`0` = 使用 OSD 默认值(`mon_osd_blocklist_default_expire`,默认 `1_hr`,取自 `src/common/options/mon.yaml.in @ v20.2.4`) | 一般保持 `0` |
|
||
| `rbd_request_timed_out_seconds` | uint | `30` | 维护类请求超时秒数 | 大集群/慢网络可增大 |
|
||
| `rbd_quiesce_notification_attempts` | uint(dev 级) | `10`(min: 1) | quiesce 通知的尝试次数 | 默认即可 |
|
||
| `rbd_config_pool_override_update_timestamp` | uint(dev 级) | `0` | pool 级配置覆盖的最近更新时间戳 | 内部使用 |
|
||
|
||
### 11.12 Persistent Write Log Cache 配置项(详见第七章)
|
||
|
||
| 配置项 | 类型 | 默认值 | 含义 |
|
||
|---|---|---|---|
|
||
| `rbd_persistent_cache_mode` | str | `disabled` | 持久 write-back 缓存模式;枚举:`disabled` / `rwl` / `ssd` |
|
||
| `rbd_persistent_cache_size` | uint | `1_G`(min: `1_G`) | 每个 image 的持久 write-back 缓存大小 |
|
||
| `rbd_persistent_cache_path` | str | `/tmp` | 持久 write-back 缓存位置(rwl 模式需在 DAX 启用文件系统上) |
|
||
|
||
### 11.13 索引:其他章节已列的配置项
|
||
|
||
| 类别 | 章节 |
|
||
|---|---|
|
||
| exclusive lock / blocklist | 第六章 6.5 |
|
||
| immutable object cache(守护进程 + QoS) | 第七章 7.2 |
|
||
| journal(mirroring 用) | 第十章 10.10 |
|
||
| mirroring(`rbd.yaml.in` 部分) | 第十章 10.10 |
|
||
| `rbd-mirror` 守护进程(`rbd-mirror.yaml.in`) | 第十章 10.10 |
|
||
|
||
---
|
||
|
||
## 十二、平台与集成
|
||
|
||
### 12.1 QEMU / KVM
|
||
|
||
> 引自:[QEMU and Block Devices](https://docs.ceph.com/en/tentacle/rbd/qemu-rbd/)
|
||
|
||
最常见的 Ceph Block Device 使用场景是给虚拟机提供块设备 image:用户创建一个装有 OS 与相关软件的 "golden" image,对其打快照,然后(可能多次)克隆该快照。**能够创建快照的 COW 克隆,意味着 Ceph 可以快速地为虚拟机供给块设备 image**,因为客户端每次启动新虚拟机时不必下载整个 image。
|
||
|
||
```text
|
||
+---------------------------------------------------+
|
||
| QEMU |
|
||
+---------------------------------------------------+
|
||
| librbd |
|
||
+---------------------------------------------------+
|
||
| librados |
|
||
+------------------------+-+------------------------+
|
||
| OSDs | | Monitors |
|
||
+------------------------+ +------------------------+
|
||
```
|
||
|
||
#### 用法格式
|
||
|
||
```bash
|
||
qemu-img {command} [options] rbd:{pool-name}/{image-name}[@snapshot-name][:option1=value1][:option2=value2...]
|
||
```
|
||
|
||
- QEMU 假定 Ceph 配置位于默认位置(如 `/etc/ceph/$cluster.conf`),且以默认 `client.admin` 用户执行,除非显式指定其他配置文件路径或其他用户;
|
||
- 指定用户时,QEMU 使用 **`ID`** 而不是完整的 `TYPE:ID`。**不要**在用户 `ID` 前面加客户端类型(即 `client.`),否则会收到认证错误;
|
||
- 应把 `admin` 用户的 key(或你用 `:id={user}` 指定的其他用户的 key)放在默认路径(`/etc/ceph` 或本地目录)的 keyring 文件中,并设好属主与权限。
|
||
|
||
```bash
|
||
qemu-img {command} [options] rbd:glance-pool/maipo:id=glance:conf=/etc/ceph/ceph.conf
|
||
```
|
||
|
||
> Tip:包含 `:`、`@` 或 `=` 的配置值可以用前导 `\` 字符转义。
|
||
|
||
#### 创建 image
|
||
|
||
```bash
|
||
qemu-img create -f raw rbd:{pool-name}/{image-name} {size}
|
||
qemu-img create -f raw rbd:data/foo 10G
|
||
```
|
||
|
||
> ⚠️ 官方 important:**`raw` 数据格式实际上是配合 RBD 唯一合理的 `format` 选项。** 技术上你可以使用其他 QEMU 支持的格式(如 `qcow2` 或 `vmdk`),但那会带来额外开销,并且在启用缓存(见下)时会使卷对虚拟机实时迁移**不安全**。
|
||
|
||
#### 调整大小
|
||
|
||
```bash
|
||
qemu-img resize rbd:{pool-name}/{image-name} {size}
|
||
qemu-img resize rbd:data/foo 10G
|
||
```
|
||
|
||
#### 查看信息
|
||
|
||
```bash
|
||
qemu-img info rbd:{pool-name}/{image-name}
|
||
qemu-img info rbd:data/foo
|
||
```
|
||
|
||
#### 用 RBD 运行 QEMU
|
||
|
||
QEMU 可以把主机的块设备透传给 guest,但**自 QEMU 0.15 起,不再需要把 image 映射为主机上的块设备**——QEMU 通过 `librbd` 直接把 image 作为虚拟块设备挂上。这种策略通过避免上下文切换并利用 RBD caching 提升了性能。
|
||
|
||
```bash
|
||
# 把既有虚拟机镜像转换为 Ceph 块设备 image
|
||
qemu-img convert -f qcow2 -O raw debian_squeeze.qcow2 rbd:data/squeeze
|
||
|
||
# 从该 image 启动虚拟机
|
||
qemu -m 1024 -drive format=raw,file=rbd:data/squeeze
|
||
|
||
# 自 QEMU 1.2 起,QEMU 的 cache 选项控制 librbd 缓存
|
||
qemu -m 1024 -drive format=rbd,file=rbd:data/squeeze,cache=writeback
|
||
|
||
# 老版本 QEMU:把 librbd 缓存配置作为 'file' 参数的一部分传入
|
||
qemu -m 1024 -drive format=raw,file=rbd:data/squeeze:rbd_cache=true,cache=writeback
|
||
```
|
||
|
||
> ⚠️ 官方 important:如果设置了 `rbd_cache=true`,**必须**设置 `cache=writeback`,否则有数据丢失风险。没有 `cache=writeback` 时,QEMU 不会向 librbd 发送 flush 请求;在这种配置下如果 QEMU 非正常退出,rbd 之上的文件系统**可能损坏**。
|
||
|
||
#### 启用 Discard / TRIM
|
||
|
||
自 **Ceph 0.46** 与 **QEMU 1.1** 起,Ceph Block Devices 支持 discard 操作:guest 可以发送 TRIM 请求让 Ceph 块设备回收未使用空间。
|
||
|
||
- 在 guest 中通过以 `discard` 选项挂载 `ext4` 或 `XFS` 启用;
|
||
- 要对块设备可用,必须**显式启用**:为驱动器指定 `discard_granularity`:
|
||
|
||
```bash
|
||
qemu -m 1024 -drive format=raw,file=rbd:data/squeeze,id=drive1,if=none \
|
||
-device driver=ide-hd,drive=drive1,discard_granularity=512
|
||
```
|
||
|
||
> 注意:上面使用的是 IDE 驱动。**virtio 驱动自 Linux kernel 5.0 起支持 discard。**
|
||
|
||
使用 libvirt 时,用 `virsh edit` 编辑 libvirt domain 配置,加入 `xmlns:qemu`,然后在 domain 下加一个 `qemu:commandline` 块。以下示例把两个设备的 `qemu id=` 设为不同的 `discard_granularity`:
|
||
|
||
```xml
|
||
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
|
||
<qemu:commandline>
|
||
<qemu:arg value='-set'/>
|
||
<qemu:arg value='block.scsi0-0-0.discard_granularity=4096'/>
|
||
<qemu:arg value='-set'/>
|
||
<qemu:arg value='block.scsi0-0-1.discard_granularity=65536'/>
|
||
</qemu:commandline>
|
||
</domain>
|
||
```
|
||
|
||
#### QEMU Cache Options 对应关系
|
||
|
||
| QEMU cache 选项 | 对应的 Ceph RBD Cache 设置 |
|
||
|---|---|
|
||
| `writeback` | `rbd_cache = true` |
|
||
| `writethrough` | `rbd_cache = true` + `rbd_cache_max_dirty = 0` |
|
||
| `none` | `rbd_cache = false` |
|
||
|
||
> **QEMU 的 cache 设置会覆盖 Ceph 的 cache 设置**(包括在 Ceph 配置文件中显式设置的项)。
|
||
>
|
||
> 官方 note:**QEMU v2.4.0 之前**,如果你在 Ceph 配置文件中显式设置了 RBD Cache 设置,**Ceph 的设置会覆盖 QEMU 的 cache 设置**。
|
||
|
||
### 12.2 libvirt
|
||
|
||
> 引自:[Using libvirt with Ceph RBD](https://docs.ceph.com/en/tentacle/rbd/libvirt/)
|
||
|
||
`libvirt` 库在 hypervisor 接口与使用它们的软件之间创建了一层虚拟机抽象层,让开发者与系统管理员可以专注于一套通用的管理框架、通用 API 与通用 shell 接口(`virsh`),支持 QEMU/KVM、XEN、LXC、VirtualBox 等。
|
||
|
||
```text
|
||
+---------------------------------------------------+
|
||
| libvirt |
|
||
+------------------------+--------------------------+
|
||
| configures
|
||
v
|
||
+---------------------------------------------------+
|
||
| QEMU |
|
||
+---------------------------------------------------+
|
||
| librbd |
|
||
+---------------------------------------------------+
|
||
| librados |
|
||
+------------------------+-+------------------------+
|
||
| OSDs | | Monitors |
|
||
+------------------------+ +------------------------+
|
||
```
|
||
|
||
Ceph 块设备支持 QEMU/KVM。最常见的 libvirt 用例是为 OpenStack、OpenNebula 或 CloudStack 等云方案提供 Ceph 块设备:云方案用 `libvirt` 与 QEMU/KVM 交互,QEMU/KVM 通过 `librbd` 与 Ceph 块设备交互。
|
||
|
||
> 示例约定:pool 名 `libvirt-pool`、用户名 `client.libvirt`、image 名 `new-libvirt-image`。你可以用任意值,但在执行后续命令时要替换。
|
||
|
||
#### 配置 Ceph
|
||
|
||
```bash
|
||
# 1) 创建 pool
|
||
ceph osd pool create libvirt-pool
|
||
ceph osd lspools # 校验
|
||
|
||
# 2) 用 rbd 工具初始化该 pool 供 RBD 使用
|
||
rbd pool init <pool-name>
|
||
|
||
# 3) 创建 Ceph 用户(0.9.7 及更早版本可用 client.admin)
|
||
ceph auth get-or-create client.libvirt mon 'profile rbd' osd 'profile rbd pool=libvirt-pool'
|
||
ceph auth ls # 校验
|
||
|
||
# 4) 用 QEMU 在 RBD pool 中创建 image
|
||
qemu-img create -f rbd rbd:libvirt-pool/new-libvirt-image 2G
|
||
rbd -p libvirt-pool ls # 校验
|
||
```
|
||
|
||
> **NOTE**:`libvirt` 访问 Ceph 时使用的是 **ID `libvirt`**,而不是 Ceph 名 `client.libvirt`。
|
||
>
|
||
> **NOTE**:也可以用 `rbd create` 创建 image,但官方建议用 QEMU 创建,以便顺便确认 QEMU 工作正常。
|
||
|
||
> 💡 Tip(可选):为这个客户端启用 debug 日志与 admin socket,可在 `/etc/ceph/ceph.conf` 中加入:
|
||
|
||
```ini
|
||
[client.libvirt]
|
||
log file = /var/log/ceph/qemu-guest-$pid.log
|
||
admin socket = /var/run/ceph/$cluster-$type.$id.$pid.$cctid.asok
|
||
```
|
||
|
||
> `client.libvirt` 段名应与上面创建的 cephx 用户匹配。若启用了 **SELinux 或 AppArmor**,可能阻止客户端进程(qemu via libvirt)执行某些操作,如写日志、操作 image 或把 admin socket 放到目标位置(`/var/log/ceph` 或 `/var/run/ceph`)。另外要确保 libvirt 与 qemu 用户对指定目录有适当访问权限。
|
||
|
||
#### 准备 VM Manager
|
||
|
||
```bash
|
||
sudo apt-get install virt-manager # 安装虚拟机管理器
|
||
sudo virt-manager # 启动
|
||
```
|
||
|
||
#### 创建 VM(virt-manager)
|
||
|
||
1. 按 **Create New Virtual Machine** 按钮;
|
||
2. 命名新的虚拟机 domain(示例用 `libvirt-virtual-machine`);
|
||
3. 导入 image(`/path/to/image/recent-linux.img`)。**NOTE:导入较新的 image,某些较老的 image 可能无法正确重新扫描虚拟设备;**
|
||
4. 配置并启动 VM;
|
||
5. 可用 `virsh list` 校验 VM domain 存在:`sudo virsh list`;
|
||
6. 登录 VM(root/root);
|
||
7. **在为 Ceph 配置 VM 之前先停止 VM**。
|
||
|
||
#### 配置 VM(virsh)
|
||
|
||
```bash
|
||
sudo virsh edit {vm-domain-name}
|
||
```
|
||
|
||
`<devices>` 下应有一个 `<disk>` 条目:
|
||
|
||
```xml
|
||
<devices>
|
||
<emulator>/usr/bin/kvm</emulator>
|
||
<disk type='file' device='disk'>
|
||
<driver name='qemu' type='raw'/>
|
||
<source file='/path/to/image/recent-linux.img'/>
|
||
<target dev='vda' bus='virtio'/>
|
||
<address type='drive' controller='0' bus='0' unit='0'/>
|
||
</disk>
|
||
```
|
||
|
||
> 使用更快的 `virtio` 总线所需的最低内核是 **2.6.25**。
|
||
>
|
||
> **IMPORTANT:必须使用 `sudo virsh edit`,不要用文本编辑器。** 如果用文本编辑器修改 `/etc/libvirt/qemu` 下的配置文件,libvirt 可能识别不到变更。如果 `/etc/libvirt/qemu` 下 XML 文件的内容与 `sudo virsh dumpxml {vm-domain-name}` 的结果不一致,你的 VM 可能无法正常工作。
|
||
|
||
**添加 Ceph RBD image 作为 `<disk>`:**
|
||
|
||
```xml
|
||
<disk type='network' device='disk'>
|
||
<source protocol='rbd' name='libvirt-pool/new-libvirt-image'>
|
||
<host name='{monitor-host}' port='6789'/>
|
||
</source>
|
||
<target dev='vdb' bus='virtio'/>
|
||
</disk>
|
||
```
|
||
|
||
- 把 `{monitor-host}` 换成你的主机名,必要时替换 pool 名与 image 名;
|
||
- 可以为你的 Ceph monitor 添加**多个 `<host>`** 条目;
|
||
- `dev` 属性是 VM 内 `/dev` 下出现的逻辑设备名;
|
||
- 可选的 `bus` 属性表示要模拟的磁盘设备类型,有效取值由驱动决定(如 `ide`、`scsi`、`virtio`、`xen`、`usb`、`sata`)。
|
||
|
||
#### 认证配置(secret)
|
||
|
||
如果 Ceph Storage Cluster 启用了 **Ceph Authentication**(默认启用),必须生成一个 secret:
|
||
|
||
```bash
|
||
# 1) 定义 secret
|
||
cat > secret.xml <<EOF
|
||
<secret ephemeral='no' private='no'>
|
||
<usage type='ceph'>
|
||
<name>client.libvirt secret</name>
|
||
</usage>
|
||
</secret>
|
||
EOF
|
||
|
||
sudo virsh secret-define --file secret.xml
|
||
{uuid of secret}
|
||
|
||
# 2) 取 client.libvirt 的 key 并保存到文件
|
||
ceph auth get-key client.libvirt | sudo tee client.libvirt.key
|
||
|
||
# 3) 设置 secret 的值
|
||
sudo virsh secret-set-value --secret {uuid of secret} --base64 $(cat client.libvirt.key) && rm client.libvirt.key secret.xml
|
||
```
|
||
|
||
**还必须在之前添加的 `<disk>` 元素中手工加入 `<auth>` 条目**(把 `uuid` 换成上一条命令的输出):
|
||
|
||
```bash
|
||
sudo virsh edit {vm-domain-name}
|
||
```
|
||
|
||
```xml
|
||
...
|
||
</source>
|
||
<auth username='libvirt'>
|
||
<secret type='ceph' uuid='{uuid of secret}'/>
|
||
</auth>
|
||
<target ...
|
||
```
|
||
|
||
> **NOTE**:示例中的 ID 是 `libvirt`,不是创建用户时的 Ceph 名 `client.libvirt`。务必使用你生成的 Ceph 名的 **ID 部分**。
|
||
> 如果因某种原因需要重新生成 secret,必须先执行 `sudo virsh secret-undefine {uuid}`,再执行 `sudo virsh secret-set-value`。
|
||
|
||
#### 校验
|
||
|
||
```bash
|
||
ceph health # Ceph 是否健康
|
||
sudo virsh list # VM 是否运行
|
||
sudo virsh qemu-monitor-command --hmp {vm-domain-name} 'info block' # VM 是否与 Ceph 通信
|
||
virsh domblklist {vm-domain-name} --details # 设备是否存在
|
||
```
|
||
|
||
### 12.3 Kubernetes
|
||
|
||
> 引自:[Block Devices and Kubernetes](https://docs.ceph.com/en/tentacle/rbd/rbd-kubernetes/)
|
||
|
||
可以通过 **`ceph-csi`** 在 **Kubernetes v1.13 及更高版本**中使用 Ceph Block Device image。`ceph-csi` 动态供给 RBD image 来支撑 Kubernetes `volumes`,并把这些 RBD image 映射为块设备(可选地挂载 image 内的文件系统)到运行引用该 RBD 支撑卷的 `pods` 的 worker 节点上。Ceph 把块设备 image 条带化为跨集群的对象,这意味着**大的 Ceph Block Device image 性能优于独立服务器**。
|
||
|
||
```text
|
||
+---------------------------------------------------+
|
||
| Kubernetes |
|
||
+---------------------------------------------------+
|
||
| ceph--csi |
|
||
+------------------------+--------------------------+
|
||
| configures
|
||
v
|
||
+------------------------+ +------------------------+
|
||
| | | rbd--nbd |
|
||
| Kernel Modules | +------------------------+
|
||
| | | librbd |
|
||
+------------------------+-+------------------------+
|
||
| RADOS Protocol |
|
||
+------------------------+-+------------------------+
|
||
| OSDs | | Monitors |
|
||
+------------------------+ +------------------------+
|
||
```
|
||
|
||
> ⚠️ 官方 important:**`ceph-csi` 默认使用 RBD 内核模块,而它可能无法支持所有的 Ceph CRUSH tunables 或 RBD image features。**
|
||
|
||
#### 创建 Pool
|
||
|
||
```bash
|
||
$ ceph osd pool create kubernetes
|
||
$ rbd pool init kubernetes
|
||
```
|
||
|
||
#### 配置 ceph-csi
|
||
|
||
**1) 创建 Ceph 客户端认证用户**
|
||
|
||
```bash
|
||
$ ceph auth get-or-create client.kubernetes mon 'profile rbd' osd 'profile rbd pool=kubernetes' mgr 'profile rbd pool=kubernetes'
|
||
[client.kubernetes]
|
||
key = AQD9o0Fd6hQRChAAt7fMaSZXduT3NWEqylNpmg==
|
||
```
|
||
|
||
**2) 生成 `ceph-csi` ConfigMap(集群 MON 地址)**
|
||
|
||
先收集 fsid 与 monitor 地址:
|
||
|
||
```bash
|
||
$ ceph mon dump
|
||
<...>
|
||
fsid b9127830-b0cc-4e34-aa47-9d1a2e9949a8
|
||
<...>
|
||
0: [v2:192.168.1.1:3300/0,v1:192.168.1.1:6789/0] mon.a
|
||
1: [v2:192.168.1.2:3300/0,v1:192.168.1.2:6789/0] mon.b
|
||
2: [v2:192.168.1.3:3300/0,v1:192.168.1.3:6789/0] mon.c
|
||
```
|
||
|
||
> 官方 note:**`ceph-csi` 目前仅支持 legacy V1 protocol。**
|
||
|
||
```yaml
|
||
---
|
||
apiVersion: v1
|
||
kind: ConfigMap
|
||
data:
|
||
config.json: |-
|
||
[
|
||
{
|
||
"clusterID": "b9127830-b0cc-4e34-aa47-9d1a2e9949a8",
|
||
"monitors": [
|
||
"192.168.1.1:6789",
|
||
"192.168.1.2:6789",
|
||
"192.168.1.3:6789"
|
||
]
|
||
}
|
||
]
|
||
metadata:
|
||
name: ceph-csi-config
|
||
```
|
||
|
||
```bash
|
||
$ kubectl apply -f csi-config-map.yaml
|
||
```
|
||
|
||
**3) KMS ConfigMap**(较新版本 `ceph-csi` 需要;未部署 KMS 时放空配置)
|
||
|
||
```yaml
|
||
---
|
||
apiVersion: v1
|
||
kind: ConfigMap
|
||
data:
|
||
config.json: |-
|
||
{}
|
||
metadata:
|
||
name: ceph-csi-encryption-kms-config
|
||
```
|
||
|
||
```bash
|
||
$ kubectl apply -f csi-kms-config-map.yaml
|
||
```
|
||
|
||
**4) ceph.conf ConfigMap**(注入 CSI 容器内的 ceph.conf)
|
||
|
||
```yaml
|
||
---
|
||
apiVersion: v1
|
||
kind: ConfigMap
|
||
data:
|
||
ceph.conf: |
|
||
[global]
|
||
auth_cluster_required = cephx
|
||
auth_service_required = cephx
|
||
auth_client_required = cephx
|
||
# keyring is a required key and its value should be empty
|
||
keyring: |
|
||
metadata:
|
||
name: ceph-config
|
||
```
|
||
|
||
```bash
|
||
$ kubectl apply -f ceph-config-map.yaml
|
||
```
|
||
|
||
**5) 生成 cephx Secret**
|
||
|
||
```yaml
|
||
---
|
||
apiVersion: v1
|
||
kind: Secret
|
||
metadata:
|
||
name: csi-rbd-secret
|
||
namespace: default
|
||
stringData:
|
||
userID: kubernetes
|
||
userKey: AQD9o0Fd6hQRChAAt7fMaSZXduT3NWEqylNpmg==
|
||
```
|
||
|
||
```bash
|
||
$ kubectl apply -f csi-rbd-secret.yaml
|
||
```
|
||
|
||
**6) 配置 ceph-csi 插件(RBAC + provisioner + node plugin)**
|
||
|
||
```bash
|
||
$ kubectl apply -f https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-provisioner-rbac.yaml
|
||
$ kubectl apply -f https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-nodeplugin-rbac.yaml
|
||
|
||
$ wget https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-rbdplugin-provisioner.yaml
|
||
$ kubectl apply -f csi-rbdplugin-provisioner.yaml
|
||
$ wget https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-rbdplugin.yaml
|
||
$ kubectl apply -f csi-rbdplugin.yaml
|
||
```
|
||
|
||
> ⚠️ 官方 important:provisioner 与 node plugin 的 YAML **默认会拉取 `ceph-csi` 容器的开发版(`quay.io/cephcsi/cephcsi:canary`)**。生产工作负载应把 YAML 更新为使用**发布版**容器。
|
||
|
||
#### 使用 Ceph Block Devices
|
||
|
||
**StorageClass**
|
||
|
||
```yaml
|
||
---
|
||
apiVersion: storage.k8s.io/v1
|
||
kind: StorageClass
|
||
metadata:
|
||
name: csi-rbd-sc
|
||
provisioner: rbd.csi.ceph.com
|
||
parameters:
|
||
clusterID: b9127830-b0cc-4e34-aa47-9d1a2e9949a8
|
||
pool: kubernetes
|
||
imageFeatures: layering
|
||
csi.storage.k8s.io/provisioner-secret-name: csi-rbd-secret
|
||
csi.storage.k8s.io/provisioner-secret-namespace: default
|
||
csi.storage.k8s.io/controller-expand-secret-name: csi-rbd-secret
|
||
csi.storage.k8s.io/controller-expand-secret-namespace: default
|
||
csi.storage.k8s.io/node-stage-secret-name: csi-rbd-secret
|
||
csi.storage.k8s.io/node-stage-secret-namespace: default
|
||
reclaimPolicy: Delete
|
||
allowVolumeExpansion: true
|
||
mountOptions:
|
||
- discard
|
||
```
|
||
|
||
```bash
|
||
$ kubectl apply -f csi-rbd-sc.yaml
|
||
```
|
||
|
||
> 注意:在 Kubernetes **v1.14 与 v1.15** 中,卷扩容特性处于 alpha 状态,需要启用 `ExpandCSIVolumes` feature gate。
|
||
|
||
**PersistentVolumeClaim —— volumeMode 与 accessMode 支持矩阵(官方原文)**
|
||
|
||
| `volumeMode` | 支持的 `accessMode` |
|
||
|---|---|
|
||
| `Filesystem` | `ReadWriteOnce`、`ReadOnlyMany` |
|
||
| `Block` | `ReadWriteOnce`、`ReadWriteMany`、`ReadOnlyMany` |
|
||
|
||
**raw block PVC + Pod**
|
||
|
||
```yaml
|
||
---
|
||
apiVersion: v1
|
||
kind: PersistentVolumeClaim
|
||
metadata:
|
||
name: raw-block-pvc
|
||
spec:
|
||
accessModes:
|
||
- ReadWriteOnce
|
||
volumeMode: Block
|
||
resources:
|
||
requests:
|
||
storage: 1Gi
|
||
storageClassName: csi-rbd-sc
|
||
```
|
||
|
||
```yaml
|
||
---
|
||
apiVersion: v1
|
||
kind: Pod
|
||
metadata:
|
||
name: pod-with-raw-block-volume
|
||
spec:
|
||
containers:
|
||
- name: fc-container
|
||
image: fedora:26
|
||
command: ["/bin/sh", "-c"]
|
||
args: ["tail -f /dev/null"]
|
||
volumeDevices:
|
||
- name: data
|
||
devicePath: /dev/xvda
|
||
volumes:
|
||
- name: data
|
||
persistentVolumeClaim:
|
||
claimName: raw-block-pvc
|
||
```
|
||
|
||
**filesystem PVC + Pod**
|
||
|
||
```yaml
|
||
---
|
||
apiVersion: v1
|
||
kind: PersistentVolumeClaim
|
||
metadata:
|
||
name: rbd-pvc
|
||
spec:
|
||
accessModes:
|
||
- ReadWriteOnce
|
||
volumeMode: Filesystem
|
||
resources:
|
||
requests:
|
||
storage: 1Gi
|
||
storageClassName: csi-rbd-sc
|
||
```
|
||
|
||
```yaml
|
||
---
|
||
apiVersion: v1
|
||
kind: Pod
|
||
metadata:
|
||
name: csi-rbd-demo-pod
|
||
spec:
|
||
containers:
|
||
- name: web-server
|
||
image: nginx
|
||
volumeMounts:
|
||
- name: mypvc
|
||
mountPath: /var/lib/www/html
|
||
volumes:
|
||
- name: mypvc
|
||
persistentVolumeClaim:
|
||
claimName: rbd-pvc
|
||
readOnly: false
|
||
```
|
||
|
||
> ⚠️ **文档未明确**:`rbd-kubernetes.rst` **没有**给出 Kubernetes 侧快照(`VolumeSnapshot`)与克隆(`dataSource` 指向 PVC)的官方示例 YAML。`ceph-csi` 支持这些能力,但不在本册源文范围内,故不在此给出具体清单,请查阅 `ceph-csi` 项目文档。
|
||
|
||
### 12.4 OpenStack
|
||
|
||
> 引自:[Block Devices and OpenStack](https://docs.ceph.com/en/tentacle/rbd/rbd-openstack/)
|
||
|
||
可以通过 `libvirt` 把 Ceph Block Device image 附加到 OpenStack 实例,`libvirt` 会把 QEMU 接口配置到 `librbd`。Ceph 把块卷条带化到集群内多个 OSD 上,这意味着**大卷的性能可以优于独立服务器上的本地驱动器**。
|
||
|
||
前置:必须安装 QEMU、`libvirt` 和 OpenStack。**建议为 OpenStack 安装使用独立的物理节点**;OpenStack 建议最低 8GB 内存与四核处理器。
|
||
|
||
```text
|
||
+---------------------------------------------------+
|
||
| OpenStack |
|
||
+---------------------------------------------------+
|
||
| libvirt |
|
||
+------------------------+--------------------------+
|
||
| configures
|
||
v
|
||
+---------------------------------------------------+
|
||
| QEMU |
|
||
+---------------------------------------------------+
|
||
| librbd |
|
||
+---------------------------------------------------+
|
||
| librados |
|
||
+------------------------+-+------------------------+
|
||
| OSDs | | Monitors |
|
||
+------------------------+ +------------------------+
|
||
```
|
||
|
||
OpenStack 有三个部分集成 Ceph 块设备:
|
||
|
||
| 组件 | 说明 |
|
||
|---|---|
|
||
| **Images** | OpenStack **Glance** 管理 VM 镜像,镜像是不可变的;OpenStack 把镜像当作二进制 blob 并按需下载 |
|
||
| **Volumes** | 卷是块设备。OpenStack 用卷启动 VM,或把卷附加到运行中的 VM。OpenStack 用 **Cinder** 服务管理卷 |
|
||
| **Guest Disks** | guest 磁盘是 guest 操作系统盘。默认启动 VM 时,其磁盘表现为 hypervisor 文件系统上的一个文件(通常在 `/var/lib/nova/instances/<uuid>/`)。Havana 之前,在 Ceph 中启动 VM 的唯一方式是使用 Cinder 的 boot-from-volume 功能;**现在可以不使用 Cinder 而直接在 Ceph 中启动每台虚拟机**,这便于用 live-migration 做维护,且 hypervisor 宕机时可以方便地触发 `nova evacuate` 在别处几乎无缝地恢复虚拟机。**exclusive locks 会阻止多个 compute 节点并发访问 guest 磁盘。** |
|
||
|
||
> ⚠️ 官方 important:**不推荐使用 QCOW2 承载虚拟机磁盘。** 如果想在 Ceph 中启动虚拟机(ephemeral backend 或 boot from volume),请在 Glance 中使用 **`raw`** 镜像格式。
|
||
|
||
> 提示:Glance 与 Cinder、Nova 的配置**不一定要同时使用**——你可以把镜像存在 Ceph 块设备中而用本地磁盘跑 VM,反之亦然。
|
||
|
||
#### 创建 Pool 与初始化
|
||
|
||
```bash
|
||
ceph osd pool create volumes
|
||
ceph osd pool create images
|
||
ceph osd pool create backups
|
||
ceph osd pool create vms
|
||
|
||
rbd pool init volumes
|
||
rbd pool init images
|
||
rbd pool init backups
|
||
rbd pool init vms
|
||
```
|
||
|
||
#### 配置 OpenStack Ceph 客户端
|
||
|
||
运行 `glance-api`、`cinder-volume`、`nova-compute` 和 `cinder-backup` 的节点都是 Ceph 客户端,每个都需要 `ceph.conf`:
|
||
|
||
```bash
|
||
ssh {your-openstack-server} sudo tee /etc/ceph/ceph.conf </etc/ceph/ceph.conf
|
||
```
|
||
|
||
**安装客户端包**
|
||
|
||
```bash
|
||
# glance-api 节点:需要 librbd 的 Python 绑定
|
||
sudo apt-get install python-rbd
|
||
sudo yum install python-rbd
|
||
|
||
# nova-compute、cinder-backup、cinder-volume 节点:Python 绑定 + 命令行工具
|
||
sudo apt-get install ceph-common
|
||
sudo yum install ceph-common
|
||
```
|
||
|
||
**设置 Ceph 客户端认证**
|
||
|
||
```bash
|
||
ceph auth get-or-create client.glance mon 'profile rbd' osd 'profile rbd pool=images' mgr 'profile rbd pool=images'
|
||
ceph auth get-or-create client.cinder mon 'profile rbd' osd 'profile rbd pool=volumes, profile rbd pool=vms, profile rbd-read-only pool=images' mgr 'profile rbd pool=volumes, profile rbd pool=vms'
|
||
ceph auth get-or-create client.cinder-backup mon 'profile rbd' osd 'profile rbd pool=backups' mgr 'profile rbd pool=backups'
|
||
```
|
||
|
||
把 keyring 放到对应节点并改属主:
|
||
|
||
```bash
|
||
ceph auth get-or-create client.glance | ssh {your-glance-api-server} sudo tee /etc/ceph/ceph.client.glance.keyring
|
||
ssh {your-glance-api-server} sudo chown glance:glance /etc/ceph/ceph.client.glance.keyring
|
||
ceph auth get-or-create client.cinder | ssh {your-volume-server} sudo tee /etc/ceph/ceph.client.cinder.keyring
|
||
ssh {your-cinder-volume-server} sudo chown cinder:cinder /etc/ceph/ceph.client.cinder.keyring
|
||
ceph auth get-or-create client.cinder-backup | ssh {your-cinder-backup-server} sudo tee /etc/ceph/ceph.client.cinder-backup.keyring
|
||
ssh {your-cinder-backup-server} sudo chown cinder:cinder /etc/ceph/ceph.client.cinder-backup.keyring
|
||
```
|
||
|
||
`nova-compute` 节点需要 `nova-compute` 进程的 keyring 文件:
|
||
|
||
```bash
|
||
ceph auth get-or-create client.cinder | ssh {your-nova-compute-server} sudo tee /etc/ceph/ceph.client.cinder.keyring
|
||
```
|
||
|
||
它们还需要把 `client.cinder` 用户的 secret key 存入 `libvirt`——libvirt 进程在从 Cinder 附加块设备访问集群时需要它。
|
||
|
||
```bash
|
||
# 在 nova-compute 节点上创建密钥的临时副本
|
||
ceph auth get-key client.cinder | ssh {your-compute-node} tee client.cinder.key
|
||
|
||
# 在 compute 节点上:把密钥加入 libvirt 并删除临时副本
|
||
uuidgen
|
||
457eb676-33da-42ec-9a8c-9293d545c337
|
||
|
||
cat > secret.xml <<EOF
|
||
<secret ephemeral='no' private='no'>
|
||
<uuid>457eb676-33da-42ec-9a8c-9293d545c337</uuid>
|
||
<usage type='ceph'>
|
||
<name>client.cinder secret</name>
|
||
</usage>
|
||
</secret>
|
||
EOF
|
||
sudo virsh secret-define --file secret.xml
|
||
Secret 457eb676-33da-42ec-9a8c-9293d545c337 created
|
||
sudo virsh secret-set-value --secret 457eb676-33da-42ec-9a8c-9293d545c337 --base64 $(cat client.cinder.key) && rm client.cinder.key secret.xml
|
||
```
|
||
|
||
> ⚠️ 官方 important:**并非所有 compute 节点都必须使用同一个 UUID**,但从平台一致性角度看,最好保持相同 UUID。保存该 secret 的 uuid 以便稍后配置 `nova-compute`。
|
||
|
||
#### 配置 Glance
|
||
|
||
编辑 `/etc/glance/glance-api.conf`,在 `[glance_store]` 段添加(**Kilo 及之后**):
|
||
|
||
```ini
|
||
[glance_store]
|
||
stores = rbd
|
||
default_store = rbd
|
||
rbd_store_pool = images
|
||
rbd_store_user = glance
|
||
rbd_store_ceph_conf = /etc/ceph/ceph.conf
|
||
rbd_store_chunk_size = 8
|
||
```
|
||
|
||
**启用镜像的 COW 克隆**(注意:这会通过 Glance API 暴露后端位置,因此启用该选项的端点**不应公开访问**):
|
||
|
||
```ini
|
||
# 除 Mitaka 外的任何 OpenStack 版本,在 [DEFAULT] 段添加
|
||
show_image_direct_url = True
|
||
```
|
||
|
||
**禁用缓存管理**(任何版本):为避免镜像被缓存到 `/var/lib/glance/image-cache/`,假定配置文件中 `flavor = keystone+cachemanagement`:
|
||
|
||
```ini
|
||
[paste_deploy]
|
||
flavor = keystone
|
||
```
|
||
|
||
**推荐的镜像属性:**
|
||
|
||
| 属性 | 作用 |
|
||
|---|---|
|
||
| `hw_scsi_model=virtio-scsi` | 添加 virtio-scsi 控制器,获得更好性能与 discard 操作支持 |
|
||
| `hw_disk_bus=scsi` | 把每个 cinder 块设备接到该控制器上 |
|
||
| `hw_qemu_guest_agent=yes` | 启用 QEMU guest agent |
|
||
| `os_require_quiesce=yes` | 通过 QEMU guest agent 发送 fs-freeze/thaw 调用 |
|
||
|
||
#### 配置 Cinder
|
||
|
||
编辑 `/etc/cinder/cinder.conf`:
|
||
|
||
```ini
|
||
[DEFAULT]
|
||
...
|
||
enabled_backends = ceph
|
||
glance_api_version = 2
|
||
...
|
||
[ceph]
|
||
volume_driver = cinder.volume.drivers.rbd.RBDDriver
|
||
volume_backend_name = ceph
|
||
rbd_pool = volumes
|
||
rbd_ceph_conf = /etc/ceph/ceph.conf
|
||
rbd_flatten_volume_from_snapshot = false
|
||
rbd_max_clone_depth = 5
|
||
rbd_store_chunk_size = 4
|
||
rados_connect_timeout = -1
|
||
```
|
||
|
||
如果使用 cephx 认证,还要配置已加入 libvirt 的用户与 secret uuid:
|
||
|
||
```ini
|
||
[ceph]
|
||
...
|
||
rbd_user = cinder
|
||
rbd_secret_uuid = 457eb676-33da-42ec-9a8c-9293d545c337
|
||
```
|
||
|
||
> 注意:如果配置多个 cinder 后端,`glance_api_version = 2` **必须**放在 `[DEFAULT]` 段。
|
||
|
||
#### 配置 Cinder Backup
|
||
|
||
在 Cinder Backup 节点编辑 `/etc/cinder/cinder.conf`:
|
||
|
||
```ini
|
||
backup_driver = cinder.backup.drivers.ceph
|
||
backup_ceph_conf = /etc/ceph/ceph.conf
|
||
backup_ceph_user = cinder-backup
|
||
backup_ceph_chunk_size = 134217728
|
||
backup_ceph_pool = backups
|
||
backup_ceph_stripe_unit = 0
|
||
backup_ceph_stripe_count = 0
|
||
restore_discard_excess_bytes = true
|
||
```
|
||
|
||
> 注意:OpenStack Cinder Backup 需要一个特定守护进程,别忘了安装。
|
||
|
||
#### 配置 Nova(附加 Ceph RBD 块设备)
|
||
|
||
要附加 Cinder 设备(普通块设备或 boot from volume),必须告诉 Nova(与 libvirt)附加设备时使用哪个用户与 UUID:
|
||
|
||
```ini
|
||
[libvirt]
|
||
...
|
||
rbd_user = cinder
|
||
rbd_secret_uuid = 457eb676-33da-42ec-9a8c-9293d545c337
|
||
```
|
||
|
||
> 这两个 flag 也被 Nova ephemeral 后端使用。
|
||
|
||
#### 配置 Nova(从 Ceph 卷直接启动 VM)
|
||
|
||
必须配置 Nova 的 ephemeral backend。**建议启用 RBD cache**(自 Giant 版本起默认启用)。此外,启用 **client admin socket** 可以采集指标,对排障非常有价值。
|
||
|
||
该 socket 可以在 hypervisor(Nova compute)节点访问:
|
||
|
||
```bash
|
||
ceph daemon /var/run/ceph/ceph-client.cinder.19195.32310016.asok help
|
||
```
|
||
|
||
在每个 hypervisor 的 `ceph.conf` 中确保包含:
|
||
|
||
```ini
|
||
[client]
|
||
rbd cache = true
|
||
rbd cache writethrough until flush = true
|
||
admin socket = /var/run/ceph/guests/$cluster-$type.$id.$pid.$cctid.asok
|
||
log file = /var/log/qemu/qemu-guest-$pid.log
|
||
rbd concurrent management ops = 20
|
||
```
|
||
|
||
配置目录权限:
|
||
|
||
```bash
|
||
mkdir -p /var/run/ceph/guests/ /var/log/qemu/
|
||
chown qemu:libvirtd /var/run/ceph/guests /var/log/qemu/
|
||
```
|
||
|
||
> 注意:用户 `qemu` 与组 `libvirtd` 可能因系统而异,上述示例适用于 RedHat 系系统。
|
||
> Tip:如果虚拟机已在运行,只需重启它即可启用 admin socket。
|
||
|
||
#### 重启 OpenStack
|
||
|
||
```bash
|
||
# Debian 系
|
||
sudo glance-control api restart
|
||
sudo service nova-compute restart
|
||
sudo service cinder-volume restart
|
||
sudo service cinder-backup restart
|
||
|
||
# Red Hat 系
|
||
sudo service openstack-glance-api restart
|
||
sudo service openstack-nova-compute restart
|
||
sudo service openstack-cinder-volume restart
|
||
sudo service openstack-cinder-backup restart
|
||
```
|
||
|
||
#### 从块设备启动
|
||
|
||
```bash
|
||
cinder create --image-id {id of image} --display-name {name of volume} {size of volume}
|
||
```
|
||
|
||
可以用 `qemu-img` 做格式转换:
|
||
|
||
```bash
|
||
qemu-img convert -f {source-format} -O {output-format} {source-filename} {output-filename}
|
||
qemu-img convert -f qcow2 -O raw precise-cloudimg.img precise-cloudimg.raw
|
||
```
|
||
|
||
**当 Glance 与 Cinder 都使用 Ceph 块设备时,该镜像是一个 COW 克隆,因此新卷创建得非常快。** 在 OpenStack dashboard 中:
|
||
|
||
1. Launch a new instance;
|
||
2. 选择与该 COW 克隆关联的镜像;
|
||
3. 选择 'boot from volume';
|
||
4. 选择你创建的卷。
|
||
|
||
### 12.5 CloudStack
|
||
|
||
> 引自:[Block Devices and CloudStack](https://docs.ceph.com/en/tentacle/rbd/rbd-cloudstack/)
|
||
|
||
可以通过 `libvirt` 在 **CloudStack 4.0 及更高版本**中使用 Ceph Block Device image,`libvirt` 把 QEMU 接口配置到 `librbd`。Ceph 把块设备 image 条带化为跨集群的对象,因此大的 Ceph Block Device image 性能优于独立服务器。
|
||
|
||
前置:必须安装 QEMU、`libvirt`、CloudStack。**建议使用独立的物理主机**;CloudStack 建议最低 4GB 内存与双核处理器(更多 CPU 与内存性能更好)。
|
||
|
||
```text
|
||
+---------------------------------------------------+
|
||
| CloudStack |
|
||
+---------------------------------------------------+
|
||
| libvirt |
|
||
+------------------------+--------------------------+
|
||
| configures
|
||
v
|
||
+---------------------------------------------------+
|
||
| QEMU |
|
||
+---------------------------------------------------+
|
||
| librbd |
|
||
+---------------------------------------------------+
|
||
| librados |
|
||
+------------------------+-+------------------------+
|
||
| OSDs | | Monitors |
|
||
+------------------------+ +------------------------+
|
||
```
|
||
|
||
CloudStack 集成 Ceph 块设备,为其提供 **Primary Storage** 后端。
|
||
|
||
> 官方 note:**建议安装 Ubuntu 14.04 或更新版本**,以便用软件包安装而不必从源码编译 libvirt。
|
||
>
|
||
> 官方 note:Ubuntu 14.04 与 CentOS 7.2 自带的 `libvirt` **默认已启用 RBD storage pool 支持**。
|
||
>
|
||
> 为 CloudStack 安装配置 QEMU 无需特殊处理:确保有运行中的 Ceph Storage Cluster,安装 QEMU 并配置它与 Ceph 配合;然后安装 `libvirt` **0.9.13 或更高版本**(可能需要从源码编译)并确保它与 Ceph 一起正常运行。
|
||
|
||
#### 创建 Pool 与用户
|
||
|
||
```bash
|
||
ceph osd pool create cloudstack
|
||
rbd pool init cloudstack
|
||
|
||
ceph auth get-or-create client.cloudstack mon 'profile rbd' osd 'profile rbd pool=cloudstack'
|
||
```
|
||
|
||
> 虽然可以用 `client.admin`,但官方建议创建只对 `cloudstack` pool 有访问权限的用户。
|
||
|
||
#### 添加 Primary Storage(UI 步骤)
|
||
|
||
1. 登录 CloudStack UI;
|
||
2. 点击左侧导航栏的 **Infrastructure**;
|
||
3. 在 **Primary Storage** 下选择 **View All**;
|
||
4. 点击右上角的 **Add Primary Storage** 按钮;
|
||
5. 按你的基础设施填写:
|
||
|
||
| 字段 | 说明 |
|
||
|---|---|
|
||
| Scope | 如 Cluster 或 Zone-Wide |
|
||
| Zone | — |
|
||
| Pod | — |
|
||
| Cluster | — |
|
||
| Name of Primary Storage | — |
|
||
| **Protocol** | 选择 **`RBD`** |
|
||
| **Provider** | 选择适当的 provider 类型(DefaultPrimary、SolidFire、SolidFireShared 或 CloudByte),并填写与你所选 provider 相关的信息 |
|
||
|
||
6. 添加集群信息(支持 `cephx`):
|
||
|
||
| 字段 | 说明 |
|
||
|---|---|
|
||
| **RADOS Monitor** | Ceph monitor 的 IP 地址或 DNS 名称。**注意:仅在 CloudStack v4.18.0.0 或更高版本中支持逗号分隔的多个 IP/DNS 名称列表** |
|
||
| **RADOS Pool** | 一个 RBD pool 的名称 |
|
||
| **RADOS User** | 对该 RBD pool 有足够权限的用户。**注意:不要包含 `client.` 部分** |
|
||
| **RADOS Secret** | 该用户的 secret |
|
||
| **Storage Tags** | 可选,自行决定 |
|
||
|
||
7. 点击 **OK**。
|
||
|
||
#### 创建 Disk Offering
|
||
|
||
创建一个新的 disk offering,使其匹配 `rbd` 标签。这样 `StoragePoolAllocator` 在选择合适存储池时会选中 `rbd` pool。如果 disk offering 不匹配 `rbd` 标签,`StoragePoolAllocator` 可能选中你创建的 pool(例如 `cloudstack`)。
|
||
|
||
#### 限制
|
||
|
||
- 直到 **v4.17.1.0**,CloudStack **一次只会绑定一个 monitor**。不过可以使用多个 DNS A 或 AAAA 记录以 round-robin 方式把连接分散到多个 monitor。
|
||
|
||
### 12.6 Nomad
|
||
|
||
> 引自:[Block Devices and Nomad](https://docs.ceph.com/en/tentacle/rbd/rbd-nomad/)
|
||
|
||
与 Kubernetes 类似,Nomad 也可以使用 Ceph Block Device,通过 **`ceph-csi`** 实现,允许动态供给 RBD image 或导入既有 RBD image。
|
||
|
||
Nomad 的每个版本都与 `ceph-csi` 兼容,但本页生成流程与指引所用的参考版本是 **Nomad v1.1.2**(撰写时可用的最新版本)。
|
||
|
||
```text
|
||
+-------------------------+-------------------------+
|
||
| Container | ceph--csi |
|
||
| | node |
|
||
| ^ | ^ |
|
||
| | | | |
|
||
+----------+--------------+-------------------------+
|
||
| | | |
|
||
| v | |
|
||
| Nomad | |
|
||
| | |
|
||
+---------------------------------------------------+
|
||
| ceph--csi |
|
||
| controller |
|
||
+--------+------------------------------------------+
|
||
| |
|
||
| configures maps |
|
||
+---------------+ +----------------+
|
||
| |
|
||
v v
|
||
+------------------------+ +------------------------+
|
||
| | | rbd--nbd |
|
||
| Kernel Modules | +------------------------+
|
||
| | | librbd |
|
||
+------------------------+-+------------------------+
|
||
| RADOS Protocol |
|
||
+------------------------+-+------------------------+
|
||
| OSDs | | Monitors |
|
||
+------------------------+ +------------------------+
|
||
```
|
||
|
||
> 官方 note:Nomad 有多种 task driver,但本例只使用 Docker 容器。
|
||
>
|
||
> ⚠️ 官方 important:**`ceph-csi` 默认使用 RBD 内核模块,可能无法支持所有 Ceph CRUSH tunables 或 RBD image features。**
|
||
|
||
#### 创建 Pool
|
||
|
||
```bash
|
||
ceph osd pool create nomad
|
||
rbd pool init nomad
|
||
```
|
||
|
||
#### 配置 ceph-csi
|
||
|
||
**创建用户**
|
||
|
||
```bash
|
||
$ ceph auth get-or-create client.nomad mon 'profile rbd' osd 'profile rbd pool=nomad' mgr 'profile rbd pool=nomad'
|
||
[client.nomad]
|
||
key = AQAlh9Rgg2vrDxAARy25T7KHabs6iskSHpAEAQ==
|
||
```
|
||
|
||
**配置 Nomad 允许容器使用特权模式**(编辑 `/etc/nomad.d/nomad.hcl`):
|
||
|
||
```hcl
|
||
plugin "docker" {
|
||
config {
|
||
allow_privileged = true
|
||
}
|
||
}
|
||
```
|
||
|
||
**加载 rbd 模块**
|
||
|
||
```bash
|
||
$ lsmod | grep rbd
|
||
rbd 94208 2
|
||
libceph 364544 1 rbd
|
||
|
||
# 若未加载:
|
||
sudo modprobe rbd
|
||
```
|
||
|
||
**重启 Nomad**
|
||
|
||
```bash
|
||
sudo systemctl restart nomad
|
||
```
|
||
|
||
#### 创建 ceph-csi controller 与 plugin nodes
|
||
|
||
`ceph-csi` 插件需要两个组件:
|
||
|
||
- **Controller plugin**:与 provider 的 API 通信;
|
||
- **Node plugin**:在客户端上执行任务。
|
||
|
||
> 注意:需要在这些文件中设置 ceph-csi 的版本,参见 `ceph-csi release` 了解兼容性。
|
||
|
||
**controller(示例 `ceph-csi-plugin-controller.nomad`)**
|
||
|
||
```hcl
|
||
job "ceph-csi-plugin-controller" {
|
||
datacenters = ["dc1"]
|
||
group "controller" {
|
||
network {
|
||
port "metrics" {}
|
||
}
|
||
task "ceph-controller" {
|
||
template {
|
||
data = <<EOF
|
||
[{
|
||
"clusterID": "b9127830-b0cc-4e34-aa47-9d1a2e9949a8",
|
||
"monitors": [
|
||
"192.168.1.1",
|
||
"192.168.1.2",
|
||
"192.168.1.3"
|
||
]
|
||
}]
|
||
EOF
|
||
destination = "local/config.json"
|
||
change_mode = "restart"
|
||
}
|
||
driver = "docker"
|
||
config {
|
||
image = "quay.io/cephcsi/cephcsi:v3.3.1"
|
||
volumes = [
|
||
"./local/config.json:/etc/ceph-csi-config/config.json"
|
||
]
|
||
mounts = [
|
||
{
|
||
type = "tmpfs"
|
||
target = "/tmp/csi/keys"
|
||
readonly = false
|
||
tmpfs_options = {
|
||
size = 1000000 # size in bytes
|
||
}
|
||
}
|
||
]
|
||
args = [
|
||
"--type=rbd",
|
||
"--controllerserver=true",
|
||
"--drivername=rbd.csi.ceph.com",
|
||
"--endpoint=unix://csi/csi.sock",
|
||
"--nodeid=${node.unique.name}",
|
||
"--instanceid=${node.unique.name}-controller",
|
||
"--pidlimit=-1",
|
||
"--logtostderr=true",
|
||
"--v=5",
|
||
"--metricsport=$${NOMAD_PORT_metrics}"
|
||
]
|
||
}
|
||
resources {
|
||
cpu = 500
|
||
memory = 256
|
||
}
|
||
service {
|
||
name = "ceph-csi-controller"
|
||
port = "metrics"
|
||
tags = [ "prometheus" ]
|
||
}
|
||
csi_plugin {
|
||
id = "ceph-csi"
|
||
type = "controller"
|
||
mount_dir = "/csi"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**node(示例 `ceph-csi-plugin-nodes.nomad`)**
|
||
|
||
```hcl
|
||
job "ceph-csi-plugin-nodes" {
|
||
datacenters = ["dc1"]
|
||
type = "system"
|
||
group "nodes" {
|
||
network {
|
||
port "metrics" {}
|
||
}
|
||
task "ceph-node" {
|
||
driver = "docker"
|
||
template {
|
||
data = <<EOF
|
||
[{
|
||
"clusterID": "b9127830-b0cc-4e34-aa47-9d1a2e9949a8",
|
||
"monitors": [
|
||
"192.168.1.1",
|
||
"192.168.1.2",
|
||
"192.168.1.3"
|
||
]
|
||
}]
|
||
EOF
|
||
destination = "local/config.json"
|
||
change_mode = "restart"
|
||
}
|
||
config {
|
||
image = "quay.io/cephcsi/cephcsi:v3.3.1"
|
||
volumes = [
|
||
"./local/config.json:/etc/ceph-csi-config/config.json"
|
||
]
|
||
mounts = [
|
||
{
|
||
type = "tmpfs"
|
||
target = "/tmp/csi/keys"
|
||
readonly = false
|
||
tmpfs_options = {
|
||
size = 1000000 # size in bytes
|
||
}
|
||
}
|
||
]
|
||
args = [
|
||
"--type=rbd",
|
||
"--drivername=rbd.csi.ceph.com",
|
||
"--nodeserver=true",
|
||
"--endpoint=unix://csi/csi.sock",
|
||
"--nodeid=${node.unique.name}",
|
||
"--instanceid=${node.unique.name}-nodes",
|
||
"--pidlimit=-1",
|
||
"--logtostderr=true",
|
||
"--v=5",
|
||
"--metricsport=$${NOMAD_PORT_metrics}"
|
||
]
|
||
privileged = true
|
||
}
|
||
resources {
|
||
cpu = 500
|
||
memory = 256
|
||
}
|
||
service {
|
||
name = "ceph-csi-nodes"
|
||
port = "metrics"
|
||
tags = [ "prometheus" ]
|
||
}
|
||
csi_plugin {
|
||
id = "ceph-csi"
|
||
type = "node"
|
||
mount_dir = "/csi"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**启动与检查**
|
||
|
||
```bash
|
||
nomad job run ceph-csi-plugin-controller.nomad
|
||
nomad job run ceph-csi-plugin-nodes.nomad
|
||
```
|
||
|
||
```bash
|
||
$ nomad plugin status ceph-csi
|
||
ID = ceph-csi
|
||
Provider = rbd.csi.ceph.com
|
||
Version = 3.3.1
|
||
Controllers Healthy = 1
|
||
Controllers Expected = 1
|
||
Nodes Healthy = 1
|
||
Nodes Expected = 1
|
||
```
|
||
|
||
#### 使用
|
||
|
||
**创建 volume(`ceph-volume.hcl`)**
|
||
|
||
```hcl
|
||
id = "ceph-mysql"
|
||
name = "ceph-mysql"
|
||
type = "csi"
|
||
plugin_id = "ceph-csi"
|
||
capacity_max = "200G"
|
||
capacity_min = "100G"
|
||
|
||
capability {
|
||
access_mode = "single-node-writer"
|
||
attachment_mode = "file-system"
|
||
}
|
||
|
||
secrets {
|
||
userID = "admin"
|
||
userKey = "AQAlh9Rgg2vrDxAARy25T7KHabs6iskSHpAEAQ=="
|
||
}
|
||
|
||
parameters {
|
||
clusterID = "b9127830-b0cc-4e34-aa47-9d1a2e9949a8"
|
||
pool = "nomad"
|
||
imageFeatures = "layering"
|
||
mkfsOptions = "-t ext4"
|
||
}
|
||
```
|
||
|
||
```bash
|
||
nomad volume create ceph-volume.hcl
|
||
```
|
||
|
||
**在容器中使用(`mysql.nomad`)**
|
||
|
||
```hcl
|
||
job "mysql-server" {
|
||
datacenters = ["dc1"]
|
||
type = "service"
|
||
group "mysql-server" {
|
||
count = 1
|
||
volume "ceph-mysql" {
|
||
type = "csi"
|
||
attachment_mode = "file-system"
|
||
access_mode = "single-node-writer"
|
||
read_only = false
|
||
source = "ceph-mysql"
|
||
}
|
||
network {
|
||
port "db" {
|
||
static = 3306
|
||
}
|
||
}
|
||
restart {
|
||
attempts = 10
|
||
interval = "5m"
|
||
delay = "25s"
|
||
mode = "delay"
|
||
}
|
||
task "mysql-server" {
|
||
driver = "docker"
|
||
volume_mount {
|
||
volume = "ceph-mysql"
|
||
destination = "/srv"
|
||
read_only = false
|
||
}
|
||
env {
|
||
MYSQL_ROOT_PASSWORD = "password"
|
||
}
|
||
config {
|
||
image = "hashicorp/mysql-portworx-demo:latest"
|
||
args = ["--datadir", "/srv/mysql"]
|
||
ports = ["db"]
|
||
}
|
||
resources {
|
||
cpu = 500
|
||
memory = 1024
|
||
}
|
||
service {
|
||
name = "mysql-server"
|
||
port = "db"
|
||
check {
|
||
type = "tcp"
|
||
interval = "10s"
|
||
timeout = "2s"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
```bash
|
||
nomad job run mysql.nomad
|
||
nomad job status mysql-server
|
||
```
|
||
|
||
> 验证持久化:修改数据库 → purge 该 job → 用同一文件重新创建。将会使用(复用)同一个 RBD image。
|
||
|
||
### 12.7 Windows
|
||
|
||
> 引自:[RBD on Windows](https://docs.ceph.com/en/tentacle/rbd/rbd-windows/)
|
||
|
||
`rbd` 命令在 Windows 上可以像在 Linux 上一样创建、删除、导入、导出、map、unmap image。原生使用 Ceph 的应用还可以使用 **`librbd.dll`**。
|
||
|
||
#### Windows service
|
||
|
||
在 Windows 上,`rbd-wnbd` 守护进程由一个**集中式服务**管理,从而把守护进程与其发起的 Windows session 解耦;同时该服务负责在主机启动时重建持久映射。**每个主机只能运行一个这样的服务。**
|
||
|
||
- **默认情况下所有 image 映射都是持久的**;可以通过 `rbd` 的 `-onon-persistent` 标志请求非持久映射;
|
||
- 持久映射在服务启动时被重建,除非被显式 unmap。服务停止时会断开这些映射。这也允许调整 Windows 服务的启动顺序,使 RBD image 能在依赖它的服务(如 VMMS)之前被映射;
|
||
- 为了能够重连 image,`rbd-wnbd` 把映射信息存放在注册表:`SYSTEM\CurrentControlSet\Services\rbd-wnbd`。
|
||
|
||
```powershell
|
||
New-Service -Name "ceph-rbd" `
|
||
-Description "Ceph RBD Mapping Service" `
|
||
-BinaryPathName "c:\ceph\rbd-wnbd.exe service" `
|
||
-StartupType Automatic
|
||
```
|
||
|
||
> Ceph MSI 安装程序会负责创建 `ceph-rbd` Windows 服务。
|
||
|
||
#### 与 Linux 的差异(官方原文)
|
||
|
||
| 项 | 差异 |
|
||
|---|---|
|
||
| 设备路径 | **不能请求设备路径**。磁盘号与路径由 Windows 选择。如果用户在映射时提供了设备路径,它会被用作**标识符**,也可在 unmap 时使用 |
|
||
| `show` 命令 | 新增,描述某个具体映射,可用于获取磁盘路径 |
|
||
| `service` 命令 | 新增,允许 `rbd-wnbd` 作为 Windows 服务运行 |
|
||
| `list` 命令 | 额外包含 `status` 列 |
|
||
|
||
RBD image 可以暴露给 OS 并承载 Windows 分区,也可以像 iSCSI 磁盘一样附加到 Hyper-V VM。**自 OpenStack Wallaby 起,Nova Hyper-V 驱动可以把 RBD Cinder 卷附加到 Hyper-V VM。**
|
||
|
||
#### 示例:导入 image 并用它启动 Hyper-V VM
|
||
|
||
```powershell
|
||
# 可以换用其他镜像;cirros 便于测试:很小(~15MB)且登录提示会打印预置密码
|
||
wget http://download.cirros-cloud.net/0.5.1/cirros-0.5.1-x86_64-disk.img `
|
||
-OutFile cirros-0.5.1-x86_64-disk.img
|
||
|
||
# 必须确保导入的镜像是 raw(不能是 qcow2 或 vhdx)
|
||
# qemu-img 可从 https://cloudbase.it/qemu-img-windows/ 获取
|
||
qemu-img convert -O raw cirros-0.5.1-x86_64-disk.img cirros-0.5.1-x86_64-disk.raw
|
||
|
||
rbd import cirros-0.5.1-x86_64-disk.raw
|
||
# 给它一个 100MB 的尺寸
|
||
rbd resize cirros-0.5.1-x86_64-disk.raw --size=100MB
|
||
|
||
rbd device map cirros-0.5.1-x86_64-disk.raw
|
||
|
||
# 查看映射
|
||
rbd device list
|
||
Get-Disk
|
||
|
||
$mappingJson = rbd-wnbd show cirros-0.5.1-x86_64-disk.raw --format=json
|
||
$mappingJson = $mappingJson | ConvertFrom-Json
|
||
|
||
$diskNumber = $mappingJson.disk_number
|
||
|
||
New-VM -VMName BootFromRBD -MemoryStartupBytes 512MB
|
||
# 磁盘必须先 offline 才能传给 Hyper-V VM
|
||
Set-Disk -Number $diskNumber -IsOffline $true
|
||
Add-VMHardDiskDrive -VMName BootFromRBD -DiskNumber $diskNumber
|
||
Start-VM -VMName BootFromRBD
|
||
```
|
||
|
||
#### 示例:创建空 image 并在主机上初始化分区
|
||
|
||
```powershell
|
||
rbd create blank_image --size=1G
|
||
rbd device map blank_image -onon-persistent
|
||
|
||
$mappingJson = rbd-wnbd show blank_image --format=json
|
||
$mappingJson = $mappingJson | ConvertFrom-Json
|
||
|
||
$diskNumber = $mappingJson.disk_number
|
||
|
||
# 磁盘必须先 online 才能创建或访问分区
|
||
Set-Disk -Number $diskNumber -IsOffline $false
|
||
|
||
# 初始化磁盘、分区并创建文件系统
|
||
Get-Disk -Number $diskNumber | `
|
||
Initialize-Disk -PassThru | `
|
||
New-Partition -AssignDriveLetter -UseMaximumSize | `
|
||
Format-Volume -Force -Confirm:$false
|
||
|
||
# 显示分区盘符(如 "D:" 或 "F:")
|
||
(Get-Partition -DiskNumber $diskNumber).DriveLetter
|
||
```
|
||
|
||
#### SAN policy
|
||
|
||
Windows SAN policy 决定哪些磁盘会被自动挂载。默认策略 **`offlineShared`** 规定:
|
||
|
||
> 所有新发现的、不在共享总线(如 SCSI 和 iSCSI)上的磁盘会被 online 并设为可读写。保持 offline 的磁盘默认为只读。
|
||
|
||
> 注意:**较新的 WNBD 驱动版本把 rbd-wnbd 磁盘报告为 SAS**,SAS 也被视为共享总线,因此这些磁盘**默认为 offline 且只读**。
|
||
|
||
把磁盘 online(挂载其分区)并清除只读标志:
|
||
|
||
```powershell
|
||
Set-Disk -Number $diskNumber -IsOffline $false
|
||
Set-Disk -Number $diskNumber -IsReadOnly $false
|
||
```
|
||
|
||
#### 限制
|
||
|
||
**CSV 支持**:目前 Microsoft Failover Cluster **不能**把 WNBD 磁盘用作 Cluster Shared Volumes (CSVs) 的底层存储。主要原因是 `WNBD` 与 `rbd-wnbd` **尚不支持 SCSI Persistent Reservations** 特性。
|
||
|
||
**Hyper-V 磁盘寻址** ⚠️:
|
||
|
||
> 官方 warning:Hyper-V **用编号而不是 SCSI ID 来标识直通 VM 磁盘**,而磁盘编号在主机重启后可能变化。这意味着主机重启后 VM 可能使用错误的磁盘,这是一个**重要的安全关切**。该问题同样影响 iSCSI 与 Fibre Channel 磁盘。
|
||
|
||
规避方式:
|
||
|
||
1. 用 NTFS/ReFS 分区来存放 VHDX 镜像文件,而不是直接附加 RBD image(可能轻微影响 IO 性能);
|
||
2. 用 Hyper-V 的 `AutomaticStartAction` 设置阻止 VM 用错误磁盘启动,并用脚本在重新上电前更新 VM 磁盘附加关系;可用 `Msvm_StorageAllocationSettingData` WMI 类的 `ElementName` 字段给 VM 磁盘附加关系打标签;
|
||
3. 使用 OpenStack Hyper-V 驱动,它会在重新上电前自动刷新 VM 磁盘附加关系。
|
||
|
||
**自动挂载磁盘**:标记为 "online" 或 "writable" 的磁盘在重连后(如主机重启、Ceph 服务重启)会保持该状态。不幸的是,**Windows 基于磁盘编号恢复磁盘状态,忽略磁盘唯一标识符**,而磁盘编号在重连后可能变化。假设 SAN policy 为 `offlineShared`,附加了三个 RBD image 且 disk 1 被设为 online;重启后 disk 1 会 online,但**它可能已对应到另一个 RBD image**。如果被挂载的磁盘本应给 VM 用,这会是个问题。(该问题同样影响 iSCSI 与 FC 磁盘。)
|
||
|
||
---
|
||
|
||
## 十三、iSCSI
|
||
|
||
### 13.1 Overview
|
||
|
||
> 引自:[Ceph iSCSI Gateway](https://docs.ceph.com/en/tentacle/rbd/iscsi-overview/)
|
||
|
||
iSCSI Gateway 提供一个**高可用(HA)的 iSCSI target**,把 RADOS Block Device (RBD) image 导出为 SCSI 磁盘。iSCSI 协议允许客户端(initiators)通过 TCP/IP 网络向存储设备(targets)发送 SCSI 命令,从而**让没有原生 Ceph 客户端支持的客户端也能访问 Ceph 块存储**。
|
||
|
||
每个 iSCSI gateway 利用 **Linux IO target 内核子系统(LIO)**提供 iSCSI 协议支持。LIO 使用 **userspace passthrough(TCMU)**与 Ceph 的 `librbd` 库交互,把 RBD image 暴露给 iSCSI 客户端。借助 Ceph 的 iSCSI gateway,你可以构建一套完全集成的块存储基础设施,具备传统 SAN 的全部特性与优势。
|
||
|
||
```text
|
||
Cluster Network (optional)
|
||
+-------------------------------------------+
|
||
| | | |
|
||
+-------+ +-------+ +-------+ +-------+
|
||
| | | | | | | |
|
||
| OSD 1 | | OSD 2 | | OSD 3 | | OSD N |
|
||
| {s}| | {s}| | {s}| | {s}|
|
||
+-------+ +-------+ +-------+ +-------+
|
||
| | | |
|
||
+--------->| | +---------+ | |<---------+
|
||
: | | | RBD | | | :
|
||
| +----------------| Image |----------------+ |
|
||
| Public Network | {d} | |
|
||
| +---------+ |
|
||
| |
|
||
| +-------------------+ |
|
||
| +--------------+ | iSCSI Initiators | +--------------+ |
|
||
| | iSCSI GW | | +-----------+ | | iSCSI GW | |
|
||
+-->| RBD Module |<--+ | Various | +-->| RBD Module |<--+
|
||
| | | | Operating | | | |
|
||
+--------------+ | | Systems | | +--------------+
|
||
| +-----------+ |
|
||
+-------------------+
|
||
```
|
||
|
||
> ⚠️ **官方 warning(重要)**:**iSCSI gateway 自 2022 年 11 月起进入 maintenance(仅维护)状态**,不再处于活跃开发中,也不会更新以添加新特性。
|
||
|
||
### 13.2 Requirements
|
||
|
||
> 引自:[iSCSI Gateway Requirements](https://docs.ceph.com/en/tentacle/rbd/iscsi-requirements/)
|
||
|
||
- **建议配置 2 到 4 个 iSCSI gateway 节点**,以构成高可用的 Ceph iSCSI gateway 方案;
|
||
- 硬件建议参见官方 hardware-recommendations;
|
||
- > 官方 note:在 iSCSI gateway 节点上,**内存占用是所映射 RBD image 数量的函数,可能增长到很大**。请根据要映射的 RBD image 数量规划内存需求。
|
||
|
||
Ceph Monitor 与 OSD **没有**特定的 iSCSI gateway 选项,但**降低检测 down OSD 的默认心跳间隔很重要**,以减少 initiator 超时的可能性。建议配置:
|
||
|
||
```ini
|
||
[osd]
|
||
osd heartbeat grace = 20
|
||
osd heartbeat interval = 5
|
||
```
|
||
|
||
**从 Ceph Monitor 节点更新运行态:**
|
||
|
||
```bash
|
||
ceph tell <daemon_type>.<id> config set <parameter_name> <new_value>
|
||
|
||
ceph tell osd.* config set osd_heartbeat_grace 20
|
||
ceph tell osd.* config set osd_heartbeat_interval 5
|
||
```
|
||
|
||
**在每个 OSD 节点上更新运行态:**
|
||
|
||
```bash
|
||
ceph daemon <daemon_type>.<id> config set osd_client_watch_timeout 15
|
||
|
||
ceph daemon osd.0 config set osd_heartbeat_grace 20
|
||
ceph daemon osd.0 config set osd_heartbeat_interval 5
|
||
```
|
||
|
||
> 请务必把这些设置持久化到 `/etc/ceph.conf`,或在 Mimic 及以后版本中存入 centralized config store。
|
||
|
||
(参考:默认值取自 `src/common/options/global.yaml.in @ v20.2.4`:`osd_heartbeat_grace` = `20`;`osd_heartbeat_interval` = `6`。即 iSCSI 场景建议把 `osd_heartbeat_interval` 从默认 `6` 降到 `5`。)
|
||
|
||
### 13.3 iSCSI Targets(部署前置条件)
|
||
|
||
> 引自:[iSCSI Targets](https://docs.ceph.com/en/tentacle/rbd/iscsi-targets/)
|
||
|
||
传统上,对 Ceph 存储集群的块级访问局限于 QEMU 与 `librbd`——这是在 OpenStack 环境中被采用的关键推动因素。**自 Ceph Luminous 版本起,块级访问扩展到提供标准的 iSCSI 支持**,从而支持更广泛的平台使用,并可能开创新的用例。
|
||
|
||
前置条件:
|
||
|
||
| 项 | 要求 |
|
||
|---|---|
|
||
| 操作系统/内核 | Red Hat Enterprise Linux/CentOS **7.5(或更新)**;Linux kernel **v4.16(或更新)** |
|
||
| Ceph 集群 | 一个可用的 Ceph Storage 集群,用 `ceph-ansible` 或命令行部署 |
|
||
| Gateway 节点 | iSCSI gateway 节点,可与 OSD 节点共存(colocated)或使用专用节点 |
|
||
| 网络 | iSCSI 前端流量与 Ceph 后端流量使用**独立的网络子网** |
|
||
|
||
部署方式二选一:**Ansible** 或 **命令行界面(CLI)**。
|
||
|
||
### 13.4 使用命令行(iscsi-target-cli)
|
||
|
||
> 引自:[Configuring the iSCSI Target using the Command Line Interface](https://docs.ceph.com/en/tentacle/rbd/iscsi-target-cli/)
|
||
|
||
Ceph iSCSI gateway 既是 iSCSI target 也是 Ceph 客户端——可以把它看作 Ceph 的 RBD 接口与 iSCSI 标准之间的"翻译器"。它可以运行在独立节点上,也可以与其他守护进程(例如在 OSD 节点上)共存;共存时确保有足够的 CPU 与内存可供共享。
|
||
|
||
**Requirements:**
|
||
|
||
- 运行中的 Ceph **Luminous 或更新**存储集群;
|
||
- RHEL/CentOS **7.5(或更新)**;Linux kernel **v4.16(或更新)**;
|
||
- 必须从 Linux 发行版软件仓库安装以下包:
|
||
|
||
| 包 | 最低版本 |
|
||
|---|---|
|
||
| `targetcli` | `2.1.fb47` 或更新 |
|
||
| `python-rtslib` | `2.1.fb68` 或更新 |
|
||
| `tcmu-runner` | `1.4.0` 或更新 |
|
||
| `ceph-iscsi` | `3.2` 或更新 |
|
||
|
||
> ⚠️ 官方 important:如果已存在这些包的旧版本,**必须先移除**再安装新版本。
|
||
|
||
**进入 Installing 之前,在 iSCSI gateway 节点上完成:**
|
||
|
||
1. 如果 iSCSI gateway 不与 OSD 节点共存,把存储集群中某个运行中的 Ceph 节点上 `/etc/ceph/` 下的 Ceph 配置文件拷贝到 iSCSI Gateway 节点。**这些配置文件必须位于 iSCSI gateway 节点的 `/etc/ceph/` 下。**
|
||
2. 安装并配置 Ceph Command-line Interface;
|
||
3. 如需要,在防火墙上开放 **TCP 3260 和 5000** 端口。
|
||
|
||
> 官方 note:**5000 端口的访问应限制在受信任的内部网络**,或只允许运行 `gwcli` 或 `ceph-mgr` 守护进程的个别主机访问。
|
||
4. 创建一个新的或使用一个既有的 RBD。
|
||
|
||
**Installing(rpm 系):**
|
||
|
||
```bash
|
||
yum install ceph-iscsi
|
||
yum install tcmu-runner
|
||
```
|
||
|
||
> 若使用上游 ceph-iscsi 包,请按照 manual install instructions(见 13.5)执行。
|
||
|
||
**Setup:**
|
||
|
||
1. `gwcli` 需要一个名为 **`rbd`** 的 pool 来存放 iSCSI 配置等元数据:
|
||
|
||
```bash
|
||
ceph osd lspools
|
||
```
|
||
|
||
2. 在 `/etc/ceph/` 下创建 `iscsi-gateway.cfg`:
|
||
|
||
```bash
|
||
touch /etc/ceph/iscsi-gateway.cfg
|
||
```
|
||
|
||
```ini
|
||
[config]
|
||
# Name of the Ceph storage cluster. A suitable Ceph configuration file allowing
|
||
# access to the Ceph storage cluster from the gateway node is required, if not
|
||
# colocated on an OSD node.
|
||
cluster_name = ceph
|
||
|
||
# Place a copy of the ceph cluster's admin keyring in the gateway's /etc/ceph
|
||
# directory and reference the filename here
|
||
gateway_keyring = ceph.client.admin.keyring
|
||
|
||
|
||
# API settings.
|
||
# The API supports a number of options that allow you to tailor it to your
|
||
# local environment. If you want to run the API under https, you will need to
|
||
# create cert/key files that are compatible for each iSCSI gateway node, that is
|
||
# not locked to a specific node. SSL cert and key files *must* be called
|
||
# 'iscsi-gateway.crt' and 'iscsi-gateway.key' and placed in the '/etc/ceph/' directory
|
||
# on *each* gateway node. With the SSL files in place, you can use 'api_secure = true'
|
||
# to switch to https mode.
|
||
|
||
# To support the API, the bare minimum settings are:
|
||
api_secure = false
|
||
|
||
# Additional API configuration options are as follows, defaults shown.
|
||
# api_user = admin
|
||
# api_password = admin
|
||
# api_port = 5001
|
||
# trusted_ip_list = 192.168.0.10,192.168.0.11
|
||
```
|
||
|
||
> 官方 note:`trusted_ip_list` 是每个 iSCSI gateway 上用于管理操作(如 target 创建、LUN 导出等)的 IP 地址列表。该 IP 可以与用于 iSCSI 数据(如到 RBD image 的 READ/WRITE 命令)的 IP 相同,但**建议使用不同的 IP**。
|
||
>
|
||
> ⚠️ 官方 important:**`iscsi-gateway.cfg` 文件在所有 iSCSI gateway 节点上必须完全相同。**
|
||
|
||
3. 把 `iscsi-gateway.cfg` 拷贝到所有 iSCSI gateway 节点;
|
||
4. 在所有 iSCSI gateway 节点上启用并启动 API 服务:
|
||
|
||
```bash
|
||
systemctl daemon-reload
|
||
|
||
systemctl enable rbd-target-gw
|
||
systemctl start rbd-target-gw
|
||
|
||
systemctl enable rbd-target-api
|
||
systemctl start rbd-target-api
|
||
```
|
||
|
||
**Configuring(gwcli):**
|
||
|
||
> `gwcli` 会创建并配置 iSCSI target 与 RBD image,并把配置复制到上一节设置好的各个 gateway。较低层工具(包括 `targetcli` 与 `rbd`)可用于查询本地配置,但**不应**用于修改它。
|
||
|
||
```console
|
||
> /> cd /iscsi-targets
|
||
> /iscsi-targets> create iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw
|
||
```
|
||
|
||
```console
|
||
> /iscsi-targets> cd iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw/gateways
|
||
> /iscsi-target...-igw/gateways> create ceph-gw-1 10.172.19.21
|
||
> /iscsi-target...-igw/gateways> create ceph-gw-2 10.172.19.22
|
||
```
|
||
|
||
> 这里使用的 IP 是将用于 iSCSI 数据(READ/WRITE 命令)的 IP。它们可以与 `trusted_ip_list` 中列出的管理操作 IP 相同,但建议使用不同 IP。
|
||
>
|
||
> 如果不是使用 RHEL/CentOS,或使用上游/ceph-iscsi-test 内核,必须使用 `skipchecks=true` 参数,以跳过 Red Hat 内核与 rpm 检查:
|
||
|
||
```console
|
||
> /iscsi-targets> cd iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw/gateways
|
||
> /iscsi-target...-igw/gateways> create ceph-gw-1 10.172.19.21 skipchecks=true
|
||
> /iscsi-target...-igw/gateways> create ceph-gw-2 10.172.19.22 skipchecks=true
|
||
```
|
||
|
||
```console
|
||
# 在 rbd pool 中添加名为 disk_1 的 RBD image
|
||
> /iscsi-target...-igw/gateways> cd /disks
|
||
> /disks> create pool=rbd image=disk_1 size=90G
|
||
|
||
# 创建 initiator 名为 iqn.1994-05.com.redhat:rh7-client 的客户端
|
||
> /disks> cd /iscsi-targets/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw/hosts
|
||
> /iscsi-target...eph-igw/hosts> create iqn.1994-05.com.redhat:rh7-client
|
||
|
||
# 设置 target 认证 initiator 时使用的 CHAP 用户名与密码
|
||
> /iscsi-target...at:rh7-client> auth username=myusername password=mypassword
|
||
```
|
||
|
||
> ⚠️ 官方 warning:**必须始终配置 CHAP。** 没有 CHAP,target 会拒绝任何登录请求。
|
||
>
|
||
> 要使用双向(mutual)认证,还要设置 initiator 认证 target 时使用的 target CHAP 用户名与密码:
|
||
|
||
```console
|
||
> /iscsi-target...at:rh7-client> auth username=myusername password=mypassword mutual_username=mytgtusername mutual_password=mytgtpassword
|
||
```
|
||
|
||
| CHAP 项 | 规则 |
|
||
|---|---|
|
||
| 用户名长度 | **8 到 64** 个字符。合法字符:`0`–`9`、`a`–`z`、`A`–`Z`、`@`、`_`、`-`、`.`、`:` |
|
||
| 密码长度 | **12 到 16** 个字符。合法字符:`0`–`9`、`a`–`z`、`A`–`Z`、`@`、`_`、`-`、`/` |
|
||
| 双向 CHAP | initiator 与 target 的**用户名和密码不得相同** |
|
||
|
||
```console
|
||
# 把磁盘加到客户端
|
||
> /iscsi-target...at:rh7-client> disk add rbd/disk_1
|
||
```
|
||
|
||
### 13.5 手工安装 ceph-iscsi
|
||
|
||
> 引自:[Manual ceph-iscsi Installation](https://docs.ceph.com/en/tentacle/rbd/iscsi-target-cli-manual-install/)
|
||
|
||
共 4 步:
|
||
|
||
1. 从 Linux 发行版软件仓库安装通用包;
|
||
2. 安装 Git 以便直接从 Git 仓库获取其余包;
|
||
3. 确保使用兼容的内核;
|
||
4. 安装 ceph-iscsi 的所有组件并启动相关守护进程:`tcmu-runner`、`rtslib-fb`、`configshell-fb`、`targetcli-fb`、`ceph-iscsi`。
|
||
|
||
**1) 通用包**(每台将成为 iSCSI gateway 的机器):
|
||
|
||
`libnl3`、`libkmod`、`librbd1`、`pyparsing`、`python kmod`、`python pyudev`、`python gobject`、`python urwid`、`python pyparsing`、`python rados`、`python rbd`、`python netifaces`、`python crypto`、`python requests`、`python flask`、`pyOpenSSL`
|
||
|
||
**2) 安装 Git**
|
||
|
||
```bash
|
||
sudo yum install git # CentOS/RHEL
|
||
sudo apt install git # Debian/Ubuntu
|
||
```
|
||
|
||
**3) 确保使用兼容内核**
|
||
|
||
- 任何内核 **v4.16 或更新**的 Linux 发行版;或
|
||
- **RHEL 或 CentOS 7.5 或更新**(这些发行版中 ceph-iscsi 支持被 backport)。
|
||
|
||
如果内核不兼容,需查阅发行版文档了解如何构建该内核。唯一的 Ceph iSCSI 特定要求是必须启用以下构建选项:
|
||
|
||
```ini
|
||
CONFIG_TARGET_CORE=m
|
||
CONFIG_TCM_USER2=m
|
||
CONFIG_ISCSI_TARGET=m
|
||
```
|
||
|
||
**4) 安装组件**
|
||
|
||
```bash
|
||
# tcmu-runner
|
||
git clone https://github.com/open-iscsi/tcmu-runner
|
||
cd tcmu-runner
|
||
./extra/install_dep.sh
|
||
cmake -Dwith-glfs=false -Dwith-qcow=false -DSUPPORT_SYSTEMD=ON -DCMAKE_INSTALL_PREFIX=/usr
|
||
make install
|
||
systemctl daemon-reload
|
||
systemctl enable tcmu-runner
|
||
systemctl start tcmu-runner
|
||
|
||
# rtslib-fb
|
||
git clone https://github.com/open-iscsi/rtslib-fb.git
|
||
cd rtslib-fb
|
||
python setup.py install
|
||
|
||
# configshell-fb
|
||
git clone https://github.com/open-iscsi/configshell-fb.git
|
||
cd configshell-fb
|
||
python setup.py install
|
||
|
||
# targetcli-fb
|
||
git clone https://github.com/open-iscsi/targetcli-fb.git
|
||
cd targetcli-fb
|
||
python setup.py install
|
||
mkdir /etc/target
|
||
mkdir /var/target
|
||
|
||
# ceph-iscsi
|
||
git clone https://github.com/ceph/ceph-iscsi.git
|
||
cd ceph-iscsi
|
||
python setup.py install --install-scripts=/usr/bin
|
||
cp usr/lib/systemd/system/rbd-target-gw.service /lib/systemd/system
|
||
cp usr/lib/systemd/system/rbd-target-api.service /lib/systemd/system
|
||
systemctl daemon-reload
|
||
systemctl enable rbd-target-gw
|
||
systemctl start rbd-target-gw
|
||
systemctl enable rbd-target-api
|
||
systemctl start rbd-target-api
|
||
```
|
||
|
||
> ⚠️ 官方 warning:**ceph-iscsi 工具假定它们管理着系统上的所有 target。** 如果已有 target 由 `targetcli` 设置并管理,**必须禁用 target 服务**。
|
||
|
||
### 13.6 使用 Ansible 部署
|
||
|
||
> 引自:[Configuring the iSCSI Target using Ansible](https://docs.ceph.com/en/tentacle/rbd/iscsi-target-ansible/)
|
||
|
||
**Requirements:**
|
||
|
||
- 运行中的 Ceph **Luminous (12.2.x) 或更新**集群;
|
||
- RHEL/CentOS **7.5(或更新)**;Linux kernel **v4.16(或更新)**;
|
||
- 所有 iSCSI gateway 节点上已安装 `ceph-iscsi` 包。
|
||
|
||
**Installation:**
|
||
|
||
```bash
|
||
# 在 Ansible installer 节点(可以是管理节点或专用部署节点)
|
||
yum install ceph-ansible
|
||
```
|
||
|
||
在 `/etc/ansible/hosts` 中添加 gateway 组条目:
|
||
|
||
```ini
|
||
[iscsigws]
|
||
ceph-igw-1
|
||
ceph-igw-2
|
||
```
|
||
|
||
> 官方 note:如果 iSCSI gateway 与 OSD 节点共存,则把该 OSD 节点也加到 `[iscsigws]` 段。
|
||
|
||
**Configuration(Ansible 变量逐项):**
|
||
|
||
`ceph-ansible` 会在 `/usr/share/ceph-ansible/group_vars/` 下放一个 `iscsigws.yml.sample`,复制一份命名为 `iscsigws.yml` 后按需修改。
|
||
|
||
| 变量 | 含义/用途 | 默认值 |
|
||
|---|---|---|
|
||
| `seed_monitor` | 每个 gateway 都需要访问 ceph 集群以执行 rados 和 rbd 调用,这意味着 iSCSI gateway 必须定义了适当的 `/etc/ceph/` 目录。`seed_monitor` 主机用于填充 iSCSI gateway 的 `/etc/ceph/` 目录 | 文档未明确 |
|
||
| `cluster_name` | 定义自定义的存储集群名 | 文档未明确 |
|
||
| `gateway_keyring` | 定义自定义 keyring 名 | 文档未明确 |
|
||
| `deploy_settings` | 若设为 `true`,则在运行 playbook 时部署这些设置 | 文档未明确 |
|
||
| `perform_system_checks` | 布尔值,检查每个 gateway 上的 multipath 与 lvm 配置设置。**首次运行时必须设为 `true`**,以确保 multipathd 与 lvm 被正确配置 | 文档未明确 |
|
||
| `api_user` | API 的用户名 | `admin` |
|
||
| `api_password` | 使用 API 的密码 | `admin` |
|
||
| `api_port` | 使用 API 的 TCP 端口号 | `5000` |
|
||
| `api_secure` | 若必须使用 TLS 则为 true。若为 true,用户必须创建所需的证书与密钥文件(详见 gwcli man 文件) | `false` |
|
||
| `trusted_ip_list` | 有权访问 API 的 IPv4 或 IPv6 地址列表。默认只有 iSCSI gateway 节点有访问权限 | 文档未明确(默认仅限 gateway 节点) |
|
||
|
||
> 完整的 advanced variables 列表参见 `iscsigws.yml.sample`。
|
||
|
||
**Deployment:**
|
||
|
||
```bash
|
||
cd /usr/share/ceph-ansible
|
||
ansible-playbook site.yml --limit iscsigws
|
||
```
|
||
|
||
> 官方 note:Ansible playbook 会处理 RPM 依赖、设置守护进程并安装 `gwcli`,以便用它创建 iSCSI target 并把 RBD image 导出为 LUN。在过往版本中,`iscsigws.yml` 可以定义 iSCSI target 以及 clients、images、LUNs 等对象,但**这已不再被支持**。
|
||
|
||
```bash
|
||
gwcli ls
|
||
```
|
||
|
||
> ⚠️ 官方 important:**试图用 `targetcli` 工具修改配置会导致问题**,包括 ALUA 配置错误与路径故障切换问题。有可能损坏数据、导致各 iSCSI gateway 间配置不一致、WWN 信息不一致,进而引发客户端 multipath 问题。
|
||
|
||
**Service Management:**
|
||
|
||
`ceph-iscsi` 包会安装配置管理逻辑与一个名为 **`rbd-target-api`** 的 Systemd 服务。该服务设为开机启动时,`rbd-target-api` 会在启动时恢复 Linux IO 状态。Ansible playbook 在部署期间会禁用 target 服务。
|
||
|
||
```bash
|
||
systemctl <start|stop|restart|reload> rbd-target-api
|
||
```
|
||
|
||
| 操作 | 效果 |
|
||
|---|---|
|
||
| `reload` | 强制 `rbd-target-api` 重新读取配置并应用到当前运行环境。通常不需要,因为变更由 Ansible 并行部署到所有 iSCSI gateway 节点 |
|
||
| `stop` | 关闭 gateway 的 portal 接口,断开到客户端的连接,并从内核中清除当前 LIO 配置,使 iSCSI gateway 回到干净状态。客户端断开时,活动 IO 会由客户端侧 multipathing 层重新调度到其他 iSCSI gateway |
|
||
|
||
**Removing the Configuration:**
|
||
|
||
`ceph-ansible` 提供了一个用于移除 iSCSI gateway 配置及相关 RBD image 的 playbook:`/usr/share/ceph-ansible/purge_gateways.yml`。运行该 playbook 时会提示选择清除类型:
|
||
|
||
| 模式 | 效果 |
|
||
|---|---|
|
||
| `lio` | 清除所有已定义 iSCSI gateway 上的 LIO 配置。**已创建的磁盘在 Ceph 存储集群中保持不变。** |
|
||
| `all` | 移除 LIO 配置,**同时删除** iSCSI gateway 环境中定义的所有 RBD image;其他无关的 RBD image 不会被删除。**该操作会删除数据,务必选对模式。** |
|
||
|
||
```text
|
||
[root@rh7-iscsi-client ceph-ansible]# ansible-playbook purge_gateways.yml
|
||
Which configuration elements should be purged? (all, lio or abort) [abort]: all
|
||
```
|
||
|
||
> ⚠️ 官方 warning:purge 操作是对 iSCSI gateway 环境的**破坏性操作**。
|
||
>
|
||
> ⚠️ 官方 warning:如果通过 Ceph iSCSI gateway 导出的 RBD image **有快照或克隆**,purge 操作会失败。
|
||
|
||
### 13.7 Initiators
|
||
|
||
> 引自:[Configuring the iSCSI Initiators](https://docs.ceph.com/en/tentacle/rbd/iscsi-initiators/)
|
||
|
||
> ⚠️ 官方 warning:**当一个 RBD image 通过多于一个 iSCSI gateway 导出时,使用 SCSI persistent group reservations (PGR) 与 SCSI 2 based reservations 的应用不受支持。**
|
||
|
||
#### 13.7.1 Linux
|
||
|
||
> 引自:[iSCSI Initiator for Linux](https://docs.ceph.com/en/tentacle/rbd/iscsi-initiator-linux/)
|
||
|
||
**Prerequisite:** `iscsi-initiator-utils`、`device-mapper-multipath`
|
||
|
||
```bash
|
||
yum install iscsi-initiator-utils
|
||
yum install device-mapper-multipath
|
||
```
|
||
|
||
**配置 multipath:**
|
||
|
||
```bash
|
||
mpathconf --enable --with_multipathd y
|
||
```
|
||
|
||
在 `/etc/multipath.conf` 中添加:
|
||
|
||
```text
|
||
devices {
|
||
device {
|
||
vendor "LIO-ORG"
|
||
product "TCMU device"
|
||
hardware_handler "1 alua"
|
||
path_grouping_policy "failover"
|
||
path_selector "queue-length 0"
|
||
failback 60
|
||
path_checker tur
|
||
prio alua
|
||
prio_args exclusive_pref_bit
|
||
fast_io_fail_tmo 25
|
||
no_path_retry queue
|
||
}
|
||
}
|
||
```
|
||
|
||
```bash
|
||
systemctl reload multipathd
|
||
```
|
||
|
||
**iSCSI Discovery and Setup:** 在 `/etc/iscsi/iscsid.conf` 中启用 CHAP 认证:
|
||
|
||
```ini
|
||
node.session.auth.authmethod = CHAP
|
||
node.session.auth.username = myusername
|
||
node.session.auth.password = mypassword
|
||
```
|
||
|
||
(双向认证再加:)
|
||
|
||
```ini
|
||
node.session.auth.username_in = mytgtusername
|
||
node.session.auth.password_in = mytgtpassword
|
||
```
|
||
|
||
```bash
|
||
iscsiadm -m discovery -t st -p 192.168.56.101
|
||
```
|
||
|
||
```text
|
||
192.168.56.101:3260,1 iqn.2003-01.org.linux-iscsi.rheln1
|
||
192.168.56.102:3260,2 iqn.2003-01.org.linux-iscsi.rheln1
|
||
```
|
||
|
||
```bash
|
||
iscsiadm -m node -T iqn.2003-01.org.linux-iscsi.rheln1 -l # 登录
|
||
```
|
||
|
||
**Multipath IO Setup:**
|
||
|
||
```bash
|
||
multipath -ll
|
||
```
|
||
|
||
```text
|
||
mpathbt (360014059ca317516a69465c883a29603) dm-1 LIO-ORG ,IBLOCK
|
||
size=1.0G features='0' hwhandler='1 alua' wp=rw
|
||
|-+- policy='queue-length 0' prio=50 status=active
|
||
| `- 28:0:0:1 sde 8:64 active ready running
|
||
`-+- policy='queue-length 0' prio=10 status=enabled
|
||
`- 29:0:0:1 sdc 8:32 active ready running
|
||
```
|
||
|
||
> 注意每条路径都被放到了各自的 priority group 中(failover 配置)。现在就可以像使用普通 multipath iSCSI 磁盘一样使用该 RBD image 了。
|
||
|
||
```bash
|
||
iscsiadm -m node -T iqn.2003-01.org.linux-iscsi.rheln1 -u # 登出
|
||
```
|
||
|
||
#### 13.7.2 Microsoft Windows
|
||
|
||
> 引自:[iSCSI Initiator for Microsoft Windows](https://docs.ceph.com/en/tentacle/rbd/iscsi-initiator-win/)
|
||
|
||
**Prerequisite:** Microsoft Windows Server **2016 或更新**
|
||
|
||
**iSCSI Initiator、Discovery 与 Setup:**
|
||
|
||
1. 安装 iSCSI initiator 驱动与 MPIO 工具;
|
||
2. 启动 MPIO 程序,点击 "Discover Multi-Paths" 标签页,勾选 "Add support for iSCSI devices",点击 "Add"。**这需要重启;**
|
||
3. 在 iSCSI Initiator Properties 窗口的 "Discovery" 标签页,添加一个 target portal:输入 Ceph iSCSI gateway 的 IP 地址或 DNS 名称与端口;
|
||
4. 在 "Targets" 标签页,选择 target 并点击 "Connect";
|
||
5. 在 "Connect To Target" 窗口,选择 "Enable multi-path" 选项,然后点击 "Advanced" 按钮;
|
||
6. 在 "Connect using" 部分,选择一个 "Target portal IP"。选择 "Enable CHAP login on" 并输入 Ceph iSCSI Ansible client credentials 段中的 "Name" 与 "Target secret" 值,点击 OK;
|
||
7. 对设置 iSCSI gateway 时定义的**每个** target portal 重复步骤 5 和 6。
|
||
|
||
**Multipath IO Setup:**
|
||
|
||
```powershell
|
||
Set-MPIOSetting -NewPDORemovePeriod 120
|
||
mpclaim.exe -l -m 1
|
||
```
|
||
|
||
```text
|
||
mpclaim -s -m
|
||
MSDSM-wide Load Balance Policy: Fail Over Only
|
||
```
|
||
|
||
8. 用 iSCSI Initiator 工具,从 "Targets" 标签页点击 "Devices..." 按钮;
|
||
9. 在 Devices 窗口中选择一个磁盘并点击 "MPIO..." 按钮;
|
||
10. 在 "Device Details" 窗口会显示到每个 target portal 的路径。如果使用 `ceph-ansible` 设置方式,iSCSI gateway 会用 **ALUA** 告知 iSCSI initiator 哪个路径与哪个 iSCSI gateway 应作为主路径。**必须选择 Load Balancing Policy "Fail Over Only"**;
|
||
|
||
```powershell
|
||
mpclaim -s -d $MPIO_DISK_ID
|
||
```
|
||
|
||
> 官方 note:使用 `ceph-ansible` 设置方式时,会有**一条 Active/Optimized 路径**(通往拥有该 LUN 的 iSCSI gateway 节点),以及**每个其他 iSCSI gateway 节点各一条 Active/Unoptimized 路径**。
|
||
|
||
> 官方 note:建议把 `PDORemovePeriod` 提高到 **120 秒**(PowerShell)。该值可能需要根据应用调整。当所有路径都 down 且 120 秒到期后,操作系统会开始让 IO 请求失败。
|
||
|
||
**Tuning(注册表):**
|
||
|
||
| 项 | 路径 | 值 |
|
||
|---|---|---|
|
||
| Windows Disk Timeout | `HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Disk` | `TimeOutValue = 65` |
|
||
| Microsoft iSCSI Initiator Driver | `HKEY_LOCAL_MACHINE\\SYSTEM\CurrentControlSet\Control\Class\{4D36E97B-E325-11CE-BFC1-08002BE10318}\<Instance_Number>\Parameters` | `LinkDownTime = 25`、`SRBTimeoutDelta = 15` |
|
||
|
||
#### 13.7.3 VMware ESX
|
||
|
||
> 引自:[iSCSI Initiator for VMware ESX](https://docs.ceph.com/en/tentacle/rbd/iscsi-initiator-esx/)
|
||
|
||
**Prerequisite:** VMware ESX **6.5 或更新**,使用 Virtual Machine compatibility 6.5 与 VMFS 6。
|
||
|
||
以下步骤使用默认的 vSphere web client 与 esxcli。
|
||
|
||
1. **启用 Software iSCSI**:从 "Navigator" 点击 "Storage",选择 "Adapters" 标签页,右键 "Configure iSCSI";
|
||
2. **设置 Initiator Name**:如果 "Name & alias" 段中的 initiator 名称与 gwcli 设置期间创建客户端时使用的名称(或 ansible `client_connections` 变量中使用的 initiator 名)不同,则 ssh 到 ESX 主机并执行以下 esxcli 命令修改:
|
||
|
||
```text
|
||
> esxcli iscsi adapter list
|
||
> Adapter Driver State UID Description
|
||
> ------- --------- ------ ------------- ----------------------
|
||
> vmhba64 iscsi_vmk online iscsi.vmhba64 iSCSI Software Adapter
|
||
```
|
||
|
||
```text
|
||
> esxcli iscsi adapter set -A vmhba64 -n iqn.1994-05.com.redhat:rh7-client
|
||
```
|
||
|
||
3. **设置 CHAP**:展开 CHAP authentication 段,选择 "Do not use CHAP unless required by target",并输入 gwcli `auth` 命令或 ansible `client_connections` credentials 变量中使用的 CHAP 凭据。
|
||
**Mutual CHAP authentication 段应选择 "Do not use CHAP"。**
|
||
|
||
> web client 有一个 bug:请求的 CHAP 设置有时不会立即生效。在 iSCSI gateway 内核日志中会看到:
|
||
>
|
||
> ```text
|
||
> > kernel: CHAP user or password not set for Initiator ACL
|
||
> > kernel: Security negotiation failed.
|
||
> > kernel: iSCSI Login negotiation failed.
|
||
> ```
|
||
>
|
||
> 规避方法是用 esxcli 命令设置 CHAP(下面 `authname` 是用户名,`secret` 是前面示例中的密码):
|
||
|
||
```text
|
||
> esxcli iscsi adapter auth chap set --direction=uni --authname=myiscsiusername --secret=myiscsipassword --level=discouraged -A vmhba64
|
||
```
|
||
|
||
4. **配置 iSCSI 设置**:展开 Advanced settings,把 "RecoveryTimeout" 设为 **25**;
|
||
5. **设置 discovery 地址**:在 Dynamic targets 段点击 "Add dynamic target",在 Addresses 下添加一个 gateway IP 地址(gwcli 阶段设置的 gateway IP,或 ansible `gateway_ip_list` 变量中的某个 IP)。**只需添加一个地址**,因为 gateway 已设置为在 discovery 期间返回所有 iSCSI portal。最后点击 "Save configuration" 按钮。在 Devices 标签页中应能看到 RBD image。
|
||
|
||
LUN 应被自动配置,并使用 **ALUA SATP** 与 **MRU PSP**。**不得使用其他 SATP 和 PSP。** 可用以下命令校验:
|
||
|
||
```text
|
||
> esxcli storage nmp path list -d eui.your_devices_id
|
||
```
|
||
|
||
### 13.8 Monitoring
|
||
|
||
> 引自:[Monitoring Ceph iSCSI gateways](https://docs.ceph.com/en/tentacle/rbd/iscsi-monitoring/)
|
||
|
||
Ceph 提供了一个工具用于监控导出 RBD image 的性能。
|
||
|
||
**`gwtop`** 是一个类 `top` 的工具,显示通过 iSCSI 导出给客户端的 RBD image 的聚合性能指标。指标来源于 **Performance Metrics Domain Agent (PMDA)**;来自 **Linux-IO target (LIO) PMDA** 的信息用于列出每个导出的 RBD image、连接的客户端及其关联的 I/O 指标。
|
||
|
||
**Requirements:** 一个运行中的 Ceph iSCSI gateway。
|
||
|
||
**Installing(在每个 iSCSI gateway 节点上以 root 执行):**
|
||
|
||
```bash
|
||
yum install ceph-iscsi-tools
|
||
yum install pcp
|
||
yum install pcp-pmda-lio
|
||
|
||
systemctl enable pmcd
|
||
systemctl start pmcd
|
||
|
||
cd /var/lib/pcp/pmdas/lio
|
||
./Install
|
||
```
|
||
|
||
- 默认情况下,`gwtop` 假定 iSCSI gateway 配置对象存储在 **`rbd` pool 中一个名为 `gateway.conf` 的 RADOS 对象**里。该配置定义了要联系哪些 iSCSI gateway 以收集性能统计。可通过 `-g` 或 `-c` 标志覆盖,详见 `gwtop --help`;
|
||
- LIO 配置决定从 performance co-pilot 提取哪类性能统计。`gwtop` 启动时会查看 LIO 配置,**如果发现 user-space 磁盘,就自动选择 LIO collector**。
|
||
|
||
**示例输出:**
|
||
|
||
```text
|
||
gwtop 2/2 Gateways CPU% MIN: 4 MAX: 5 Network Total In: 2M Out: 3M 10:20:00
|
||
Capacity: 8G Disks: 8 IOPS: 503 Clients: 1 Ceph: HEALTH_OK OSDs: 3
|
||
Pool.Image Src Size iops rMB/s wMB/s Client
|
||
iscsi.t1703 500M 0 0.00 0.00
|
||
iscsi.testme1 500M 0 0.00 0.00
|
||
iscsi.testme2 500M 0 0.00 0.00
|
||
iscsi.testme3 500M 0 0.00 0.00
|
||
iscsi.testme5 500M 0 0.00 0.00
|
||
rbd.myhost_1 T 4G 504 1.95 0.00 rh460p(CON)
|
||
rbd.test_2 1G 0 0.00 0.00
|
||
rbd.testme 500M 0 0.00 0.00
|
||
```
|
||
|
||
> 在 *Client* 列中,`(CON)` 表示该 iSCSI initiator(客户端)当前已登录到 iSCSI gateway。若显示 `-multi-`,则表示**多个客户端映射到了同一个 RBD image**。
|
||
|
||
---
|
||
|
||
## 十四、NVMe-oF
|
||
|
||
### 14.1 Overview
|
||
|
||
> 引自:[Ceph NVMe-oF Gateway](https://docs.ceph.com/en/tentacle/rbd/nvmeof-overview/)
|
||
|
||
存储管理员可以为 Storage Ceph 集群安装并配置 NVMe over Fabrics (NVMe-oF) gateway。借助 Ceph NVMe-oF gateway,你可以运行一套完全集成的块存储基础设施,具备传统 SAN 的全部特性与优势。
|
||
|
||
NVMe-oF gateway 把 Storage Ceph 与 **NVMe over TCP (NVMe/TCP)** 协议集成,提供一个导出 RBD image 的 NVMe/TCP target。NVMe/TCP 协议允许客户端(称为 **initiators**)通过 IP 网络向存储设备(称为 **targets**)发送 NVMe-oF 命令。Initiator 可以是 Linux 客户端、VMware 客户端,或两者兼有。**对 VMware 客户端,NVMe/TCP 卷表现为 VMFS Datastore;对 Linux 客户端,NVMe/TCP 卷表现为块设备。**
|
||
|
||
```text
|
||
Cluster Network (optional)
|
||
+-------------------------------------------+
|
||
| | | |
|
||
+-------+ +-------+ +-------+ +-------+
|
||
| | | | | | | |
|
||
| OSD 1 | | OSD 2 | | OSD 3 | | OSD N |
|
||
| {s}| | {s}| | {s}| | {s}|
|
||
+-------+ +-------+ +-------+ +-------+
|
||
| | | |
|
||
+--------->| | +---------+ | |<----------+
|
||
: | | | RBD | | | :
|
||
| +----------------| Image |----------------+ |
|
||
| Public Network | {d} | |
|
||
| +---------+ |
|
||
| |
|
||
| +--------------------+ |
|
||
| +--------------+ | NVMeoF Initiators | +--------------+ |
|
||
| | NVMe‐oF GW | | +-----------+ | | NVMe‐oF GW | |
|
||
+-->| RBD Module |<--+ | Various | +-->| RBD Module |<--+
|
||
| | | | Operating | | | |
|
||
+--------------+ | | Systems | | +--------------+
|
||
| +-----------+ |
|
||
+--------------------+
|
||
```
|
||
|
||
#### 高可用(HA)与 gateway group
|
||
|
||
- **HA(高可用性)**为主机 initiator 提供 I/O 与控制路径冗余,有时也称为 failover 与 failback 支持。这种冗余对于防范一个或多个 gateway 故障至关重要。有了 HA,即使有 gateway 失效,主机也能继续 I/O,最多只是可能有性能延迟,直到故障 gateway 恢复正常;
|
||
- NVMe-oF gateway 被**虚拟地分组为 gateway groups,HA 域位于 gateway group 内**。一个 NVMe-oF gateway group **目前支持 8 个 gateway**。group 中每个 gateway 都可以作为通往该 group 中定义的任一 subsystem 或 namespace 的路径。**HA 在 gateway group 中有两个及以上 gateway 时才有效**;
|
||
- **HA 默认启用**。要使用 HA,必须为每个 subsystem 在所有 GW 上定义**至少两个 gateway 和两个 listener**;
|
||
- 必须在主机与 gateway 之间建立冗余:为获得完全冗余的网络连接,主机应有**两个以太网口**,通过具备冗余的网络(例如两台网络交换机)连接到 gateway;
|
||
- **HA 对每个 namespace 使用 Active/Standby 方式**:任意时刻只有该 gateway group 中的一个 NVMe-oF gateway 为某个特定 namespace 提供主机 I/O。为了充分利用所有 NVMe-oF gateway,**每个 namespace 被分配到不同的 load-balancing group**。load-balancing group 的数量等于 gateway group 中 NVMe-oF gateway 的数量;
|
||
- 如果 group 中一个或多个 GW 失效或无法被 Ceph NVMe-oF monitor 看到,会**自动触发 failover**,group 中另一个 GW 将接管失效 GW 的 load-balancing group。这意味着 **IO 不会中断**,因为会有另一个 GW 继续服务这些 namespace。如果失效的 GW 重新出现,会**自动触发 failback**;
|
||
- 主机上的 NVMe-oF initiator 也会继续尝试连接失效的 GW,持续时间为 `connect-all` 命令中指定的时间。**推荐值为 1800 秒。**
|
||
|
||
#### Scale-out 上限(官方明确数字)
|
||
|
||
| 维度 | 上限 |
|
||
|---|---|
|
||
| NVMe-oF gateway groups | **4** |
|
||
| 每个 gateway group 中的 NVMe-oF gateway | **8** |
|
||
| 每个 gateway group 中的 NVMe-oF subsystem | **128** |
|
||
| 每个 NVMe-oF subsystem 的主机数 | **32** |
|
||
| 每个 gateway group 的 namespace 数 | **1024** |
|
||
|
||
#### Discovery
|
||
|
||
Ceph NVMe-oF gateway 支持 Discovery。**每个运行在 Ceph 集群中的 NVMe-oF gateway 同时运行一个 Discovery Controller**,该 Discovery Controller 报告 GW group 中的所有 Subsystem。
|
||
|
||
### 14.2 Requirements
|
||
|
||
> 引自:[NVMe-oF Gateway Requirements](https://docs.ceph.com/en/tentacle/rbd/nvmeof-requirements/)
|
||
|
||
| 项 | 要求 |
|
||
|---|---|
|
||
| 内存 | 每个 NVMe-oF gateway 实例**至少 8 GB** 专用内存 |
|
||
| CPU | **强烈建议**为每个 NVMe-oF gateway 专用**至少 4 个 CPU 线程或 vcore**。只用 1 个线程/vcore 也能工作,但性能可能低于预期。**最好为 NVMe-oF gateway 服务专用服务器**,以免与其他 Ceph 服务互相拖累 |
|
||
| 网络 | 到 Ceph public network **至少 10 Gb/s** 链路。为获得最佳延迟与吞吐,**推荐 25 Gb/s 或 100 Gb/s** 链路 |
|
||
| Bonding | 链路绑定(配合适当的 xmit hash policy)对高可用性是理想的。**注意:某个 NVMe-oF 客户端的吞吐不会高于 bond 中单条链路的吞吐。** 因此,如果 gateway 节点上绑定了 4 条 10 Gb/s 链路,单个客户端实现的吞吐不会超过 10 Gb/s。**注意 Ceph NVMe-oF gateway 同时还要通过 public network 与后端 OSD 通信**,这与客户端到 gateway 的流量相互争用。**网络资源务必预留充足,避免拥塞与饱和** |
|
||
| 高可用 | 在一个 gateway group 中、**在独立的 Ceph 集群节点上**至少配置 **2 个** NVMe-oF gateway,以构成高可用的 Ceph NVMe/TCP 方案 |
|
||
| 代理 | Ceph NVMe-oF gateway 容器由多个相互通信的组件构成。如果运行这些容器的节点需要 HTTP/HTTPS 代理配置才能访问容器注册表或其他外部资源,这些设置可能**干扰容器内部通信**。如果在供给 NVMe-oF gateway 时遇到 gRPC 或其他错误,可能需要调整代理配置 |
|
||
|
||
### 14.3 安装与配置 NVMe-oF Target
|
||
|
||
> 引自:[Installing and Configuring NVMe-oF Targets](https://docs.ceph.com/en/tentacle/rbd/nvmeof-target-configure/)
|
||
|
||
**Prerequisites:**
|
||
|
||
- 一个可用的 **Ceph Tentacle 或更新**存储集群,使用 **`cephadm`** 部署;
|
||
- NVMe-oF gateway,可与 OSD 节点共存或使用专用节点;
|
||
- **独立的网络子网**用于 NVMe-oF 前端流量与 Ceph 后端流量。
|
||
|
||
Ceph NVMe-oF gateway 既是 NVMe-oF target 也是 Ceph 客户端——可以把它看作 Ceph RBD 接口与 NVMe-oF 协议之间的"翻译器"。
|
||
|
||
**Installation:**
|
||
|
||
```bash
|
||
# 1) 创建用于管理 gateway 配置的 pool
|
||
ceph osd pool create NVME-OF_POOL_NAME
|
||
|
||
# 2) 在该 pool 上启用 RBD
|
||
rbd pool init NVME-OF_POOL_NAME
|
||
|
||
# 3) 在指定节点集合上部署 NVMe-oF gateway 守护进程
|
||
ceph orch apply nvmeof NVME-OF_POOL_NAME --placement="host01, host02"
|
||
```
|
||
|
||
**Configuration:**
|
||
|
||
首次使用前先下载 `nvmeof-cli` 容器:
|
||
|
||
```bash
|
||
podman pull quay.io/ceph/nvmeof-cli:latest
|
||
```
|
||
|
||
```bash
|
||
# 1) 创建 NVMe subsystem(subsystem NQN 是用户自定义字符串,例如 nqn.2016-06.io.spdk:cnode1)
|
||
podman run -it --rm quay.io/ceph/nvmeof-cli:latest --server-address GATEWAY_IP --server-port GATEWAY_PORT 5500 subsystem add --subsystem SUSYSTEM_NQN
|
||
|
||
# 2a) 在安装节点上获取 NVMe-oF Gateway 名称
|
||
ceph orch ps | grep nvme
|
||
|
||
# 2b) 定义 gateway 上处理 NVMe/TCP 命令与 I/O 的 IP 端口
|
||
podman run -it --rm quay.io/ceph/nvmeof-cli:latest --server-address GATEWAY_IP --server-port GATEWAY_PORT 5500 listener add --subsystem SUBSYSTEM_NQN --host-name HOST_NAME --traddr GATEWAY_IP --trsvcid 4420
|
||
|
||
# 3) 获取每台主机的 host NQN(NVMe Qualified Name)
|
||
cat /etc/nvme/hostnqn # Linux
|
||
esxcli nvme info get # ESX
|
||
|
||
# 4) 允许 initiator 主机连接到新建的 NVMe subsystem
|
||
podman run -it --rm quay.io/ceph/nvmeof-cli:latest --server-address GATEWAY_IP --server-port GATEWAY_PORT 5500 host add --subsystem SUBSYSTEM_NQN --host "HOST_NQN1 HOST_NQN2"
|
||
|
||
# 5) 列出 gateway 中配置的所有 subsystem
|
||
podman run -it --rm quay.io/ceph/nvmeof-cli:latest --server-address GATEWAY_IP --server-port GATEWAY_PORT 5500 subsystem list
|
||
|
||
# 6) 创建新的 NVMe namespace
|
||
podman run -it quay.io/ceph/nvmeof-cli:latest --server-address GATEWAY_IP --server-port GATEWAY_PORT 5500 namespace add --subsystem SUBSYSTEM_NQN --rbd-pool POOL_NAME --rbd-image IMAGE_NAME
|
||
|
||
# 7) 列出 subsystem 中的所有 namespace
|
||
podman run -it quay.io/ceph/nvmeof-cli:latest --server-address GATEWAY_IP --server-port GATEWAY_PORT 5500 namespace list --subsystem SUBSYSTEM_NQN
|
||
```
|
||
|
||
> 💡 补充:源文中 `subsystem add` 与 `namespace add` 的模板写作 `SUSYSTEM_NQN`(typo,应为 `SUBSYSTEM_NQN`),使用时按 `SUBSYSTEM_NQN` 理解。此外 `--server-port GATEWAY_PORT 5500` 这种写法在源文中同时出现了 `GATEWAY_PORT` 与 `5500` 两个记号;`5500` 是 `rbd-target-api` 风格的 API 端口写法,`4420` 是 NVMe/TCP 数据端口、`8009` 是 Discovery controller 端口(见 14.4)。请以实际环境的 gateway API 端口为准。
|
||
|
||
### 14.4 Initiators
|
||
|
||
> 引自:[Configuring the NVMe-oF Initiators](https://docs.ceph.com/en/tentacle/rbd/nvmeof-initiators/)
|
||
|
||
支持两类 initiator:**Linux** 与 **VMware ESX**。
|
||
|
||
#### 14.4.1 Linux
|
||
|
||
> 引自:[NVMe/TCP Initiator for Linux](https://docs.ceph.com/en/tentacle/rbd/nvmeof-initiator-linux/)
|
||
|
||
**Prerequisites:**
|
||
|
||
| 项 | 要求 |
|
||
|---|---|
|
||
| 内核 | **5.0 或更新** |
|
||
| RHEL | **9.2 或更新** |
|
||
| Ubuntu | **24.04 或更新** |
|
||
| SLES | **15 SP3 或更新** |
|
||
|
||
```bash
|
||
# 1) 安装 nvme-cli
|
||
yum install nvme-cli
|
||
|
||
# 2) 加载 NVMe-oF 模块
|
||
modprobe nvme-fabrics
|
||
|
||
# 3) 验证 NVMe/TCP target 可达
|
||
nvme discover -t tcp -a GATEWAY_IP -s 8009
|
||
|
||
# 4) 连接到 NVMe/TCP target。为高可用,使用 connect-all 命令
|
||
nvme connect-all --traddr GATEWAY_IP --transport tcp -l 1800 -s 8009
|
||
```
|
||
|
||
- `-l 1800`:推荐值,允许 initiator 在 **1800 秒**内持续尝试连接 GW。这在 GW 因任何原因临时不可用时很有帮助;
|
||
- `-s 8009`:**Discovery controller 的端口地址**。`connect-all` 命令会先连接到 DC,然后用其返回的信息连接各个 GW。
|
||
|
||
**验证:**
|
||
|
||
```bash
|
||
# 1) 验证 initiator 已连接到 gateway group 中的所有 NVMe-oF gateway 与 subsystem
|
||
nvme list-subsys
|
||
```
|
||
|
||
```text
|
||
nvme-subsys<X> - NQN=<NQN>
|
||
\
|
||
+- nvmeX tcp traddr=<GW IP>,trsvcid=4420 live
|
||
+- nvmeY tcp traddr=<GW IP>,trsvcid=4420 live
|
||
+- nvmeZ tcp traddr=<GW IP>,trsvcid=4420 live
|
||
+- nvmeW tcp traddr=<GW IP>,trsvcid=4420 live
|
||
```
|
||
|
||
```bash
|
||
# 2) 列出 NVMe 块设备
|
||
nvme list
|
||
|
||
# 3) 在目标设备上创建文件系统
|
||
mkfs.ext4 NVME_NODE_PATH
|
||
|
||
# 4) 挂载文件系统
|
||
mkdir /mnt/nvmeof
|
||
mount NVME_NODE_PATH /mnt/nvmeof
|
||
|
||
# 5) 列出 NVMe-oF 文件
|
||
ls /mnt/nvmeof
|
||
|
||
# 6) 在 /mnt/nvmeof 目录创建一个文本文件
|
||
echo "Hello NVME-oF" > /mnt/nvmeof/hello.text
|
||
|
||
# 7) 验证文件可访问
|
||
cat /mnt/nvmeof/hello.text
|
||
```
|
||
|
||
#### 14.4.2 VMware ESX
|
||
|
||
> 引自:[NVMe/TCP Initiator for VMware ESX](https://docs.ceph.com/en/tentacle/rbd/nvmeof-initiator-esx/)
|
||
|
||
**Prerequisites:**
|
||
|
||
- 运行 **VMware vSphere Hypervisor (ESXi) 7.0U3 或更新**的 VMware ESXi 主机;
|
||
- 已部署的 Ceph NVMe-oF gateway;
|
||
- 带有 NVMe-oF 配置的 Ceph 集群;
|
||
- gateway 中已定义的 subsystem。
|
||
|
||
**Configuration(vSphere web client + esxcli):**
|
||
|
||
```bash
|
||
# 1) 在 NIC 上启用 NVMe/TCP(把 N 换成 NIC 编号)
|
||
esxcli nvme fabric enable --protocol TCP --device vmnicN
|
||
|
||
# 2) 给 VMKernel NIC 打标签以允许 NVMe/TCP 流量(把 N 换成 VMkernel 的 ID)
|
||
esxcli network uip interface tag add --interface-nme vmkN --tagname NVMeTCP
|
||
|
||
# 3a) 列出 NVMe-oF adapter
|
||
esxcli nvme adapter list
|
||
|
||
# 3b) 可选:发现 NVMe-oF subsystem
|
||
esxcli nvme fabric discover -a NVME_TCP_ADAPTER -i GATEWAY_IP -p 4420
|
||
|
||
# 3c) 连接到 NVMe-oF gateway subsystem
|
||
esxcli nvme fabrics discover -a NVME_TCP_ADAPTER -i GATEWAY_IP -p 8009 -c
|
||
```
|
||
|
||
> `-c` 会发现 gateway group 中的 NVMe-oF gateway,然后连接到这些 gateway 以**提供 multipath 访问**。
|
||
|
||
```bash
|
||
# 3d) 列出 NVMe/TCP controller
|
||
esxcli nvme controller list
|
||
|
||
# 3e) 列出 subsystem 中的 NVMe-oF namespace
|
||
esxcli nvme namespace list
|
||
```
|
||
|
||
**验证:** 从 vSphere client 进入 ESXi 主机 → 在 Storage 页面进入 Devices 标签页 → 确认表中列出了 NVMe/TCP 磁盘。
|
||
|
||
### 14.5 iSCSI 与 NVMe-oF 对比
|
||
|
||
> 💡 补充:官方未直接给出两者的对比表,下表基于本册两个章节的源文事实整理。
|
||
|
||
| 维度 | iSCSI Gateway | NVMe-oF Gateway |
|
||
|---|---|---|
|
||
| 维护状态 | **自 2022-11 起 maintenance,不再新增特性** | 活跃开发 |
|
||
| 协议 | iSCSI over TCP/IP(SCSI 语义) | NVMe/TCP(NVMe 语义) |
|
||
| 内核子系统 | LIO + TCMU(userspace passthrough)→ librbd | NVMe-oF gateway → RBD Module(容器化) |
|
||
| 部署方式 | `ceph-ansible` 或 CLI(`gwcli`) | **`cephadm`** + `nvmeof-cli` 容器 |
|
||
| 集群版本要求 | Luminous+ | **Tentacle+** |
|
||
| OS 要求 | RHEL/CentOS 7.5+,kernel v4.16+ | 客户端:Linux kernel 5.0+ / RHEL 9.2+ / Ubuntu 24.04+ / SLES 15 SP3+ / ESXi 7.0U3+ |
|
||
| 网络建议 | 前后端独立子网;端口 3260(数据)/ 5000(API) | 至少 10 Gb/s,推荐 25/100 Gb/s;前后端独立子网;端口 4420(数据)/ 8009(Discovery) |
|
||
| 网关数量建议 | 2–4 个节点 | gateway group 内最多 8 个,group 最多 4 个 |
|
||
| HA 机制 | ALUA + 客户端 multipath(Linux `multipathd`、Windows MPIO、ESXi SATP/PSP) | 内建 Active/Standby per namespace + 自动 failover/failback |
|
||
| 认证 | **必须配置 CHAP**(否则拒绝登录),支持双向 CHAP | 源文未提及 CHAP(`nvmeof-*` 页面);以 subsystem/host NQN 控制访问 |
|
||
| 监控 | `gwtop`(PCP + LIO PMDA) | 源文未提及专门监控工具 |
|
||
| 限制 | 不支持 SCSI PGR / SCSI-2 reservations(多 gateway 导出同一 RBD image 时) | 单客户端吞吐受限于 bond 单链路;命名空间按 gateway 数分组负载均衡 |
|
||
| 客户端形态 | Linux / Windows Server 2016+ / ESXi 6.5+ | Linux / ESXi 7.0U3+(Windows 未在 `nvmeof-*` 源文中出现) |
|
||
|
||
---
|
||
|
||
## 十五、其他
|
||
|
||
### 15.1 RBD Replay
|
||
|
||
> 引自:[RBD Replay](https://docs.ceph.com/en/tentacle/rbd/rbd-replay/)
|
||
|
||
RBD Replay 是一套用于**捕获(capture)与回放(replay)RADOS Block Device (RBD) 工作负载**的工具。
|
||
|
||
**版本要求:**
|
||
|
||
| 动作 | 要求 |
|
||
|---|---|
|
||
| 捕获工作负载 | 客户端必须安装 **`lttng-tools`**;客户端的 `librbd` 必须是 **v0.87 (Giant) 或更新** |
|
||
| 回放工作负载 | 客户端的 `librbd` 必须是 **Giant 或更新** |
|
||
|
||
**三步流程:**
|
||
|
||
```bash
|
||
# 1) 捕获 trace。务必捕获 pthread_id 上下文
|
||
mkdir -p traces
|
||
lttng create -o traces librbd
|
||
lttng enable-event -u 'librbd:*'
|
||
lttng add-context -u -t pthread_id
|
||
lttng start
|
||
# run RBD workload here
|
||
lttng stop
|
||
```
|
||
|
||
```bash
|
||
# 2) 用 rbd-replay-prep 处理 trace
|
||
rbd-replay-prep traces/ust/uid/*/* replay.bin
|
||
```
|
||
|
||
```bash
|
||
# 3) 用 rbd-replay 回放 trace。在确定它确实在做你想做的事之前,使用 read-only
|
||
rbd-replay --read-only replay.bin
|
||
```
|
||
|
||
> ⚠️ 官方 important:**`rbd-replay` 默认会破坏数据。** 不要对希望保留的 image 使用,除非加上 `--read-only` 选项。
|
||
|
||
- 回放的工作负载**不必**针对与捕获时相同的 RBD image,甚至不必是同一个集群;
|
||
- 为了适配差异,可能需要使用 `rbd-replay` 的 **`--pool`** 与 **`--map-image`** 选项。
|
||
|
||
**相关 man page:** `rbd-replay(8)`、`rbd-replay-prep(8)`、`rbd-replay-many(8)`(见 15.3)。
|
||
|
||
### 15.2 rbd-ko(内核模块操作)
|
||
|
||
> 引自:[Kernel Module Operations](https://docs.ceph.com/en/tentacle/rbd/rbd-ko/)
|
||
|
||
> 📌 说明:任务书把 `rbd-ko.rst` 描述为"对象映射内核对象",但**该页实际内容是"内核模块操作"**(`rbd device map` / `list` / `unmap`),并不涉及 object map 的内核对象结构。本章按其真实内容定位,完整内容见第四章「内核模块与客户端」。
|
||
|
||
| 操作 | 命令 |
|
||
|---|---|
|
||
| 获取 image 列表 | `rbd list` |
|
||
| map | `sudo rbd device map {pool-name}/{image-name} --id {user-name}`(可加 `--keyring` 或 `--keyfile`) |
|
||
| 显示已映射 | `rbd device list` |
|
||
| unmap | `sudo rbd device unmap /dev/rbd/{poolname}/{imagename}` |
|
||
|
||
### 15.3 RBD man pages 清单
|
||
|
||
> 引自:[Ceph Block Device Manpages](https://docs.ceph.com/en/tentacle/rbd/man/index/)
|
||
|
||
| man page | 说明(本册推断,页面本身只列出条目) |
|
||
|---|---|
|
||
| `rbd(8)` | RBD – Manage RADOS Block Device (RBD) Images |
|
||
| `rbd-fuse(8)` | 以 FUSE 方式挂载 RBD |
|
||
| `rbd-nbd(8)` | 通过 NBD 映射 RBD image(加密 image 的自动 encryption load 即通过它) |
|
||
| `rbd-ggate(8)` | FreeBSD 侧的 RBD 映射 |
|
||
| `rbd-map(8)` / `rbdmap` | `rbdmap` 服务相关 |
|
||
| `ceph-rbdnamer(8)` | RBD 设备命名(udev) |
|
||
| `rbd-replay-prep(8)` | 见 15.1 |
|
||
| `rbd-replay(8)` | 见 15.1 |
|
||
| `rbd-replay-many(8)` | 批量回放 |
|
||
|
||
---
|
||
|
||
## 十六、命令速查表
|
||
|
||
### 16.1 image 生命周期
|
||
|
||
| 命令 | 用途 |
|
||
|---|---|
|
||
| `rbd pool init {pool-name}` | 初始化 pool 供 RBD 使用 |
|
||
| `rbd create --size {MB} {pool}/{image}` | 创建 image |
|
||
| `rbd ls` / `rbd ls {pool}` | 列出 image |
|
||
| `rbd info {image}` / `rbd info {pool}/{image}` | 查看 image 信息 |
|
||
| `rbd resize --size {MB} {image}` | 扩容 |
|
||
| `rbd resize --size {MB} {image} --allow-shrink` | 缩容 |
|
||
| `rbd rm {image}` / `rbd rm {pool}/{image}` | 删除 image |
|
||
| `rbd trash mv {pool}/{image}` | 移入 trash(延迟删除) |
|
||
| `rbd trash ls [--all]` / `rbd trash ls {pool}` | 列出 trash |
|
||
| `rbd trash rm {pool}/{image-id}` | 从 trash 彻底删除(可加 `--force`、`--expires-at`) |
|
||
| `rbd trash restore {image-id}` / `rbd trash restore {pool}/{image-id} [--image new-name]` | 恢复 |
|
||
| `rbd du` | 计算实际数据用量(依赖 `fast-diff` 加速) |
|
||
| `rbd status {pool}/{image}` | 查看 watchers、PWL cache 状态、live-migration 状态 |
|
||
|
||
### 16.2 快照与克隆
|
||
|
||
| 命令 | 用途 |
|
||
|---|---|
|
||
| `rbd snap create {pool}/{image}@{snap}` | 创建快照 |
|
||
| `rbd snap ls {pool}/{image}` | 列出快照 |
|
||
| `rbd snap rollback {pool}/{image}@{snap}` | 回滚(慢,建议改用克隆) |
|
||
| `rbd snap rm {pool}/{image}@{snap}` | 删除快照(异步 snaptrim 回收空间) |
|
||
| `rbd snap purge {pool}/{image}` | 清除所有快照 |
|
||
| `rbd snap protect {pool}/{image}@{snap}` | 保护快照(克隆前必需) |
|
||
| `rbd snap unprotect {pool}/{image}@{snap}` | 取消保护(需先 flatten/删除所有克隆) |
|
||
| `rbd clone {pool}/{parent}@{snap} {pool}/{child}` | 从快照克隆(可跨 pool) |
|
||
| `rbd children {pool}/{image}@{snap}` | 列出快照的子 image |
|
||
| `rbd flatten {pool}/{image}` | 展平克隆(去除对父快照的依赖) |
|
||
|
||
### 16.3 feature 与配置
|
||
|
||
| 命令 | 用途 |
|
||
|---|---|
|
||
| `rbd feature enable {pool}/{image} {feature-name}` | 启用 image feature(如 `journaling`) |
|
||
| `rbd feature disable {pool}/{image} {feature-name}` | 禁用 image feature |
|
||
| `rbd config ...`(参见 `rbd(8)` 的 commands 段) | per-pool / per-image 配置覆盖 |
|
||
|
||
### 16.4 内核映射(krbd)与 NBD / Windows
|
||
|
||
| 命令 | 用途 |
|
||
|---|---|
|
||
| `rbd list` | 列出 image(准备映射) |
|
||
| `sudo rbd device map {pool}/{image} --id {user}` | 映射 image(krbd) |
|
||
| `sudo rbd device map {pool}/{image} --id {user} --keyring {path}` | 带 keyring 映射 |
|
||
| `sudo rbd device map {pool}/{image} --id {user} --keyfile {path}` | 带 keyfile 映射 |
|
||
| `rbd device map --exclusive ...` | 以 `RBD_LOCK_MODE_EXCLUSIVE` 映射(禁止自动锁转移) |
|
||
| `rbd device list` | 列出已映射设备 |
|
||
| `sudo rbd device unmap /dev/rbd/{pool}/{image}` | 取消映射 |
|
||
| `rbd device map -t nbd -o encryption-passphrase-file={file} {image-spec}` | 以 NBD 映射并自动加载加密 |
|
||
| `rbd device map {image} -onon-persistent`(Windows) | 非持久映射 |
|
||
| `rbd-wnbd show {image} --format=json`(Windows) | 查看映射详情(含 disk_number) |
|
||
|
||
### 16.5 缓存
|
||
|
||
| 命令 | 用途 |
|
||
|---|---|
|
||
| `rbd status {pool}/{image}` | 查看 PWL cache 状态 |
|
||
| `rbd persistent-cache flush {pool}/{image}` | 刷写 PWL 缓存到 OSD |
|
||
| `rbd persistent-cache invalidate {pool}/{image}` | 使 PWL 缓存失效并删除本地缓存文件 |
|
||
| `systemctl enable ceph-immutable-object-cache@{id}` | 启用只读父镜像缓存守护进程 |
|
||
| `ceph-immutable-object-cache -f --log-file={path}` | 前台运行该守护进程 |
|
||
|
||
### 16.6 加密
|
||
|
||
| 命令 | 用途 |
|
||
|---|---|
|
||
| `rbd encryption format [--cipher-alg aes-128\|aes-256] {image-spec} {luks1\|luks2} {passphrase-file}` | 格式化 image 为 LUKS |
|
||
| `rbd resize --size {G} --encryption-passphrase-file {file} {image-spec}` | 按有效大小 resize(补偿 header 开销) |
|
||
| `rbd device map -t nbd -o encryption-passphrase-file={file} {image-spec}` | 映射加密 image |
|
||
|
||
### 16.7 Live migration
|
||
|
||
| 命令 | 用途 |
|
||
|---|---|
|
||
| `rbd migration prepare {source} [{target}]` | 准备迁移(可加 layout 选项) |
|
||
| `rbd migration prepare --import-only --source-spec "{JSON}" {target}` | 准备 import-only 迁移 |
|
||
| `rbd migration prepare --import-only --source-spec-path {file\|-} {target}` | 从文件/STDIN 读 source-spec |
|
||
| `rbd migration execute {target}` | 执行块深度拷贝 |
|
||
| `rbd migration commit {target} [--force]` | 提交迁移(删除源) |
|
||
| `rbd migration abort {target}` | 中止迁移(删除目标、恢复源) |
|
||
| `rbd status {target}` | 查看迁移状态与进度 |
|
||
|
||
### 16.8 Mirroring
|
||
|
||
(详见第十章 10.11 表格,此处不重复)
|
||
|
||
### 16.9 QEMU / libvirt
|
||
|
||
| 命令 | 用途 |
|
||
|---|---|
|
||
| `qemu-img create -f raw rbd:{pool}/{image} {size}` | 用 QEMU 创建 image |
|
||
| `qemu-img resize rbd:{pool}/{image} {size}` | 用 QEMU 调整大小 |
|
||
| `qemu-img info rbd:{pool}/{image}` | 用 QEMU 查看信息 |
|
||
| `qemu-img convert -f qcow2 -O raw {src} rbd:{pool}/{image}` | 转换并导入 |
|
||
| `qemu -m 1024 -drive format=raw,file=rbd:{pool}/{image}` | 从 RBD image 启动 VM |
|
||
| `qemu -m 1024 -drive format=rbd,file=rbd:{pool}/{image},cache=writeback` | 启用 librbd writeback 缓存 |
|
||
| `virsh secret-define --file secret.xml` | 定义 Ceph secret |
|
||
| `virsh secret-set-value --secret {uuid} --base64 {key}` | 设置 secret 值 |
|
||
| `virsh secret-undefine {uuid}` | 删除 secret(重置前必需) |
|
||
| `virsh edit {vm-domain-name}` | 编辑 VM 配置(**必须用 virsh,不能直接用编辑器**) |
|
||
| `virsh dumpxml {vm-domain-name}` | 校验配置一致性 |
|
||
| `virsh qemu-monitor-command --hmp {domain} 'info block'` | 检查 VM 是否在与 Ceph 通信 |
|
||
| `virsh domblklist {domain} --details` | 检查设备是否存在 |
|
||
| `ceph daemon /var/run/ceph/ceph-client.cinder.*.asok help` | 访问 hypervisor 上的 client admin socket |
|
||
|
||
### 16.10 iSCSI / NVMe-oF
|
||
|
||
| 命令 | 用途 |
|
||
|---|---|
|
||
| `gwcli` / `gwcli ls` | iSCSI gateway 命令行(交互式) |
|
||
| `systemctl <start\|stop\|restart\|reload> rbd-target-api` | 管理 iSCSI API 服务 |
|
||
| `ansible-playbook site.yml --limit iscsigws` | Ansible 部署 iSCSI gateway |
|
||
| `ansible-playbook purge_gateways.yml` | 清除 iSCSI gateway 配置(`all` / `lio` / `abort`) |
|
||
| `iscsiadm -m discovery -t st -p {IP}` | iSCSI 发现 |
|
||
| `iscsiadm -m node -T {iqn} -l` / `-u` | iSCSI 登录 / 登出 |
|
||
| `multipath -ll` | 查看 multipath 拓扑 |
|
||
| `mpathconf --enable --with_multipathd y` | 生成 multipath.conf |
|
||
| `gwtop` | 监控导出的 RBD image 性能 |
|
||
| `ceph orch apply nvmeof {POOL} --placement="host01, host02"` | 部署 NVMe-oF gateway |
|
||
| `ceph orch ps \| grep nvme` | 查看 NVMe-oF gateway 名称 |
|
||
| `podman pull quay.io/ceph/nvmeof-cli:latest` | 获取 nvmeof-cli |
|
||
| `nvmeof-cli ... subsystem add --subsystem {NQN}` | 创建 NVMe subsystem |
|
||
| `nvmeof-cli ... listener add --subsystem {NQN} --host-name {H} --traddr {IP} --trsvcid 4420` | 定义 NVMe/TCP listener |
|
||
| `nvmeof-cli ... host add --subsystem {NQN} --host "{NQN1} {NQN2}"` | 授权 initiator 主机 |
|
||
| `nvmeof-cli ... namespace add --subsystem {NQN} --rbd-pool {P} --rbd-image {I}` | 创建 namespace |
|
||
| `nvme discover -t tcp -a {GW_IP} -s 8009` | Linux 发现 NVMe-oF target |
|
||
| `nvme connect-all --traddr {GW_IP} --transport tcp -l 1800 -s 8009` | Linux 连接(HA) |
|
||
| `nvme list-subsys` / `nvme list` | 查看已连接的 subsystem / 块设备 |
|
||
| `esxcli nvme fabric enable --protocol TCP --device vmnicN` | ESXi 启用 NVMe/TCP |
|
||
| `esxcli nvme fabrics discover -a {ADAPTER} -i {GW_IP} -p 8009 -c` | ESXi 发现并连接(multipath) |
|
||
| `esxcli nvme controller list` / `esxcli nvme namespace list` | ESXi 查看 controller / namespace |
|
||
| `esxcli iscsi adapter list` / `esxcli iscsi adapter set -A {A} -n {IQN}` | ESXi 查看/设置 iSCSI initiator 名 |
|
||
| `esxcli iscsi adapter auth chap set --direction=uni --authname {u} --secret {p} --level=discouraged -A {A}` | ESXi 设置 CHAP |
|
||
|
||
### 16.11 工作负载录制回放
|
||
|
||
| 命令 | 用途 |
|
||
|---|---|
|
||
| `lttng create -o traces librbd` / `lttng enable-event -u 'librbd:*'` / `lttng add-context -u -t pthread_id` / `lttng start` / `lttng stop` | 捕获 RBD 工作负载 trace |
|
||
| `rbd-replay-prep traces/ust/uid/*/* replay.bin` | 处理 trace |
|
||
| `rbd-replay --read-only replay.bin` | 回放(**默认会破坏数据,务必先加 `--read-only`**) |
|
||
| `rbd-replay --pool {P} --map-image {A}={B} replay.bin` | 回放时适配不同 pool / image 名 |
|
||
|
||
---
|
||
|
||
## 文档未明确项
|
||
|
||
以下条目在 Ceph Tentacle v20.2.4 的 `doc/rbd/` 源文与 `src/common/options/{rbd,rbd-mirror,immutable-object-cache,global,mon}.yaml.in` 中**均未给出明确答案**,本册不做臆测:
|
||
|
||
| # | 项目 | 说明 |
|
||
|---|---|---|
|
||
| 1 | krbd 的通用最低内核版本 | `rbd-ko.rst` 未给出;仅能从 `rbd-config-ref.rst` 的 image feature 表推出各 feature 所需版本(见 4.5) |
|
||
| 2 | 单 image 快照数量上限与性能影响的量化数据 | `rbd-snapshot.rst` 只说明 snaptrim 异步回收,无任何数字 |
|
||
| 3 | `Operations`(256)、`Migrating`(512)、`Non-primary`(1024)三个 feature 的**默认值** | `rbd-config-ref.rst` 的 feature 表对这三项未写 `:Default:` |
|
||
| 4 | `Operations`、`Migrating`、`Non-primary` 的 CLI 值 | 三项均未给出 `:CLI value:`(`rbd_default_features` 的 long_desc 也只列到 +128 data-pool) |
|
||
| 5 | `rbd_default_data_pool` 的默认值 | `rbd.yaml.in` 中无 `default:` 字段;validator 仅说明非法值时重置为空串 |
|
||
| 6 | `rbd_default_map_options` 的默认值 | `rbd.yaml.in` 中无 `default:` 字段 |
|
||
| 7 | `rbd_plugins` 的默认值 | `rbd.yaml.in` 中无 `default:` 字段 |
|
||
| 8 | `rbd_qos_exclude_ops` 的默认值 | `rbd.yaml.in` 中无 `default:` 字段 |
|
||
| 9 | `rbd_journal_pool` 的默认值 | `rbd.yaml.in` 中无 `default:` 字段 |
|
||
| 10 | `rbd_default_stripe_count = 0` 与 `rbd_default_stripe_unit = 0` 的精确语义 | 源文只写 "default stripe count/width",未定义 `0` 的行为 |
|
||
| 11 | `iscsigws.yml` 中 `seed_monitor`、`cluster_name`、`gateway_keyring`、`deploy_settings`、`perform_system_checks`、`trusted_ip_list` 的默认值 | `iscsi-target-ansible.rst` 的表格只写含义,未写默认值(仅 `api_user`/`api_password`/`api_port`/`api_secure` 有默认值) |
|
||
| 12 | iSCSI gateway 场景下各 Ansible 变量在 `iscsigws.yml.sample` 中的完整清单 | 源文只列出 10 个变量,并说"完整清单见 sample 文件" |
|
||
| 13 | NVMe-oF 的认证机制(是否存在 CHAP 等价物) | `nvmeof-*` 全部页面均未提及认证配置;只描述了 host NQN 授权 |
|
||
| 14 | NVMe-oF gateway 的监控工具 | `nvmeof-*` 页面未提及(iSCSI 有 `gwtop`) |
|
||
| 15 | NVMe-oF 对 Windows initiator 的支持 | `nvmeof-initiators.rst` 只列出 Linux 与 VMware ESX 两个子页面 |
|
||
| 16 | Kubernetes 侧快照 / 克隆的 `VolumeSnapshot` 与 PVC `dataSource` 官方示例 | `rbd-kubernetes.rst` 未提供(属于 `ceph-csi` 项目文档范围) |
|
||
| 17 | `ceph-csi` ConfigMap 中 `ceph.conf` 的完整可用配置项清单 | 源文只给了 3 个 `auth_*_required` 示例 |
|
||
| 18 | `iscsi-gateway.cfg` 中 `api_port` 的默认值究竟是 5000 还是 5001 | `iscsi-target-cli.rst` 注释写 `# api_port = 5001`,而 `iscsi-target-ansible.rst` 表格写 default 为 `5000`;源文存在不一致,本册不做裁决 |
|
||
| 19 | `nvmeof-cli` 命令中 `--server-port` 的准确取值(源文同时出现 `GATEWAY_PORT` 与 `5500`) | 源文写法含混,见 14.3 的补充说明 |
|
||
| 20 | RBD image 命名 `userid/<uuid>` 这类约定的具体用途与冲突场景 | `rados-rbd-cmds.rst` 只提示"可能造成混淆",未展开 |
|
||
| 21 | `rbd_default_snapshot_quiesce_mode = required` 时若无 agent 的具体失败行为 | 源文只给了枚举值含义,未描述失败模式 |
|
||
| 22 | PWL cache 在 `ssd` 模式下是否需要 DAX | 源文只说 `rwl` 模式"必须"启用 DAX,未说明 `ssd` 模式 |
|
||
| 23 | `immutable_object_cache_max_inflight_ops` 与 `immutable_object_cache_client_dedicated_thread_num` 在 `rbd-persistent-read-only-cache.rst` 中未列出 | 本册从 `immutable-object-cache.yaml.in @ v20.2.4` 补齐,已标注来源 |
|
||
| 24 | `osd_client_watch_timeout 15` 是否必须配合 iSCSI gateway | `iscsi-requirements.rst` 在"在每个 OSD 节点上更新运行态"示例中给出该命令,但未说明它与其他两项的关系 |
|