news 2026/9/21 16:29:16

Ceph 设备发现指南:详解 `ceph-volume lvm list` 命令的使用、输出格式与实现原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Ceph 设备发现指南:详解 `ceph-volume lvm list` 命令的使用、输出格式与实现原理

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输出格式,可选jsonprettypretty(人类可读的分组格式)

此外,该命令还接受一个可选的位置参数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 后端还可能出现dbwalblock等类型;
  • 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/sdc

2. 按物理设备路径查询(必须使用完整路径)

裸磁盘(含分区)必须使用完整设备路径:

ceph-volume lvm list /dev/sdd1

输出:

====== osd.0 ======= [journal] /dev/sdd1 PARTUUID cd72bd28-002a-48da-bdf6-d5b993e84f3f

3. 按 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_namelv_pathlv_uuidvg_nametype)以及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字段的来源)。

具体的同步流程为:

  1. 报告生成前,工具通过blkidPARTUUID反查设备的当前真实名称;
  2. 如果发现当前名称与标签中记录的名称不一致(例如/dev/sda1已变为/dev/sdb1);
  3. 更新对应 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类。整个执行流程可概括为:

  1. main.pyLVM.main()通过terminal.dispatch(self.mapper, self.argv)list参数分发给listing.List
  2. List.main()解析参数(device位置参数与--format选项);
  3. List.list()判断是否传入设备参数,分别调用single_report()full_report()
  4. create_report()遍历 LV,先做 Ceph 关联过滤(is_ceph_device),再按 OSD ID 分组、补充物理设备(devices字段)、追加非 LVM 的 journal/wal/db 物理设备条目;
  5. 最后根据--formatjson.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_fsidceph.osd_idceph.type等标签的 LV 才会被is_ceph_device识别为 Ceph 设备,这与 doc/dev/ceph-volume/lvm.rst 中"标签是设备发现的唯一依据"的设计一脉相承。常用的ceph.*标签包括:type(data/journal/osd 等)、cluster_fsidosd_fsidosd_iddata_device/data_uuidjournal_device/journal_uuid,以及 bluestore 后端的block_device/block_uuiddb_device/db_uuidwal_device/wal_uuidencrypted(LUKS 加密标记)、vdo等。

实用建议与常见场景

  • 快速核对 OSD 与磁盘的对应关系:执行ceph-volume lvm list,按====== osd.N =======分段阅读,即可确认每个 OSD 的数据盘、日志盘分别落在哪些物理设备上;
  • 脚本化采集设备元数据:使用ceph-volume lvm list --format=json,配合jq按 OSD ID 聚合tagsdevices数组;注意空结果时退出码仍为 0,需自行判断 JSON 是否为空;
  • 排查设备名漂移:当怀疑/dev/sdX名称变化导致 OSD 激活失败时,优先运行list触发 PARTUUID 同步并观察devices字段是否已更新为新路径;
  • 定位单一设备归属:不确定某个裸盘属于哪个 OSD 时,用ceph-volume lvm list /dev/sdX1直接查询,输出中的osd idtype字段会给出答案;
  • 与相关命令配合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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/21 16:28:25

Vercel 部署错误指南:Invalid Region or DC Identifier 的成因与修复

CLI后端云原生 【免费下载链接】vercel Develop. Preview. Ship. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/ve/vercel 点击查看 免费下载 本文围绕 Vercel 开源仓库&#xff08;GitHub 加速计划 / ve / vercel&#xff09;中的错误说明文档 errors/deploy-invali…

作者头像 李华
网站建设 2026/9/21 16:27:34

TiXL 中 Cos 运算符实战:用余弦波驱动实时运动图形

音视频图形学桌面应用 【免费下载链接】t3 TiXL is an open source software to create realtime motion graphics. 项目地址&#xff1a; https://gitcode.com/GitHub_Trending/t3/t3 点击查看 免费下载 导读 Cos 是 TiXL 运算符库 Lib.numbers.float.trigonometry 中生成余…

作者头像 李华
网站建设 2026/9/21 16:26:24

前端工程师如何用CSVLoader和JSONLoader快速切入AI Agent开发

1. 项目概述&#xff1a;为什么前端工程师突然开始写 Agent&#xff1f;“前端转 Agent 开发 第六节”这个标题乍看像是一门系列课的普通一讲&#xff0c;但放在2025年中后期的工程实践语境里&#xff0c;它其实是一条清晰的职业演进路径的具象切片——不是概念炒作&#xff0…

作者头像 李华
网站建设 2026/9/21 16:26:17

React双缓存Fiber树机制解析与应用

1. React 双缓存 Fiber 树机制解析在 React 16 之后引入的 Fiber 架构中&#xff0c;双缓存 Fiber 树机制是实现高效渲染和并发更新的核心设计。这个机制让 React 能够在不阻塞主线程的情况下完成复杂的 UI 更新&#xff0c;同时保持界面的流畅性和响应性。1.1 Fiber 架构概述F…

作者头像 李华