Ceph 设备发现指南:详解ceph-volume lvm list命令的使用、输出格式与实现原理
【免费下载链接】cephCeph is a distributed object, block, and file storage platform项目地址: https://gitcode.com/gh_mirrors/ce/ceph
ceph-volume lvm list是 Ceph 卷管理工具ceph-volume中用于**发现并列出与 Ceph 集群关联的所有设备(逻辑卷与物理磁盘)**的核心子命令。本文以 Ceph 官方文档 doc/ceph-volume/lvm/list.rst 为骨架,结合仓库中 listing.py 与 lvm.py API 的源码实现,完整讲解该命令的两种报告模式、pretty/json两种输出格式、LVM 标签约定与设备名同步机制,帮助你快速定位 OSD 与设备之间的对应关系,并在脚本化运维中正确解析输出。
命令定位:发现哪些设备属于 Ceph
ceph-volume lvm list属于ceph-volume lvm子命令体系(完整的子命令列表见 doc/ceph-volume/lvm/index.rst)。它列出系统中可能与 Ceph 集群关联的所有设备(逻辑卷和物理设备),前提是这些设备携带了足够的元数据(LVM 标签)以供发现。
与已废弃的ceph-disk不同,该命令只展示与 Ceph 关联的设备:凡是未被 Ceph 使用的设备,一律不会出现在输出中。从源码看,这一过滤逻辑位于 listing.py 的create_report方法:遍历api.get_lvs()返回的每一个逻辑卷,调用api.is_ceph_device(lv)判断其是否携带 Ceph 标签,不满足条件的 LV 直接continue跳过。
输出按OSD ID分组(每个 OSD 一个====== osd.N =======段落),这与ceph-disk按设备路径组织的输出风格截然不同,便于直接回答"某个 OSD 由哪些设备组成"。
命令行选项
原文档给出的唯一命令行选项为:
| 选项 | 说明 | 默认值 |
|---|---|---|
--format | 输出格式,可选json或pretty | pretty(人类可读的分组格式) |
此外,该命令还接受一个可选的位置参数DEVICE(路径),用于单设备报告(见下文)。这一参数定义在 listing.py 的main方法 中:nargs='?'表示可省略,帮助文本明确说明其取值可以是vg/lv形式的逻辑卷路径,也可以是/dev/sda1这样的设备路径。
完整报告(Full Reporting):一览集群全部关联设备
不带任何位置参数时,ceph-volume lvm list输出系统中所有与 Ceph 关联的设备与逻辑卷。执行:
ceph-volume lvm list两个 OSD 的pretty输出示例(一个 OSD 使用 LV 作为 journal,另一个使用物理设备作为 journal)如下:
====== osd.1 ======= [journal] /dev/journals/journal1 journal uuid C65n7d-B1gy-cqX3-vZKY-ZoE0-IEYM-HnIJzs osd id 1 cluster fsid ce454d91-d748-4751-a318-ff7f7aa18ffd type journal osd fsid 661b24f8-e062-482b-8110-826ffe7f13fa data uuid SlEgHe-jX1H-QBQk-Sce0-RUls-8KlY-g8HgcZ journal device /dev/journals/journal1 data device /dev/test_group/data-lv2 devices /dev/sda [data] /dev/test_group/data-lv2 journal uuid C65n7d-B1gy-cqX3-vZKY-ZoE0-IEYM-HnIJzs osd id 1 cluster fsid ce454d91-d748-4751-a318-ff7f7aa18ffd type data osd fsid 661b24f8-e062-482b-8110-826ffe7f13fa data uuid SlEgHe-jX1H-QBQk-Sce0-RUls-8KlY-g8HgcZ journal device /dev/journals/journal1 data device /dev/test_group/data-lv2 devices /dev/sdb ====== osd.0 ======= [data] /dev/test_group/data-lv1 journal uuid cd72bd28-002a-48da-bdf6-d5b993e84f3f osd id 0 cluster fsid ce454d91-d748-4751-a318-ff7f7aa18ffd type data osd fsid 943949f0-ce37-47ca-a33c-3413d46ee9ec data uuid TUpfel-Q5ZT-eFph-bdGW-SiNW-l0ag-f5kh00 journal device /dev/sdd1 data device /dev/test_group/data-lv1 devices /dev/sdc [journal] /dev/sdd1 PARTUUID cd72bd28-002a-48da-bdf6-d5b993e84f3f输出字段解读
pretty模式下每个设备条目包含以下字段:
type:设备在 OSD 中扮演的角色,如data(数据)、journal(日志);结合 tag-api 文档 可知,bluestore 后端还可能出现db、wal、block等类型;osd id:该设备所属的 OSD 编号;cluster fsid:Ceph 集群的文件系统 ID(UUID);osd fsid:OSD 自身的 UUID;journal uuid/data uuid:对应逻辑卷或分区的 UUID;journal device/data device:设备路径;devices:组成该逻辑卷的物理设备列表。
关于devices字段,原文档特别指出:由于 LVM 允许一个逻辑卷横跨多块物理磁盘,因此在pretty模式下该值为逗号分隔的字符串,而在json模式下则为数组。这一点在源码 listing.py 的pretty_report中有直接体现:打印时使用','.join(device['devices'])拼接;而在create_report中,该字段通过 lvm.py 的get_pvs遍历物理卷,按pv.lv_uuid == lv.lv_uuid匹配归属,原样以列表存入报告。
注意:
pretty输出中的标签名是经过可读化处理的。例如osd id在 LVM 元数据中实际以ceph.osd_id标签存储(readable_tag函数将ceph.osd_id拆分为osd id)。LVM 标签的完整命名约定见 LVM Tag API 文档,所有标签统一使用ceph.<tag name>=<tag value>的命名空间前缀。
单设备报告(Single Reporting):按需查询指定设备
单设备报告接受设备路径或逻辑卷作为位置参数,三种输入形式如下:
1. 按逻辑卷查询(必须使用卷组名/逻辑卷名)
逻辑卷必须同时给出卷组(vg)名和逻辑卷(lv)名:
ceph-volume lvm list test_group/data-lv2输出:
====== osd.1 ======= [data] /dev/test_group/data-lv2 journal uuid C65n7d-B1gy-cqX3-vZKY-ZoE0-IEYM-HnIJzs osd id 1 cluster fsid ce454d91-d748-4751-a318-ff7f7aa18ffd type data osd fsid 661b24f8-e062-482b-8110-826ffe7f13fa data uuid SlEgHe-jX1H-QBQk-Sce0-RUls-8KlY-g8HgcZ journal device /dev/journals/journal1 data device /dev/test_group/data-lv2 devices /dev/sdc2. 按物理设备路径查询(必须使用完整路径)
裸磁盘(含分区)必须使用完整设备路径:
ceph-volume lvm list /dev/sdd1输出:
====== osd.0 ======= [journal] /dev/sdd1 PARTUUID cd72bd28-002a-48da-bdf6-d5b993e84f3f3. 按 OSD ID 查询
从源码 listing.py 的single_report可以看到,参数会被按以下规则分派:
- 参数全为数字(如
0)→ 视为 OSD ID,调用 get_lvs_from_osd_id 按ceph.osd_id标签查询该 OSD 下全部 LV; - 参数以
/开头→ 视为块设备路径,调用 get_lvs_from_path:先按设备路径查询物理卷上关联的 LV,若没有命中,再退化为按 LV 的path过滤(覆盖/dev/vg/lv、/dev/mapper/形式); - 其余形式 → 按
vg_name/lv_name拆解,调用 get_single_lv 精确匹配,匹配到多个 LV 时该方法会抛出RuntimeError以避免歧义。
值得注意的边界情况:当按路径查询未命中任何 Ceph LV 时,single_report还会尝试把该路径当作非 LVM 的 journal/wal/db 物理设备来匹配——它会反向遍历所有 LV 的ceph.<type>_device标签,若某标签值等于所查路径,则将该 LV 关联的 OSD 与该物理设备一并报告(对应源码 L169-L179 的 fallback 逻辑)。这正是上文/dev/sdd1只显示PARTUUID一个字段的原因:它本身不是 LVM 卷,其身份信息全部保存在关联的 data LV 标签中。
json 输出:面向自动化与脚本解析
使用--format=json时,命令会输出设备在 LVM 元数据中存储的全部信息,包括原始标签,且不做任何可读化改写——标签名保留ceph.osd_id等原始形式。完整报告和单设备查询都支持 json 模式。
以单个逻辑卷为例:
ceph-volume lvm list --format=json test_group/data-lv1{ "0": [ { "devices": ["/dev/sda"], "lv_name": "data-lv1", "lv_path": "/dev/test_group/data-lv1", "lv_tags": "ceph.cluster_fsid=ce454d91-d748-4751-a318-ff7f7aa18ffd,ceph.data_device=/dev/test_group/data-lv1,ceph.data_uuid=TUpfel-Q5ZT-eFph-bdGW-SiNW-l0ag-f5kh00,ceph.journal_device=/dev/sdd1,ceph.journal_uuid=cd72bd28-002a-48da-bdf6-d5b993e84f3f,ceph.osd_fsid=943949f0-ce37-47ca-a33c-3413d46ee9ec,ceph.osd_id=0,ceph.type=data", "lv_uuid": "TUpfel-Q5ZT-eFph-bdGW-SiNW-l0ag-f5kh00", "name": "data-lv1", "path": "/dev/test_group/data-lv1", "tags": { "ceph.cluster_fsid": "ce454d91-d748-4751-a318-ff7f7aa18ffd", "ceph.data_device": "/dev/test_group/data-lv1", "ceph.data_uuid": "TUpfel-Q5ZT-eFph-bdGW-SiNW-l0ag-f5kh00", "ceph.journal_device": "/dev/sdd1", "ceph.journal_uuid": "cd72bd28-002a-48da-bdf6-d5b993e84f3f", "ceph.osd_fsid": "943949f0-ce37-47ca-a33c-3413d46ee9ec", "ceph.osd_id": "0", "ceph.type": "data" }, "type": "data", "vg_name": "test_group" } ] }json 输出的结构说明
- 顶层是一个以 OSD ID 为键的对象(字符串形式的
"0"),值为该 OSD 关联设备的数组; - 每个设备对象包含 LV 的常规属性(
lv_name、lv_path、lv_uuid、vg_name、type)以及devices(物理设备数组)和tags(结构化标签对象); lv_tags是 LVM 原始标签的逗号分隔字符串,与tags对象内容等价,只是保持了 LVM 元数据的原始呈现。
json 输出由 listing.py 的list方法 直接json.dumps(report, indent=4, sort_keys=True)生成。源码注释揭示了一个重要的工程细节:当报告为空(没有任何 Ceph 设备)时,json 模式依然返回退出码 0,而不是报错。这是因为该输出常被 ceph-ansible 等自动化系统消费,调用方只需读取 JSON 内容判断即可,非零退出码反而会带来不必要的噪音;相比之下,pretty模式在无结果时会抛出No valid Ceph lvm devices found并非零退出(raise SystemExit),更适合交互式排查。
另外,json 模式下devices字段是数组(而非逗号拼接),tags中保留了ceph.osd_id=0这类原始标签键,与pretty模式中"osd id"的可读形式形成鲜明对比——两者服务于不同的消费场景。
信息同步机制:设备名变化时如何保持准确
在执行任何列表操作之前,ceph-volume lvm list会先查询 LVM API,确保可能被使用的物理设备没有发生命名漂移。为什么需要这一步?因为像/dev/sda1这类非持久化设备名,在重启或硬件枚举顺序变化后可能变成/dev/sdb1,如果直接使用旧名,报告就会指向错误的设备。
检测原理:PARTUUID
检测得以实现的关键在于:PARTUUID被作为元数据的一部分保存在 data 逻辑卷的 LVM 标签中。即使 journal 是物理设备(非 LVM 卷),其PARTUUID信息也会存储在与之关联的 data LV 上(这正是上文/dev/sdd1条目中PARTUUID字段的来源)。
具体的同步流程为:
- 报告生成前,工具通过
blkid按PARTUUID反查设备的当前真实名称; - 如果发现当前名称与标签中记录的名称不一致(例如
/dev/sda1已变为/dev/sdb1); - 则更新对应 LVM 标签,使后续报告使用刷新后的新名称。
从源码结构看,这一"按需刷新"的行为与 lvm.py API 中围绕 LV 标签读写、blkid/PARTUUID查询的工具函数相互配合,保证list报告始终反映设备的最新命名,避免运维人员被过时的设备路径误导。
源码视角:list子命令的完整调用链
ceph-volume lvm list的入口在 src/ceph-volume/ceph_volume/devices/lvm/main.py 的mapper字典中:'list'映射到listing.List类。整个执行流程可概括为:
main.py的LVM.main()通过terminal.dispatch(self.mapper, self.argv)将list参数分发给listing.List;List.main()解析参数(device位置参数与--format选项);List.list()判断是否传入设备参数,分别调用single_report()或full_report();create_report()遍历 LV,先做 Ceph 关联过滤(is_ceph_device),再按 OSD ID 分组、补充物理设备(devices字段)、追加非 LVM 的 journal/wal/db 物理设备条目;- 最后根据
--format走json.dumps(json 模式)或pretty_report()(pretty 模式,内含标签名可读化与osd.%s标题渲染)。
其中full_report实际执行的是create_report(api.get_lvs()),即全量扫描系统 LV;而direct_report()是一个不带 CLI 参数解析的便捷入口,供其他非 CLI 消费者直接获取完整报告,无需构造参数对象。
依赖前提
list能正确工作有一个前提:相关 LV 必须已经通过ceph-volume lvm prepare/create(或batch)预先打上所需标签。只有携带了ceph.cluster_fsid、ceph.osd_id、ceph.type等标签的 LV 才会被is_ceph_device识别为 Ceph 设备,这与 doc/dev/ceph-volume/lvm.rst 中"标签是设备发现的唯一依据"的设计一脉相承。常用的ceph.*标签包括:type(data/journal/osd 等)、cluster_fsid、osd_fsid、osd_id、data_device/data_uuid、journal_device/journal_uuid,以及 bluestore 后端的block_device/block_uuid、db_device/db_uuid、wal_device/wal_uuid和encrypted(LUKS 加密标记)、vdo等。
实用建议与常见场景
- 快速核对 OSD 与磁盘的对应关系:执行
ceph-volume lvm list,按====== osd.N =======分段阅读,即可确认每个 OSD 的数据盘、日志盘分别落在哪些物理设备上; - 脚本化采集设备元数据:使用
ceph-volume lvm list --format=json,配合jq按 OSD ID 聚合tags与devices数组;注意空结果时退出码仍为 0,需自行判断 JSON 是否为空; - 排查设备名漂移:当怀疑
/dev/sdX名称变化导致 OSD 激活失败时,优先运行list触发 PARTUUID 同步并观察devices字段是否已更新为新路径; - 定位单一设备归属:不确定某个裸盘属于哪个 OSD 时,用
ceph-volume lvm list /dev/sdX1直接查询,输出中的osd id与type字段会给出答案; - 与相关命令配合:
list只读不改动设备状态,是排查问题的安全第一步;确认归属后再结合 zap.rst(销毁设备)、migrate.rst(迁移 journal/db/wal)等命令执行变更操作。
小结
ceph-volume lvm list以 LVM 标签为核心,把"发现设备 → 按 OSD 分组 → 输出报告"三个环节串成一条清晰的链路:pretty模式适合人工排障,json模式适合自动化消费,单设备查询支持vg/lv、/dev/xxx与 OSD ID 三种输入形式,而基于PARTUUID的命名同步机制保证了结果始终与设备真实状态一致。理解其输出字段与标签约定,是高效管理 Ceph OSD 设备、排查启动与挂载问题的关键基本功。
【免费下载链接】cephCeph is a distributed object, block, and file storage platform项目地址: https://gitcode.com/gh_mirrors/ce/ceph
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考