Ceph集群开篇

15272 字
76 分钟
Ceph集群开篇
Ceph集群开篇

Ceph 集群开篇#

[TOC]


一、Ceph 概述#

Ceph 是什么#

==Ceph== 是一个开源的分布式存储系统,它把每一块待管理的数据切分为固定大小的对象(==object==),并以对象为原子单元完成数据存取

底层存储服务由多个主机(host)组成的存储集群提供,该集群被称为 ==RADOS==(Reliable Automatic Distributed Object Store)——==可靠==、==自动化==、==分布式==、==对象存储==系统


RADOS 通俗理解:把四个字母拆开就是它的全部秘密:

字母含义通俗解释
Reliable可靠每份数据自动存 3 份,坏一台机器不丢数据
Automatic自动化你不用管数据放哪块盘,系统自己决定
Distributed分布式多台机器绑在一起干活,不是单机
Object Store对象存储数据被切成固定大小的”对象”来存取,像一个个标准快递箱
  • RADOS Cluster = 分布式集群 = 服务端

  • RADOS Cluster 本身就是由多台物理主机组成的

  • 不是一台机器叫 RADOS,是这几台绑在一起才叫 RADOS Cluster

🧪 单节点实验

Ceph-201(仅一台)

MON ✅

MGR ✅

OSD.0/1/2

🏭 生产环境(≥3台主机)

Ceph-203

MON ✅

MGR

OSD.6/7/8

Ceph-202

MON ✅

MGR

OSD.3/4/5

Ceph-201

MON ✅

MGR ✅

OSD.0/1/2

✅ 一台挂 > 另两台顶上

❌ 一台挂 = 全集群挂

(不适合生产环境)

🧪 单节点实验

Ceph-201(仅一台)

MON ✅

MGR ✅

OSD.0/1/2

🏭 生产环境(≥3台主机)

Ceph-203

MON ✅

MGR

OSD.6/7/8

Ceph-202

MON ✅

MGR

OSD.3/4/5

Ceph-201

MON ✅

MGR ✅

OSD.0/1/2

✅ 一台挂 > 另两台顶上

❌ 一台挂 = 全集群挂

(不适合生产环境)

Tip

📌 一句话:RADOS 是 Ceph 的唯一地基——无论上层是 RBD、CephFS 还是 RadosGW

数据最终都变成”对象”沉到 RADOS 里,再由它分发到各台机器的磁盘上


Ceph 架构全景:工具 > 接口 > 集群#

Ceph 整个体系就三层——从你敲的命令,到程序调用的接口,到底层真正存数据的集群:

📡 接口层:三种存储入口

🔧 工具层:你在终端敲的命令

直接管理

💾 RADOS Cluster 分布式集群

提供集群地图

监控性能指标

管理 OSD 注册

🧠 Monitor · 大脑:管地图

MON

Ceph-201

MON

Ceph-202

MON

Ceph-203

📊 Manager · 副手:管监控

MGR(active)

Ceph-201

MGR(standby)

Ceph-202

MGR(standby)

Ceph-203

🗄️ Storage · 仓库:存数据

🖥 Ceph-203

OSD.6

/sdb

OSD.7

/sdc

OSD.8

/sdd

🖥 Ceph-202

OSD.3

/sdb

OSD.4

/sdc

OSD.5

/sdd

🖥 Ceph-201

OSD.0

/sdb

OSD.1

/sdc

OSD.2

/sdd

rbd

(块设备命令)

ceph fs

(文件系统命令)

radosgw-admin

(对象网关命令)

ceph

(集群管理命令)

RBD

(块设备接口)

CephFS

(文件系统接口)

RadosGW

(对象网关接口)

📡 接口层:三种存储入口

🔧 工具层:你在终端敲的命令

直接管理

💾 RADOS Cluster 分布式集群

提供集群地图

监控性能指标

管理 OSD 注册

🧠 Monitor · 大脑:管地图

MON

Ceph-201

MON

Ceph-202

MON

Ceph-203

📊 Manager · 副手:管监控

MGR(active)

Ceph-201

MGR(standby)

Ceph-202

MGR(standby)

Ceph-203

🗄️ Storage · 仓库:存数据

🖥 Ceph-203

OSD.6

/sdb

OSD.7

/sdc

OSD.8

/sdd

🖥 Ceph-202

OSD.3

/sdb

OSD.4

/sdc

OSD.5

/sdd

🖥 Ceph-201

OSD.0

/sdb

OSD.1

/sdc

OSD.2

/sdd

rbd

(块设备命令)

ceph fs

(文件系统命令)

radosgw-admin

(对象网关命令)

ceph

(集群管理命令)

RBD

(块设备接口)

CephFS

(文件系统接口)

RadosGW

(对象网关接口)

📌 三层角色:

层是什么谁在用举例
工具层命令行可执行文件运维/开发人员手工敲rbd create、ceph fs ls、radosgw-admin user create
接口层三种存储入口应用程序通过代码调用RBD(块)、CephFS(文件)、RadosGW(对象)
集群层服务端进程的集合接口层把数据交给它MON + MGR + OSD + MDS(可选)

💡 类比:

  • 工具层 = ATM 机的触摸屏——你用手指点它
  • 接口层 = ATM 机内部的银行系统——屏上的操作转成后台调用
  • 集群层 = 银行金库——钱真正存放的地方

📌 librados 为什么不在接口层:它不是独立的存储类型(你不能说”我用 librados 存储”)

  • 而是 RBD 和 RadosGW 底层共用的 C 语言原生库

三种存储类型#

存储类型接口(接口层)工具(工具层)依赖关系通俗理解典型用途
块存储==RBD==rbd依赖 librados虚拟硬盘,能格式化、分区、挂载虚拟机磁盘、数据库
文件存储==CephFS==ceph fs不依赖 librados共享文件夹,多台机器同时挂载文件共享、日志存储
对象存储==RadosGW==radosgw-admin依赖 libradosHTTP/HTTPS API,适合非结构化数据图片/视频云存储

💡 关键区别:

  • RadosGW:基于 RESTful 风格提供跨互联网的==云存储服务==
    • 里面的对象和 Ceph 内部的对象(固定大小存储块,基于 RPC 协议)不是一回事
  • RBD:将 Ceph 集群的存储空间模拟成独立块设备,依赖 Linux 内核的 librbd 模块
  • CephFS:和 librados 是同级组件,但使用热度比 RadosGW 和 RBD 低

📌 librados 的特殊地位:

RBD 和 RadosGW 底层都调用 librados,但 CephFS 不走这条路:

Terminal window
RBD ──────> librados ──> RADOS Cluster
RadosGW ──> librados ──> RADOS Cluster
CephFS ────────────────> RADOS Cluster (直接和 MDS / OSD 通信)
  • RADOS Cluster = 分布式集群 = 服务端

  • librados 是 Ceph 的”母语”——其他接口要么基于它,要么绕过它直接说方言

Ceph-架构
Ceph-架构

📌 核心要点:

  • 无论你用哪种工具、哪种接口,最终数据都会被写入 RADOS Cluster(分布式集群)
  • 每种客户端类型都有自己的存储池(Pool)资源
    • 这句话的核心意思是:不同存储类型的”数据地盘”是分开的
Terminal window
"类比理解"
一个 RADOS Cluster 就像一栋商场大楼:
RADOS Cluster(商场)
├── Pool A(RBD 专区) > 只放虚拟硬盘的"扇区数据"
├── Pool B(CephFS 专区) > 只放共享文件夹的"文件+目录信息"
├── Pool C(RadosGW 专区)> 只放云存储的"图片/视频对象"
└── Pool D(.mgr 系统池) > 只放集群自己的"内部账本"
# 初始化集群后只有一个 .mgr 系统池
✅️ 每个 Pool 有自己独立的配置——副本数、PG 数量、CRUSH 规则——互不干扰
===========================
为什么不能混用❓️
1.RBD 存的是扇区块(像硬盘的 0/1 二进制块)
2.CephFS 存的是文件 + 目录树(像文件夹结构)
3.RadosGW 存的是S3 对象 + 元数据(像云存储的 Key-Value)
✅️ 数据格式完全不同,所以每种类型必须有自己的 Pool
💡 就像商场里服装店和餐厅不能共用同一个铺位
Tip

📌 一句话总结

  • 每种客户端类型都有自己的存储池
    • 你用 RBD 就建 RBD 的池,用 CephFS 就建 CephFS 的池,各有各的地盘,互不串门

CRUSH 算法详解#

CRUSH = Controlled Replication Under Scalable Hashing

  • 可控的、可扩展的、基于哈希的副本分布算法
  • ==CRUSH 算法== 是 Ceph 内部数据对象存储路由的算法,它没有中心节点(无元数据服务器)

🧱 通俗理解:

传统存储(比如 HDFS)的做法:

  • 搞一个 NameNode(元数据服务器),里面记着”文件A > 块1在机器3、块2在机器5”

  • 客户端每次读写都要先问它

Ceph 的做法:不搞中心索引 —> ==客户端自己算位置==(去中心化)

Terminal window
传统 HDFS: Ceph CRUSH:
客户端 客户端
│ "文件A存哪?" │ "我自己算!"
▼ │
NameNode ──> "机器3和机器5" │ 对象名 + CRUSH Map
│ │ ↓ 哈希计算
▼ │ OSD.3 + OSD.7 + OSD.12
机器3、机器5 ▼
直接找 OSD.3 写数据

💡 核心思想:CRUSH 就是一个伪随机哈希函数——给定”对象名字”和”集群地图”,算出”应该存到哪几块盘”

对比维度传统元数据服务器(HDFS NameNode)Ceph CRUSH
数据寻址查表——问中心节点计算——客户端自己算
中心节点有(单点瓶颈、单点故障)无(去中心化)
扩展性受限于 NameNode 内存理论上无限
节点增减需要大规模重新平衡只迁移受影响的 PG,其余不动
故障影响NameNode 一挂 > 所有 I/O 立刻停Monitor 不在数据路径上(门口保安)
短期:已连接客户端仍可读写
长期:无法认证新连接,集群最终不可用

🧱 为什么 Monitor 挂了”短期能读、长期不行”:

Terminal window
HDFS NameNode 是"必经之路": Ceph Monitor 是"门口保安":
客户端 客户端(缓存了地图)
│ 每次读写都得问 │ "我知道 OSD.3 在哪"
▼ ▼
NameNode ──> 一挂全停 ❌️ OSD.3 <── 直接通信,不经过 Monitor
✅️ Monitor 不在数据路径上
场景还能不能?原因
部分 Monitor 挂(还有 quorum)✅ 完全正常活着的 Monitor 继续服务,3个挂1个 —> 无所谓
全部 Monitor 挂 > 已连接客户端读写✅ 短期能客户端缓存了 OSD Map 和 CRUSH Map,知道数据在哪个 OSD,直接和 OSD 通信
全部 Monitor 挂 > 新建连接/打开新文件❌ 不能新客户端需要向 Monitor 认证身份、获取集群地图
全部 Monitor 挂 > 长时间运行❌ 不能OSD Map 有过期时间,OSD 之间心跳也会断,集群最终停摆

📌 CRUSH 三个关键优势:

  • 去中心化:客户端拿着 CRUSH Map(集群拓扑图),自己就能算出数据该存哪个 OSD,不需要每次问 Monitor

    • 这就是”没有元数据服务器”的含义
  • 故障域可控:你可以指定”同一份数据的 3 个副本必须分布在 3 台不同主机上”

    • 这就是 type=host 的作用
  • 弹性伸缩:加减 OSD 时,CRUSH 只重新分配受影响的 PG(安置组),不是全量数据搬迁

📌 CRUSH Map 是什么❓️

CRUSH Map 就是”集群的地图”——它描述了:

  • 有多少台主机
  • 每台主机上有多少块 OSD
  • OSD 的权重*(容量越大的盘权重越高)*
  • 故障域层级(root > host > osd)

客户端下载了这份地图,就不需要问别人了——所有位置计算都在本地完成

核心组件#

🚢 ① ==OSD==(Object Storage Device,对象存储守护进程,ceph-osd)

通俗解释:真正负责存数据的”仓库管理员”,一块磁盘对应一个 OSD 守护进程,类似于 HDFS 的 DataNode

  • 存储数据、处理数据复制、恢复、重新平衡
  • 通过检查其他 OSD 的心跳向 Monitor 和 Manager 提供监视信息
  • 负责守护程序和管理客户端之间的身份验证(基于 ==Cephx 协议==)
  • ❗️ 为了实现冗余和高可用,通常至少需要 3 个 OSD(默认数据副本是 3 个)

🧱 OSD 心跳互检——“不是 Monitor 挨个 ping,而是 OSD 互相盯着”:

🗄️ OSD 集群

心跳检测

心跳检测

心跳检测

📢 上报:OSD.3 挂了!

🧠 Monitor(大脑)

OSD.0

OSD.1

OSD.2

OSD.3 ❌ 已挂

🗄️ OSD 集群

心跳检测

心跳检测

心跳检测

📢 上报:OSD.3 挂了!

🧠 Monitor(大脑)

OSD.0

OSD.1

OSD.2

OSD.3 ❌ 已挂

  • 每个 OSD 定期给其他 OSD 发心跳包

  • 如果 OSD.1 发现 OSD.3 半天没回应,就主动上报 Monitor

  • Monitor 不需要自己扫描所有 OSD

**类比:**老师(Monitor)不需要挨个点名——同学们(OSD)互相看着,谁没来立刻有人举手报告


🧱 OSD 负责 Cephx 身份验证——“Monitor 发证,OSD 验票”:

OSD.3Monitor客户端OSD.3Monitor客户端① 我是 client.admin,这是我的 key返回通行证(ticket)(Monitor 用密钥签名)② 我要写数据,这是我的通行证自己验票:签名是 Monitor 的❓️没过期❓️权限够❓️✅ 放行 / ❌ 拒绝
OSD.3Monitor客户端OSD.3Monitor客户端① 我是 client.admin,这是我的 key返回通行证(ticket)(Monitor 用密钥签名)② 我要写数据,这是我的通行证自己验票:签名是 Monitor 的❓️没过期❓️权限够❓️✅ 放行 / ❌ 拒绝

关键:Monitor 只负责签发通行证,不参与每一次数据读写——否则 Monitor 又变成瓶颈了

  • OSD 是验票的——每一次客户端读写,OSD 都要查通行证是否有效,防止未授权的客户端偷数据
  • 通行证是 Monitor 用密钥签名的,OSD 认得这个签名——不需要每次回头问 Monitor

📦 ② ==Monitor==(监视器,ceph-mon)

通俗解释:集群的”大脑”和”元数据中心”,维护整个集群的运行状态

  • 维护 5 张映射表:Monitor Map、Manager Map、OSD Map、CRUSH Map、PG Map
  • 负责集群成员管理和客户端认证
  • ❗️ 至少需要 3 个 Monitor(高可用 + 负载均衡)

⚙️ ③ ==Manager==(管理器,ceph-mgr)

通俗解释:集群状态的收集和展示(监控指标、性能数据)

  • Ceph 早期版本没有 mgr 组件,mon 每次查询都实时读取,代价高昂
  • L 版本引入 mgr,还托管基于 Python 的插件和 Rest API
  • ❗️ 高可用部署中 Manager 至少需要 2 个(1 个 active + 1 个 standby)

🧱 Manager 缓存了什么——和 Dashboard 的关系:

Terminal window
浏览器打开 Dashboard(https://Ceph-201:8443)
│
▼
Manager <── 提前从集群各处收集并缓存:
│
├── 集群健康状态(HEALTH_OK / WARN / ERR)
├── OSD 列表、状态、容量、延迟
├── MON 列表、quorum 情况
├── PG 状态(active+clean / degraded / ...)
├── 性能图表数据(IOPS、吞吐量、延迟曲线)
├── Dashboard 配置(你改过的密码、告警阈值...)
└── 设备健康信息(SMART 数据、磁盘温度...)
简单概括: '存设备健康+数据、性能指标、Dashboard 配置等"内部账本"'
这些数据存在哪❓️
> Manager 把上述数据持久化到 .mgr 存储池(系统池,bootstrap 时自动创建)
> 这样 Manager 重启后配置不丢,Dashboard 刷新时秒出数据
❌️ Manager 不存用户数据(你的 RBD 块、CephFS 文件、RadosGW 对象)
✅️ 它只管"集群自己的内部账本和监控数据"

📌 通俗类比:

  • Monitor 是”公司档案室”(存地图和花名册)

  • Manager 是”运营大屏”(Dashboard)的后台

    • 它提前把各项指标算好缓存起来,你打开网页时不用现场去每个部门问一遍

🗂️ ④ ==MDS==(MetaData Server,元数据服务器,ceph-mds,可选组件)

通俗解释:对应 CephFS 文件系统的”目录索引”,类似于 HDFS 的 NameNode——找文件时不用扫描所有 OSD

  • 存储 CephFS 的元数据(文件名、目录结构、权限)
  • 仅在使用 CephFS 时需要,RBD 和 RadosGW 不 需要
  • 从严格意义上来讲,MDS 只能算作构建于 RADOS 之上的文件存取接口,而非基础组件
  • ❗️ 如果使用 CephFS,建议部署多个 MDS 以防单点故障

🔹 ⑤ ==RGW==(对象存储网关,可选组件)

用于对象存储系统,需要启用相关组件模块


📋 ⑥ ==Pool & PG==(存储池 & 安置组,抽象概念)

通俗解释:

  • Pool:数据的逻辑分区
    • 一个 Ceph 集群可以有多个 Pool,每个 Pool 还可以划分多个 namespace
  • PG(Placement Group):Pool 内部的逻辑分组
    • 数据通过 CRUSH 算法映射到具体 OSD 时,以 ==PG== 为单位
Tip

Pool 就是 PG 的容器,PG 是数据分布的”最小单位”

数据存储流程#

用一个具体例子走一遍:把一张 100MB 的照片存进 Ceph

Step 3:PG → OSD · size=3 副本 · 故障域=host · 三台不同主机

PG.7

CRUSH 再次计算

副本① Ceph-201 osd.1

副本② Ceph-202 osd.4

副本③ Ceph-203 osd.7

Step 2:对象 → PG · CRUSH 伪随机哈希

对象名

rbd_data.1032.0001

CRUSH 计算

CRUSH Map

集群拓扑

命中 Pool 下的 👉 PG.7



💡一个 PG 可存放多个对象

PG 是数据分布的最小单位

Step 1:切块 · 按 4MB 固定大小,💡 不足也补齐

📄 100MB 照片

25 个 4MB 对象

obj1 · obj2 · obj3 · ... · obj25

Step 3:PG → OSD · size=3 副本 · 故障域=host · 三台不同主机

PG.7

CRUSH 再次计算

副本① Ceph-201 osd.1

副本② Ceph-202 osd.4

副本③ Ceph-203 osd.7

Step 2:对象 → PG · CRUSH 伪随机哈希

对象名

rbd_data.1032.0001

CRUSH 计算

CRUSH Map

集群拓扑

命中 Pool 下的 👉 PG.7



💡一个 PG 可存放多个对象

PG 是数据分布的最小单位

Step 1:切块 · 按 4MB 固定大小,💡 不足也补齐

📄 100MB 照片

25 个 4MB 对象

obj1 · obj2 · obj3 · ... · obj25

📝 关键补充说明

Step 1 切块

  • Ceph 对象固定大小 4MB(可配置)
  • 100MB 文件 → 切成 25 个 4MB 对象
  • 10MB 文件 → 切成 3 个 4MB 对象(最后一个 2MB 数据 + 2MB 空白补齐)

Step 2 对象 → PG

  • 每个对象有唯一名称(如 rbd_data.1032.0001)
  • CRUSH 算法根据 对象名 + CRUSH Map(集群拓扑) 计算 PG 归属
  • 25 个对象均匀分布到各 PG,一个 PG 可存放多个对象
  • PG 是数据分布的最小单位,Pool 是 PG 的容器

Step 3 PG → OSD(副本落地)

  • 根据 Pool 的副本数 size=3,CRUSH 再算 3 个 OSD 位置
  • 故障域 host 保证副本落在不同主机,实现高可用
  • obj1 最终变成 3 份副本,存于三台不同机器的磁盘上

📌 三个关键角色:

角色是什么为什么需要它
Object4MB 固定大小的数据块统一大小,方便管理和分布
PGPool 内的逻辑分组海量对象 > 少量 PG > 几块 OSD
PG 做聚合收敛:百万对象只需几百个 PG
加减 OSD 时只搬 PG,不搬海量对象
CRUSH==决定”去哪”的算法==在数据落地过程中用了两次:① 对象名>PG;② PG>OSD

🧱 CRUSH 发挥了两次作用:

CRUSH ①

去哪个 PG?

CRUSH ②

副本放哪 3 块盘?

对象名

PG.7

osd.1

osd.4

osd.7

CRUSH ①

去哪个 PG?

CRUSH ②

副本放哪 3 块盘?

对象名

PG.7

osd.1

osd.4

osd.7

Tip
  • 第一次负责逻辑分组(对象归哪个 PG)
    • CRUSH①:object_name + pool_id + PG_num → PG.x(逻辑分组)
  • 第二次负责数据落盘(PG 的副本落哪几块盘)#

    CRUSH②:PG.x + CRUSH_map + size=3 → osd.1, osd.4, osd.7(副本落盘)

两段分工不同,但用的都是同一套 CRUSH 算法

CRUSH 哈希收敛

CRUSH 再计算

🔍 PG.7 内部(一个 PG = 大量对象的容器)

obj1 4MB

obj2 4MB

...

📦 对象(几百万~上亿个)

海量

🧩 PG 安置组(32~1024)

少量

💾 OSD(几十块盘)

CRUSH 哈希收敛

CRUSH 再计算

🔍 PG.7 内部(一个 PG = 大量对象的容器)

obj1 4MB

obj2 4MB

...

📦 对象(几百万~上亿个)

海量

🧩 PG 安置组(32~1024)

少量

💾 OSD(几十块盘)

Tip
  • PG 做的是聚合收敛——不是一对一映射

  • 如果每个对象对应一个 PG,那 PG 就没有存在的必要了

    • ✅ PG 的数量远小于对象的数量——这才是 PG 存在的意义

  • 每个 PG 里装了大量对象,CRUSH 把对象均匀哈希到各 PG

    • ✅️ 一个 PG 里可以存放多个对象
  • 迁移时以 PG 为单位搬 → 一次搬”一筐对象”,而不是一个一个搬

  • 📌 文件 → 切成对象 → CRUSH 算 PG → PG 分发到 OSD → 存 3 份到不同主机

BlueStore 存储引擎#

BlueStore 是 OSD 内部的存储引擎——决定数据最终以什么方式写到磁盘上

🧱 通俗理解:

OSD 收到一个对象后,怎么把它存到磁盘❓️ —> 这就靠存储引擎

Ceph 经历过一次大换血:

🟢 BlueStore(新 · 一次到位)

查询偏移量(这个对象存在磁盘的哪个物理位置)

对象

📦 数据

🏷️ 元数据

💾 裸块设备

直接写入

🗄️ RocksDB

Key-Value 数据库

🔴 FileStore(旧 · 写两次)

第 1 次写

第 2 次写

对象

📋 Journal 日志盘

📁 XFS 文件系统

💾 裸块设备

🟢 BlueStore(新 · 一次到位)

查询偏移量(这个对象存在磁盘的哪个物理位置)

对象

📦 数据

🏷️ 元数据

💾 裸块设备

直接写入

🗄️ RocksDB

Key-Value 数据库

🔴 FileStore(旧 · 写两次)

第 1 次写

第 2 次写

对象

📋 Journal 日志盘

📁 XFS 文件系统

💾 裸块设备

Tip
  • 🟢 BlueStore:数据直接写裸盘,元数据走 RocksDB,不依赖任何文件系统

  • 🔴 FileStore:每笔数据写两遍(Journal → XFS → 裸盘),依赖 XFS,写放大严重

  • FileStore 是”先写草稿再誊写”,BlueStore 是”一笔写成”

    • 💡 少了一道工序,性能自然更好
对比BlueStore(新)FileStore(旧)
写数据直接写裸块设备(写一次)先写 Journal > 再搬 XFS > 再落盘(写两次)
元数据内建 RocksDB(Key-Value 数据库),自己管靠 XFS 文件系统管理
依赖不依赖任何文件系统,直接在裸盘上存储依赖 XFS 文件系统层
快满时几乎不降性能陡降
小随机写快(RocksDB 优化)慢
额外机制支持 COW(写时复制),RBD 快照/克隆更高效无
Tip

📌 RocksDB 是什么:一个轻量级的嵌入式键值(Key-Value)数据库(Facebook 开源)

  • BlueStore 用它来存元数据——“对象 A 存在磁盘偏移量 0x1234 处,长度 4MB”
    • 读写数据前先查 RocksDB,找到位置后直接操作裸盘

二、Ceph 高可用集群部署#

部署工具概览#

部署工具特点推荐度
==cephadm==类似 kubeadm,部署服务非常方便,容器化部署⭐⭐⭐⭐⭐
ceph-deploy原生工具,仅依赖 SSH + sudo + Python⭐⭐(已丢弃)
ceph-ansible基于 Ansible playbook⭐⭐⭐⭐

💡 推荐使用 cephadm:与 k8s 的 kubeadm 一样好用,基于容器化部署,官方主推

Ceph 版本说明#

Terminal window
x.0.z > 0 --> 开发版本(内部测试)
x.1.z > 1 --> 测试版本(开发人员测试)
x.2.z > 2 --> 稳定版本(✅️ 生产环境推荐)
'x --> 大版本'
'z --> 小版本'
示例: 20.2.1 (Tentacle) 为稳定版本

三、cephadm 快速部署实战#

环境准备#

官方前提条件

Terminal window
- Python 3
- Systemd
- Podman or Docker for running containers
- Time synchronization (such as Chrony or NTP)
- LVM2 for provisioning storage devices

集群节点规划(3 节点)

主机IPCPU内存磁盘设备
Ceph-20110.0.0.2012C4G/dev/sdb (300G), /dev/sdc (500G), /dev/sdd (1024G==1T)
Ceph-20210.0.0.2022C4G/dev/sdb (300G), /dev/sdc (500G), /dev/sdd (1024G==1T)
Ceph-20310.0.0.2032C4G/dev/sdb (300G), /dev/sdc (500G), /dev/sdd (1024G==1T)

Terminal window
✅️ 我是开机添加的, "重启生效"
'查看磁盘设备是否就绪'
root@Ceph-201 ~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 40G 0 disk
|-sda1 8:1 0 1M 0 part
|-sda2 8:2 0 2G 0 part /boot
|-sda3 8:3 0 38G 0 part
└─-ubuntu--vg-ubuntu--lv 252:0 0 30G 0 lvm /
sdb 8:16 0 300G 0 disk # < 待加入 Ceph 的数据盘
sdc 8:32 0 500G 0 disk # < 待加入 Ceph 的数据盘
sdd 8:48 0 1T 0 disk # < 待加入 Ceph 的数据盘
sr0 11:0 1 2.6G 0 rom
"sdb/sdc/sdd 三块裸盘无分区无挂载,满足加入 Ceph 的条件"

基础环境配置

Terminal window
1)设置时区(所有节点)
root@Ceph-201 ~# timedatectl status | grep zone
Time zone: Asia/Shanghai (CST, +0800)
root@Ceph-201 ~# timedatectl set-timezone Asia/Shanghai
root@Ceph-201 ~# ll /etc/localtime
lrwxrwxrwx 1 root root 33 May 16 09:38 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
2)安装 Docker 环境(所有节点)
root@Ceph-201 ~# ls
autoinstall-docker.zip
root@Ceph-201 ~# unzip autoinstall-docker.zip
root@Ceph-201 ~# chmod +x install-docker.sh
root@Ceph-201 ~# ./install-docker.sh i
root@Ceph-201 ~# scp -O autoinstall-docker.zip root@10.0.0.202:/root/
autoinstall-docker.zip 100% 96MB 108.2MB/s
# -O 参数会告诉 scp 使用旧版的 SCP 协议进行文件传输,而不是默认的 SFTP 协议
root@Ceph-201 ~# scp -O autoinstall-docker.zip root@10.0.0.203:/root/
# 另外两台也要进行安装
3)添加 hosts 解析(所有节点)
root@Ceph-201 ~# cat >> /etc/hosts <<EOF
10.0.0.201 Ceph-201
10.0.0.202 Ceph-202
10.0.0.203 Ceph-203
EOF
4)集群时间同步
apt -y install chrony
cp /etc/chrony/chrony.conf /etc/chrony/chrony.conf.bak
cat > /etc/chrony/chrony.conf << 'EOF'
server ntp.aliyun.com iburst
sourcedir /run/chrony-dhcp
sourcedir /etc/chrony/sources.d
keyfile /etc/chrony/chrony.keys
driftfile /var/lib/chrony/chrony.drift
ntsdumpdir /var/lib/chrony
logdir /var/log/chrony
maxupdateskew 100.0
rtcsync
makestep 1 3
leapseclist /usr/share/zoneinfo/leap-seconds.list
leapsectz right/UTC
confdir /etc/chrony/conf.d
EOF
systemctl restart chrony
5)关机拍快照【强烈推荐】
root@Ceph-201 ~# init 0
# 快照可以让你在部署失败时快速回滚

初始化 Ceph 集群#

  1. 下载并安装 cephadm
Terminal window
1)下载 cephadm(选择与目标版本一致)
root@Ceph-201 ~# CEPH_RELEASE=20.2.1
root@Ceph-201 ~# curl --silent --remote-name --location https://download.ceph.com/rpm-${CEPH_RELEASE}/el9/noarch/cephadm
'建议用浏览器去提前下载安装'
root@Ceph-201 ~# ls
cephadm
2)添加到 PATH
root@Ceph-201 ~# chmod +x cephadm
'下载下来的是二进制执行文件644'(不保留x权限)
root@Ceph-201 ~# mv cephadm /usr/local/bin/
root@Ceph-201 ~# ls /usr/local/bin/cephadm
/usr/local/bin/cephadm
root@Ceph-201 ~# cephadm version
# 验证版本
cephadm version 20.2.1 (6a49aff47758778a5f5951e731d437c317f72fb2) tentacle (stable)
'版本号确认无误 ✅️'
  1. 必要镜像拉取
Terminal window
'提前拉取 Ceph 所需镜像(避免初始化时从外网拉取失败)'
root@Ceph-201 ~# docker pull quay.io/ceph/ceph:v20
root@Ceph-201 ~# docker pull quay.io/ceph/grafana:12.2.0
root@Ceph-201 ~# docker pull quay.io/prometheus/prometheus:v3.6.0
root@Ceph-201 ~# docker pull quay.io/prometheus/node-exporter:v1.9.1
root@Ceph-201 ~# docker pull quay.io/prometheus/alertmanager:v0.28.1
'因为这些镜像没在Docker Hub上, 所以拉取镜像还是很轻松的'
root@Ceph-201 ~# docker images
quay.io/ceph/ceph:v20 0bae386bc859 2.15GB
quay.io/ceph/grafana:12.2.0 74144189b384 974MB
quay.io/prometheus/alertmanager:v0.28.1 27c475db5fb1 110MB
quay.io/prometheus/node-exporter:v1.9.1 d00a542e409e 40.8MB
quay.io/prometheus/prometheus:v3.6.0 76947e7ef22f 440MB
# 5 个核心镜像:ceph + grafana + prometheus + node-exporter + alertmanager
'save导出 & load导入别的节点'
root@Ceph-201 ~# docker save quay.io/ceph/ceph:v20 > ceph-v20.tar.gz
root@Ceph-201 ~# docker save quay.io/ceph/grafana:12.2.0 > grafana-12.2.0.tar.gz
root@Ceph-201 ~# docker save quay.io/prometheus/alertmanager:v0.28.1 > alertmanager-v0.28.1.tar.gz
root@Ceph-201 ~# docker save quay.io/prometheus/node-exporter:v1.9.1 > node-exporter-v1.9.1.tar.gz
root@Ceph-201 ~# docker save quay.io/prometheus/prometheus:v3.6.0 > prometheus-v3.6.0.tar.gz
root@Ceph-201 ~# ls *.tar.gz | xargs -n 1
alertmanager-v0.28.1.tar.gz
ceph-v20.tar.gz
grafana-12.2.0.tar.gz
node-exporter-v1.9.1.tar.gz
prometheus-v3.6.0.tar.gz
root@Ceph-201 ~# ls *.tar.gz | xargs -i scp -O {} root@10.0.0.202:/home/test
root@Ceph-201 ~# ls *.tar.gz | xargs -i scp -O {} root@10.0.0.203:/home/test
# 别的节点
root@Ceph-202 ~# ls /home/test/
alertmanager-v0.28.1.tar.gz
root@Ceph-202 ~# cd /home/test/
root@Ceph-202 test# for i in `ls`; do docker load -i $i;done
'另一台也一样'
root@Ceph-203 test# docker images
quay.io/ceph/ceph:v20
quay.io/ceph/grafana:12.2.0
...........xxxxxxxx

初始化集群#

Terminal window
root@Ceph-201 ~# cephadm bootstrap \
--mon-ip 10.0.0.201 \
--cluster-network 10.0.0.0/24 \
--initial-dashboard-password=passwd \
--dashboard-password-noupdate \
--allow-fqdn-hostname \
--skip-pull
'cephadm bootstrap 是 Ceph 集群初始化的核心命令'

📌 参数说明:

参数作用
--mon-ip 10.0.0.201指定 Monitor 监听 IP
--cluster-network 10.0.0.0/24集群内部通信网络(OSD 间数据复制走此网)
--allow-fqdn-hostname允许使用主机名而非仅 IP
--skip-pull跳过镜像拉取(已提前导入)

🔹 bootstrap 常用可选参数补充

参数作用
--registry-url=xxxx指定私有镜像仓库地址
--registry-username=xxxx私有仓库用户名
--registry-password=xxx私有仓库密码
--initial-dashboard-password=xxx ✅️预设 Dashboard 密码
--dashboard-password-noupdate ✅️禁止首次登录强制修改密码
--single-host-defaults单节点部署优化(见下方实验)
Terminal window
Verifying podman|docker is present...
...........
Waiting for mgr to start...
Waiting for mgr...
mgr not available, waiting (1/15)...
mgr not available, waiting (2/15)...
mgr not available, waiting (3/15)...
mgr is available
Ceph Dashboard is now available at:
URL: https://Ceph-201:8443/ <--'域名访问'(导入Windows中hosts表)
User: admin <--"用户名"
Password: twt8hvj9t0 <--"密码"(随机生成)

💡 Bootstrap 做了什么?

① 生成了集群 FSID(唯一标识)

② 在本地主机上为新集群创建一个 Monitor(监听 10.0.0.201<6789>) 和一个 Manager 守护程序

③ 为 Ceph 集群生成一个新的 SSH 密钥,私钥自己拿着(存在 Ceph 内部)

  • 👆 并将公钥添加到 root 用户的 /root/.ssh/authorized_keys 文件中(方便连自身)

④ 将公钥副本写入 /etc/ceph/ceph.pub(用于分发)

⑤ 将最小配置文件写入 /etc/ceph/ceph.conf(与 Ceph 守护程序通信所必需的)

⑥ 将 client.admin 管理(特权)密钥副本写入 /etc/ceph/ceph.client.admin.keyring

⑦ 将 _admin 标签添加到引导主机

  • 👆 默认情况下,任何具有此标签的主机都会获得 ceph.conf 和 keyring(管理员密钥环)的副本
Terminal window
1)SSH 密钥与 authorized_keys(为什么内容一模一样?)
root@Ceph-201 ~# cat /root/.ssh/authorized_keys
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMK+kon/b+d4oV1PQNY4AKhq5R9M17zm18uLv//0/4N8 ceph-fdc2219c-5344-11f1-8042-000c2990a57e
=======================不同的文件
root@Ceph-201 ~# cat /etc/ceph/ceph.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMK+kon/b+d4oV1PQNY4AKhq5R9M17zm18uLv//0/4N8 ceph-fdc2219c-5344-11f1-8042-000c2990a57e
=======================
─── 通俗解释 ───
SSH 密钥对 = 私钥 + 公钥
- 私钥(自己留着,不公开) > Bootstrap 生成了,存在 Ceph 内部
- 公钥(可以到处分发) > 写入 /etc/ceph/ceph.pub
/root/.ssh/authorized_keys 是什么❓️
> 这是 SSH 的"访客白名单":谁的公钥在里面,谁就能"免密登录"这台机器
=======================
为什么两个文件内容一样?
Bootstrap 拿同一把公钥做了两件事:
① 把公钥"贴到"自己的 authorized_keys 文件里
> 让 Ceph-201 自己能 SSH 免密连自己(后续编排时 master 需要连自身)
② 把公钥保存到 /etc/ceph/ceph.pub
> 以后用 ssh-copy-id -i /etc/ceph/ceph.pub 分发给其他节点
> 其他节点收到这把公钥,也会把它写入自己的 authorized_keys
> 这样 Ceph-201 就能免密 SSH 到所有节点,完成集群的编排调度
📌 一句话:ceph.pub 是钥匙的"公钥副本",authorized_keys 是"允许用这把钥匙的人进来"
✅️ 两者内容相同,因为本质上是同一把公钥
2)最小配置文件
root@Ceph-201 ~# cat /etc/ceph/ceph.conf
# minimal ceph.conf for fdc2219c-5344-11f1-8042-000c2990a57e
[global]
fsid = fdc2219c-5344-11f1-8042-000c2990a57e # < 集群唯一身份证号(UUID)
mon_host = [v2:10.0.0.201:3300/0,v1:10.0.0.201:6789/0]
=======================
─── 通俗解释 ───
fsid(集群 ID):
1.就像每个人的身份证号,全球唯一,用来区分不同的 Ceph 集群
2.当你管理多个集群时,就是靠 fsid 来区分"你在操作哪一个集群"
=======================
mon_host(Monitor 地址列表):
告诉客户端:集群的大脑(Monitor)在哪里?
格式:[v2:IP:3300/0, v1:IP:6789/0]
- v2(msgr2 协议):端口 3300,新版高性能通信协议,支持加密
- v1(msgr1 协议):端口 6789,老版协议,向后兼容
"两个协议地址都写上,新旧客户端都能连"
=======================
为什么叫"最小配置"❓️
① fsid > 知道你是谁(不能连错集群)
就像你去公司报到,只需要知道"公司名称"和"公司地址"
② mon_host > 知道大脑在哪里(去哪报到)
其他所有信息(OSD 在哪、数据怎么分布…)都由 Monitor 动态告诉你
3) 管理员密钥环(keyring)
root@Ceph-201 ~# cat /etc/ceph/ceph.client.admin.keyring
[client.admin] # < 用户名:client.admin(管理员账号)
key = AQBh9wtq2sSYJRAAweHsVl4OjRia0jObKVHapA== # < 管理员的"密码"
caps mds = "allow *" # 对 MDS 的权限: * = 所有操作
caps mgr = "allow *" # 对 Manager 的权限: * = 所有操作
caps mon = "allow *" # 对 Monitor 的权限: * = 所有操作
caps osd = "allow *" # 对 OSD 的权限: * = 所有操作
=======================
─── 通俗解释 ───
keyring(密钥环)是什么❓️
就是 Ceph 的"用户名+密码+权限"文件
类似 MySQL 的 user@host 认证,或 Linux 的 /etc/shadow
MySQL 客户端连接 ` mysql -u root -p `
# 你向 MySQL 服务端证明"我是 root"
Ceph 客户端连接 ` ceph -s ` ---> 背后读取 client.admin keyring
# ceph 命令行工具向 Monitor(mon_host 指定的地址)证明"我是 admin"
=======================
[client.admin] > 用户名
这是 Ceph 的"root 账号",拥有集群的绝对控制权
类比:Linux 的 root、MySQL 的 root@localhost
key = AQBh... > 密码(经过 base64 编码的密钥)
这是 client.admin 的认证密钥,不是人类可读的密码,而是加密密钥
客户端出示 key > Monitor 验证 > 通过后发放 session ticket
"普通客户端(只想挂个 RBD 硬盘) --> 创建一个权限受限的普通账号"
=======================
caps(capabilities,权限)> 能做什么
每个组件都有独立的权限控制:
mds = CephFS 元数据服务器 > allow * = 拥有文件系统元数据的完整读写权限
mgr = Manager > allow * = 可访问所有监控指标,调用编排功能
mon = Monitor > allow * = 可读写集群状态,参与集群管理
osd = OSD 数据守护进程 > allow * = 可以直接读写所有磁盘数据
4) 浏览器访问 Dashboard
URL: https://Ceph-201:8443/
# 用上面输出的 admin 用户名和初始密码登录即可

如果用主机名访问 Dashboard,需要修改 Windows 的hosts 解析记录

⚠️ 注意:首次登录 Dashboard 需要修改密码

配置 Ceph 集群管理命令#

方式一:宿主机直接安装(推荐)#

Terminal window
1)安装 ceph 通用工具包
root@Ceph-201 ~# apt update
root@Ceph-201 ~# apt -y install ceph-common
# 所有主机节点都装一下
2)测试使用
root@Ceph-201 ~# ceph version
ceph version 20.2.1 (6a49aff47758778a5f5951e731d437c317f72fb2) tentacle (stable)
root@Ceph-201 ~# ceph -s
cluster:
id: fdc2219c-5344-11f1-8042-000c2990a57e
health: HEALTH_WARN
# 还没加 OSD,所以健康状态为 WARN
OSD count 0 < osd_pool_default_size 3
services:
mon: 1 daemons, quorum Ceph-201 (age 7m) [leader: Ceph-201]
mgr: Ceph-201.cxdvrq(active, since 7m)
osd: 0 osds: 0 up, 0 in
# 还没有 OSD
data:
pools: 0 pools, 0 pgs
objects: 0 objects, 0 B
usage: 0 B used, 0 B / 0 B avail
pgs:

方式二:基于容器管理#

Terminal window
1)启动 cephadm shell(本质是启动了一个临时容器)
root@Ceph-201 ~# cephadm shell
Inferring fsid fdc...xxx
root@Ceph-201:/# ceph -s
cluster:
id: fdc2219c-5344-11f1-8042-000c2990a57e
health: HEALTH_WARN
OSD count 0 < osd_pool_default_size 3
...
============================
# 新开一个终端
root@Ceph-201 ~# docker ps -l
IMAGE COMMAND CREATED STATUS
0bae386bc859 "bash" About a minute ago Up About a minute
============================
root@Ceph-201:/# exit
exit
'exit退出shell后,容器随即自动删除'
2)非交互式执行命令(执行完自动退出容器)
'用 -- 分隔,后面跟要执行的命令,适合脚本和快速查看'
root@Ceph-201 ~# cephadm shell -- ceph -s
Inferring fsid ...
cluster:
id: fdc2219c-5344-11f1-8042-000c2990a57e
health: HEALTH_WARN
OSD count 0 < osd_pool_default_size 3
...
3)多集群环境指定参数
'单集群环境 --> 参数可自动添加,多集群需显式指定'
root@Ceph-201 ~# cephadm shell --fsid <fsid> -c /etc/ceph/ceph.conf -k /etc/ceph/ceph.client.admin.keyring
✅️ 明确指定集群 fsid、最小配置文件、keyring(管理员密钥环)路径

📌 关键点:cephadm shell 本质是启动一个临时容器,退出即删除

添加主机到集群#

Terminal window
'在 Ceph-201 节点上操作'
1)查看现有集群主机
root@Ceph-201 ~# ceph orch host ls
HOST ADDR LABELS STATUS
Ceph-201 10.0.0.201 _admin
1 hosts in cluster
2)把 SSH 公钥分发到其他节点
root@Ceph-201 ~# ssh-copy-id -f -i /etc/ceph/ceph.pub Ceph-202
-f # 参数用于强制复制
-i # 指定密钥
Number of key(s) added: 1
root@Ceph-201 ~# ssh-copy-id -f -i /etc/ceph/ceph.pub Ceph-203
3)添加主机到集群
root@Ceph-201 ~# ceph orch host add Ceph-202 10.0.0.202
Added host 'Ceph-202' with addr '10.0.0.202'
root@Ceph-201 ~# ceph orch host add Ceph-203 10.0.0.203
Added host 'Ceph-203' with addr '10.0.0.203'
4)验证集群节点列表
root@Ceph-201 ~# ceph orch host ls
HOST ADDR LABELS STATUS
Ceph-201 10.0.0.201 _admin
Ceph-202 10.0.0.202
Ceph-203 10.0.0.203
3 hosts in cluster
✅️ 3 个节点全部加入集群

四、添加 OSD 设备#

OSD 加入条件#

Terminal window
⚠️ 一个设备想要加入 Ceph 集群,必须满足 3 个条件:
(1)设备未被使用(无分区、无文件系统、没有被 LVM 占用、当前未挂载)
(2)设备的存储大小必须大于 5GB
(3)需要等待 30s~3min 才能在 ceph orch device ls 中看到设备
'ceph orch device ls --refresh'
✅️ --refresh 强扫,比干等 agent 周期扫描快
'绕开缓存直接触发一次新扫描'

查看可用设备#

Terminal window
1)查看集群可用的设备
root@Ceph-201 ~# ceph orch device ls
✅️ 优先加 --refresh 强扫选项
HOST PATH TYPE SIZE AVAILABLE
Ceph-201 /dev/sdb hdd 300G Yes 15m ago
Ceph-201 /dev/sdc hdd 500G Yes 15m ago
Ceph-201 /dev/sdd hdd 1024G Yes 15m ago
Ceph-201 /dev/sr0 hdd VMware..xxx space (<5GB) # < 光驱,<5GB,不可用
Ceph-202 /dev/sdb hdd 300G Yes 13m ago
Ceph-202 /dev/sdc hdd 500G Yes 13m ago
Ceph-202 /dev/sdd hdd 1024G Yes 13m ago
Ceph-202 /dev/sr0 hdd VMware..xxx space (<5GB)
Ceph-203 /dev/sdb hdd 300G Yes 10s ago
Ceph-203 /dev/sdc hdd 500G Yes 10s ago
Ceph-203 /dev/sdd hdd 1024G Yes 10s ago
Ceph-203 /dev/sr0 hdd VMware..xxx space (<5GB)
# 每个节点 3 块数据盘 × 3 个节点 = 9 个候选 OSD
============================
AVAILABLE 列的评判标准:就是"这块盘还能不能拿来当 OSD"
一旦加入OSD成功,Ceph 在上面建了 LVM、写了文件系统
再次查看时,AVAILABLE 从 Yes 变No --> ✅️ 不是盘坏了,是盘已经有主了
2)查看当前 OSD 列表(加盘前)
root@Ceph-201 ~# ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 0 root default
# 空 ——> 还没加 OSD
字段说明
IDOSD 或节点的==唯一标识符==,负数通常表示分组节点
-1:默认根节点
CLASS**存储设备的类型分类
**如 hdd(机械硬盘)、ssd(固态硬盘)、nvme(NVMe SSD)
WEIGHTCRUSH 算法中使用的权重值,决定数据分布比例
容量越大权重==通常==越大
TYPE==节点类型==
如 root(根节点)、host(主机)、osd(存储守护进程)
NAME节点名称
可能是主机名或 OSD 编号
STATUS==状态==
up 表示在线可用,down 表示离线
REWEIGHT临时权重调整值,用于控制数据迁移
1.0 为正常,0.0 为禁止数据
PRI-AFFPlacement Group 亲和性设置

📌 CLASS 类型速查:

CLASS接口/协议判断依据性能定位VMware 模拟
hdd(机械硬盘)SATA/SCSIrotational=1,/dev/sd*慢,便宜,容量大SCSI/SATA 虚拟盘(默认)
ssd(固态硬盘)SATA/SCSIrotational=0,/dev/sd*快,适合热数据SCSI/NVMe 虚拟盘
nvme(NVMe SSD)PCIe 直连/dev/nvme*(自动识别)最快,延迟最低NVMe 虚拟盘
Tip

hdd < ssd < nvme — CRUSH 用 CLASS 区分快慢,实现数据分层

元数据放 nvme、热数据放 ssd、冷数据放 hdd

⭐批量添加 OSD#

Terminal window
'一次一条命令,将 9 块盘全部添加为 OSD'
# --- Ceph-201 节点 ---
root@Ceph-201 ~# ceph orch daemon add osd Ceph-201:/dev/sdb
✅️ 太慢了,等等吧...
Created osd(s) 0 on host 'Ceph-201'
root@Ceph-201 ~# ceph orch daemon add osd Ceph-201:/dev/sdc
Created osd(s) 1 on host 'Ceph-201'
root@Ceph-201 ~# ceph orch daemon add osd Ceph-201:/dev/sdd
Created osd(s) 2 on host 'Ceph-201'
root@Ceph-202 ~# ceph orch daemon add osd Ceph-202:/dev/sdb
Error initializing cluster client: ObjectNotFound('RADOS object not found (error calling conf_read_file)')
# ↑ Ceph-202 本地找不到 /etc/ceph/ceph.conf,无法知道 Monitor 在哪,认证凭据也没有

🧱 通俗解释:

ceph orch host add(添加主机到集群) 只是把主机名和 IP 登记到集群的”花名册”上(Monitor 知道有这台机器了),但并没有把”身份证”发给这台机器

执行 ceph orch daemon add osd 时,命令要和 Monitor 通信——需要两样东西:

  • ceph.conf > “公司在哪”(Monitor 地址)
  • ceph.client.admin.keyring > “你是谁”(管理员身份证明)

Ceph-202 本地没有这两个文件 > 报 ObjectNotFound

解决:从 Ceph-201(引导节点)拷贝过去就行

💡 总结:配置文件管的是”从哪台机器能执行 ceph 管理命令”

📌 延伸 — 多集群管理:既然 ceph.conf + keyring 决定了”连哪个集群、以什么身份连”

那么一个客户端拿着多套配置文件,就能同时管理多个 Ceph 集群:

Terminal window
# 切换到集群 A
ceph --fsid <fsid-A> -c /etc/ceph/ceph-A.conf -k /etc/ceph/ceph-A.client.admin.keyring -s
# 切换到集群 B
ceph --fsid <fsid-B> -c /etc/ceph/ceph-B.conf -k /etc/ceph/ceph-B.client.admin.keyring -s
Note

无需登录到不同节点,在本地切换配置文件即可——类似于 kubectl 的 context 切换

Terminal window
'👇在 Ceph-201 上执行,把"身份证"分发到其他节点'
root@Ceph-201 ~# scp /etc/ceph/ceph.conf root@Ceph-202:/etc/ceph/
root@Ceph-201 ~# scp /etc/ceph/ceph.client.admin.keyring root@Ceph-202:/etc/ceph/
# ✅ ceph.client.admin.keyring 是 client.admin 这个 Ceph 用户的认证凭据
# 谁拿着这个文件,谁就能以 admin 身份和 Monitor 通信
# 拷给 Ceph02,意味着 在 Ceph02 上敲 ceph 命令的人 拥有了 admin 权限——不是节点本身"变成了 admin"
'👇设置正确权限'
root@Ceph-201 ~# ssh root@Ceph-202 "chmod 644 /etc/ceph/ceph.conf && chmod 600 /etc/ceph/ceph.client.admin.keyring"
# --- Ceph-202 节点 ---
root@Ceph-201 ~# ceph orch daemon add osd Ceph-202:/dev/sdb
Created osd(s) 3 on host 'Ceph-202'
root@Ceph-201 ~# ceph orch daemon add osd Ceph-202:/dev/sdc
Created osd(s) 4 on host 'Ceph-202'
root@Ceph-201 ~# ceph orch daemon add osd Ceph-202:/dev/sdd
Created osd(s) 5 on host 'Ceph-202'
# --- Ceph-203 节点 ---
'同上'
root@Ceph-201 ~# ceph orch daemon add osd Ceph-203:/dev/sdb
Created osd(s) 6 on host 'Ceph-203'
root@Ceph-201 ~# ceph orch daemon add osd Ceph-203:/dev/sdc
Created osd(s) 7 on host 'Ceph-203'
root@Ceph-201 ~# ceph orch daemon add osd Ceph-203:/dev/sdd
Created osd(s) 8 on host 'Ceph-203'

❤️LVM 技术栈#

💡 底层原理:ceph 底层使用 ==LVM 技术栈== 管理磁盘,每块盘会被初始化为 LVM PV > VG > LV

LVM技术栈
LVM技术栈

🧱 LVM 技术栈详解:PV > VG > LV

LVM(==逻辑卷管理器==)是 Linux 下对磁盘进行灵活分区管理的技术

它的核心思路是:在物理磁盘和文件系统之间加一层抽象

让你可以随时调整”分区”大小,而不需要像传统分区那样推倒重来

① 物理卷 — PV(Physical Volume)

PV 是最底层的存储单元

  • PV 可以是一整块物理磁盘(如 /dev/sdb),也可以是磁盘上的一个分区(如 /dev/sda3)
  • 一块盘/分区被 pvcreate 标记后,LVM 就能识别并使用它
  • PV 内部被切分为==固定大小==的 PE(Physical Extent,默认 4MB)
    • PE 是 LVM 分配空间的最小单位

📌 类比:PV 就像一块空地——不管原来是整座山(整块盘)还是山的一角(分区),圈进来之后就都是可用的地皮

② 卷组 — VG(Volume Group)

VG 是 LVM 的==“资源池”==——把多块 PV 整合成一个统一的大池子

  • 多个 PV 可以加入同一个 VG,VG 的容量 = 所有 PV 容量之和
  • VG 就像一个弹性仓库——你只负责从池子里取空间,底层是哪块盘不用操心
  • 后期可以随时往 VG 里加新盘(新 PV),也可以移除旧盘(数据迁移后)

📌 类比:VG 就像把多块空地合并成一个大工地

③ 逻辑卷 — LV(Logical Volume)

LV 是从 VG 中切分出来的、==最终可用==的存储空间

  • 从 VG 中==按需划分==,大小可以动态调整(扩容/缩容)
  • LV 可以像普通分区一样格式化(ext4/XFS)并挂载使用
  • LV 支持快照(snapshot)——给某个 LV 拍一个”当时的状态”,用于备份或回滚

📌 类比:LV 就像从大工地里隔出来的房间——想要多大隔多大,房间不够用了还能在线扩容

📋 三层结构速查表:

层次英文是什么关键操作
物理卷PV底层存储”砖块”pvcreate /dev/sdb
卷组VG多块 PV 的”资源池”vgcreate vg_name /dev/sdb /dev/sdc
逻辑卷LV最终使用的”存储空间”lvcreate -L 100G -n lv_name vg_name

🔁 数据流向:物理磁盘 > PV > VG > LV > 格式化文件系统 > 挂载使用


⚖️ LVM 的优缺点:

优点缺点
1在线扩容:LV 不够用了,在线扩,不影响正在跑的业务多一层开销:比直接操作裸盘多一层抽象,有微弱性能损耗
2灵活聚合:多块小盘合成一个大 VG,打破单盘容量限制
加新盘 > 扩 VG > 扩 LV > 文件系统变大
故障面扩大:VG 中某块 PV 坏了,用到它的 LV 会受影响
3快照功能:给 LV 拍快照,备份/回滚/测试都很方便学习成本:多了一套概念(PV>VG>LV),排错链路变长
4动态伸缩:不光能扩容,还能缩容(ext4 支持,XFS 不支持缩容)固件限制:固件不认识 LVM,只认普通分区
所以 /boot 通常要单独分出来放在 LVM 外面

💻 Ubuntu 与 LVM:

Ubuntu 系统安装时如果勾选”使用 LVM”,底层就是这样运作的——安装程序自动创建:

Terminal window
# Ubuntu 默认 LVM 结构(以 40G 系统盘为例)
/dev/sda3 > PV ──> ubuntu-vg(VG)──> ubuntu-lv(LV,挂载到 /)
│
└── LV 不会占满整个 VG,留一部分空闲
'不是空间浪费,是刻意的'
'留着以后给 / 根分区在线扩容用'
Terminal window
# 验证一下(Ubuntu环境里就有)
root@Ceph-201 ~# lsblk
sda 8:0 0 40G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 2G 0 part /boot ✅️'/boot只认普通分区'
└─sda3 8:3 0 '38G' 0 part
└─ubuntu--vg-ubuntu--lv 252:0 0 '30G' 0 'lvm' /
👆 '这一整行是逻辑卷(LV)' 'LVM技术栈'👆
📌 细节 --> 从sda3开始分
✅️ 38G 的 PV,LV 只用了 30G > 8G 空闲留在 VG 里
root@Ceph-201 ~# vgs
VG #PV #LV #SN Attr VSize VFree
ubuntu-vg 1 1 0 wz--n- 38.00g 8.00g
👆 '这才是卷组'
✅️ VFree = 8G < 空闲空间,随时可以扩给 /

📌 Ubuntu 不会一开始就把所有空间分给根分区,只会分一半左右——剩下的留在 VG 里

  • 方便后续 lvextend 在线扩容,不用重装系统

🔗 回到 Ceph:

Ceph 添加 OSD 时,ceph orch daemon add osd 在背后做的事本质上就是这套 LVM 流程:

Terminal window
# 当你执行 ceph orch daemon add osd Ceph-201:/dev/sdb 时,Ceph 自动:
/dev/sdb > pvcreate > 创建 PV
> vgcreate > 创建 VG(名:ceph-<VG_UUID>)
> lvcreate > 创建 LV(不进行文件系统格式化, BlueStore 直接写裸 LV)
✅️ BlueStore: '不依赖任何文件系统,直接在裸盘上存储'
Terminal window
root@Ceph-201 ~# vgs
VG #PV #LV #SN Attr VSize VFree
ceph-023d...f772 1 1 0 wz--n- <500.00g 0
ceph-6f9f...7035 1 1 0 wz--n- <1024.00g 0
ceph-fadf...ac73 1 1 0 wz--n- <300.00g 0
ubuntu-vg 1 1 0 wz--n- <38.00g <8.00g
# 👆 卷组名 = ceph-<VG_UUID>(VG_UUID 是 LVM 随机生成的)
Terminal window
'在 Ceph-202 上验证 LVM 结构'
root@Ceph-202 ~# lsblk
sda 8:0 0 40G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 2G 0 part /boot
└─sda3 8:3 0 38G 0 part
└─ubuntu--vg-ubuntu--lv 252:0 0 30G 0 lvm /
'上面是系统盘'
sdb ✅️物理磁盘 'PV' 8:16 0 300G 0 disk
└─ceph--fadf...ac73-osd--block--2078...bd8bd 252:1 0 300G 0 lvm
sdc ✅️物理磁盘 'PV' 8:32 0 500G 0 disk
└─ceph--023d...f772-osd--block--8bb5...f359 252:2 0 500G 0 lvm
sdd ✅️物理磁盘 'PV' 8:48 0 1T 0 disk
└─ceph--6f9f...7035-osd--block--da9a...7195 252:0 0 1024G 0 lvm
# 👆 lsblk 看到的是基于物理磁盘创建的 LV(逻辑卷)
'这些逻辑卷被用作 Ceph OSD 的数据存储'

📋 命名规律速查:

层级命名格式示例(以 sdb 300G 为例)
VGceph-<VG_UUID>
随机生成的
ceph-fadf...ac73
LV 短名osd-block-<OSD_FSID>osd-block-2078...bd8bd
LV 完整名(lsblk)ceph--<VG_UUID>-osd--block--<OSD_FSID>ceph--fadf...ac73-osd--block--2078...bd8bd

📌 规律:ceph- 开头 > ==VG(卷组)==,osd-block- 开头 > ==LV 短名==

  • LV 完整名 = VG名 + LV短名,lsblk 里看到的就是这个完整名
  • LV 短名中的 osd-block-<OSD_FSID> = OSD 的 fsid(/var/lib/ceph/<集群>/osd.<N>/fsid)
Terminal window
/var/lib/ceph/
└── fdc2219c-5344-11f1-8042-000c2990a57e/ <-- '这是集群的 FSID'
├── cephadm.adad9831..xxx
├── osd.3 ✅️ OSD 目录
├── osd.4 ✅️ OSD 目录
├── osd.5 ✅️ OSD 目录
├── ...xxx
└── crash
root@Ceph-201 osd.0# pwd
/var/lib/ceph/<集群>/osd.0
'每个 OSD 有一个唯一的 fsid'
root@Ceph-201 osd.0# cat fsid
2078...bd8bd
对比Ubuntu 系统盘 LVMCeph OSD 数据盘 LVM
PV/dev/sda3(分区)/dev/sdb(整块裸盘)
VGubuntu-vgceph-<VG_UUID>
LV 短名ubuntu-lvosd-block-<OSD_FSID>
LV 完整名(lsblk)ubuntu--vg-ubuntu--lvceph--<VG_UUID>-osd--block--<OSD_FSID>
文件系统ext4(建在 LV 上)无(BlueStore 绕过文件系统直接操作裸 LV)
扩容方式lvextend + resize2fs不需要——Ceph 已占满整块盘

📌 一句话:Ceph 底层使用 LVM 技术栈管理每块 OSD 数据盘

  • PV>VG>LV 三步把裸盘变成 Ceph 可管理的存储单元

  • BlueStore 直接在 LV 上读写,省掉了文件系统这层中间商

验证 OSD 状态#

Terminal window
1)查看 OSD 树
root@Ceph-201 ~# ceph osd tree
'每个字段的含义,参考上面的表格'
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 5.34389 root default
-3 1.78130 host Ceph-201
0 hdd 0.29300 osd.0 up 1.00000 1.00000
1 hdd 0.48830 osd.1 up 1.00000 1.00000
2 hdd 1.00000 osd.2 up 1.00000 1.00000
-5 1.78130 host Ceph-202
3 hdd 0.29300 osd.3 up 1.00000 1.00000
4 hdd 0.48830 osd.4 up 1.00000 1.00000
5 hdd 1.00000 osd.5 up 1.00000 1.00000
-7 1.78130 host Ceph-203
6 hdd 0.29300 osd.6 up 1.00000 1.00000
7 hdd 0.48830 osd.7 up 1.00000 1.00000
8 hdd 1.00000 osd.8 up 1.00000 1.00000
'hdd -->机械硬盘'
# 9 个 OSD 全部 up ✅️
2)查看集群健康状态
root@Ceph-201 ~# ceph -s
cluster:
id: fdc2219c-5344-11f1-8042-000c2990a57e
health: HEALTH_OK ✅️ 健康!
services:
mon: 3 daemons, quorum Ceph-201,Ceph-202,Ceph-203 (age 113m) [leader: Ceph-201]
mgr: Ceph-201.cxdvrq(active, since 5h), standbys: Ceph-202.xdeumk
osd: 9 osds: 9 up (since 37m), 9 in (since 39m) ✅️ 9 个全 up
data:
pools: 1 pools, 1 pgs
objects: 2 objects, 449 KiB
usage: 249 MiB used, 5.3 TiB / 5.3 TiB avail ✅️ 总空间 5.3T
pgs: 1 active+clean

📌 集群关键数据:3 节点 × 3 盘 = 9 OSD,总容量 ~5.3 TiB,9/9 在线,状态 HEALTH_OK

OSD 的移除与磁盘清理#

加盘的反向操作——当你需要撤掉某个 OSD 或重新部署时:

Terminal window
1)从集群中删除 OSD 守护进程
root@Ceph-201 ~# ceph orch daemon rm osd.0 --force
Removed osd.0 from host 'Ceph-201'
rm # 移除 OSD 守护进程(容器停止并被删除)
osd.0 # 表示OSD的ID编号
--force # 跳过确认提示,直接执行
2)擦除磁盘上的 Ceph 数据(恢复为空盘)
ceph orch device zap <主机名> <路径> [--force]
root@Ceph-201 ~# ceph orch device zap Ceph-201 /dev/sdb --force
zap successful for /dev/sdb on Ceph-201
zap # "清零"——销毁 Ceph 建的 LVM 卷、分区、文件系统
--force # 跳过确认提示
root@Ceph-201 ~# ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 1.78130 root default
-3 1.78130 host Ceph-201
0 hdd 0.29300 osd.0 'down' 1.00000 1.00000
'已经down掉了'
root@Ceph-201 ~# ceph orch device ls
Ceph-201 /dev/sdb hdd 300G 'Yes' ✅️ AVAILABLE为Yes --> 可以重新添加为OSD
root@Ceph-201 ~# ceph orch daemon add osd Ceph-201:/dev/sdb
Created osd(s) 3 on host 'Ceph-201'
root@Ceph-201 ~# ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 2.07430 root default
-3 2.07430 host Ceph-201
0 hdd 0.29300 'osd.0' down 0 1.00000
1 hdd 0.48830 'osd.1' up 1.00000 1.00000
2 hdd 1.00000 'osd.2' up 1.00000 1.00000
3 hdd 0.29300 'osd.3' up 1.00000 1.00000
root@Ceph-201 ~# ceph -s
cluster:
id: 3ca027a7-5400-11f1-a4e3-000c2990a57e
health: HEALTH_WARN ❌️
⚠️ 此时 `ceph -s` 出现 `1 stray daemon(s)` 告警
1 stray daemon(s) not managed by cephadm
# 一个流浪进程,不被cephadm管理了
services: xxx
osd: 4 osds: 3 up (since 61s), 3 in (since 42s)
'4 个 OSD 记录,但只有 3 个在线'
osd.0 > down(旧号,没人管了)
osd.3 > up (新盘,新 ID)
Terminal window
🧱 为什么会有 stray daemon❓️
ceph orch daemon rm osd.0 > 只删了编排器层(cephadm 视角)的容器进程
ceph orch device zap Ceph-201 /dev/sdb > 磁盘清空
但是!CRUSH 拓扑层(CRUSH 全局视角)还记着 osd.0:
> CRUSH 说:"osd.0 应该在线啊,去哪了?"
> cephadm 说:"osd.0 不归我管了"
> 这个没人认领的 OSD 就是 stray daemon(流浪进程)
层面命令入口管的视角
CRUSH 拓扑层ceph osd ...CRUSH 地图、OSD 状态、数据放置规则CRUSH 全局视角——“数据该往哪放”
编排器层ceph orch ...容器/进程、磁盘设备、主机节点cephadm 视角——“服务跑在哪”

📌 stray daemon 的根因:ceph orch daemon rm 只清了编排器层,CRUSH 拓扑层还记着这个 OSD > 两层不一致 > 集群告警

✅ 正确做法:用 ceph orch osd rm 一条命令同时清两层(停进程 + 清 CRUSH + 可选 zap),详见 day03 笔记

🔧 如果已经出现 stray daemon,此时 OSD 已经是 down 状态,直接 purge 就行:

Terminal window
'从 CRUSH 表彻底删除 > 集群名单踢出'
ceph osd purge osd.<旧ID> --yes-i-really-mean-it
# stray daemon 的 OSD 已经 down 了(容器早就被 rm 了),所以直接 purge 不会报错
root@Ceph-201 ~# ceph -s
cluster:
id: 3ca027a7-5400-11f1-a4e3-000c2990a57e
health: HEALTH_OK
services:...xxx
osd: 3 osds: 3 up (since 3m), 3 in (since 6m)
'三个osd,三个都在运行'

🔹 osd out 是什么?

Terminal window
`osd out` 的作用是 标记 OSD 为"即将退役"
触发 PG 恢复——集群自动把该 OSD 上的数据副本搬到其他 OSD,等数据全部搬完后再删盘就不会丢数据
============================
osd out 之后发生的事:
osd.3 上的副本 > 搬到 osd.1 / osd.2 / osd.4 ...
PG 状态:recovering > active+clean
数据搬完了 > 删 osd.3 就安全了

⚠️ 但实验环境几乎没数据,osd out 反而触发无意义的恢复

  • 集群拼命搬空气,搬完你又加回来,纯属折腾

✅ 删除 OSD — 生产环境 vs 实验环境:

Terminal window
'============================='
' 生产环境(有真实数据)— 四步 '
'============================='
1)标记退役 > 触发 PG 恢复,数据安全搬到其他 OSD
root@Ceph-201 ~# ceph osd out osd.3
'等待 recovery 完成'
# ceph -s 确认 PG 全部 active+clean
'============================='
' 实验环境(没数据)— 三步即可 '
'============================='
📌 下篇笔记📚有更简单的方法
`ceph orch osd rm` ——> 一条命令完成停进程 + 清 CRUSH + 清磁盘
2)停进程
root@Ceph-201 ~# ceph orch daemon rm osd.3 --force
3)销户口
root@Ceph-201 ~# ceph osd purge osd.3 --yes-i-really-mean-it
4)清磁盘
root@Ceph-201 ~# ceph orch device zap Ceph-201 /dev/sdb --force
Terminal window
对比:
生产环境:out > daemon rm > purge > zap (多一步 out,保证数据安全)
实验环境: daemon rm > purge > zap (跳过 out,避免无意义恢复)
==============================
关键依赖:无论哪种,purge 都必须在 daemon rm 之后(要求 down 状态)
  • ⚠️ zap 不可逆,生产环境慎用;实验环境无所谓
    • 拍快照, 尝试单机部署

五、CRUSH 规则与故障域#

🧱 故障域概念:Ceph 的 CRUSH 算法决定了数据副本如何分布在不同的 OSD 上,而”故障域”定义了故障的隔离边界

*默认情况下,Ceph 按**主机(host)*划分故障域

  • 这意味着 CRUSH 会尽量将同一数据的多个副本放置在不同的主机上

默认规则长什么样❓️

Terminal window
root@Ceph-201 ~# ceph osd crush rule dump
'查看Ceph集群中的所有CRUSH规则'
[
{
"rule_id": 0, <-- 默认规则 ✅️
"rule_name": "replicated_rule",
"type": 1,
"steps": [
{ "op": "take", "item": -1, "item_name": "default" },
{ "op": "chooseleaf_firstn", "num": 0, "type": "host" },
{ "op": "emit" }
]
}
]

📌 chooseleaf_firstn + type: "host" 的执行步骤(假设副本数 = 3):

Terminal window
① take default > 从 CRUSH 树的根节点开始
② chooseleaf_firstn > 选 N 台不同的 host,每台 host 下再挑 1 块最佳 OSD
num = 0 > 这里的 0 不是"选 0 个",是"不硬编码"的占位符
> 实际 N 从存储池的 size 参数动态读取
> 池 size=3 > 0 等价于 3(如果池 size=2,0 就等价于 2)
Step 1: 选第 1 台 host > 挑该 host 下的一块 OSD > 放副本①
Step 2: 选第 2 台 host(必须和 Step1 不同)> 挑 OSD > 放副本②
Step 3: 选第 3 台 host(必须和 Step1/2 不同)> 挑 OSD > 放副本③
核心约束:同一台 host 只能被选中一次!

💡 num = 0 的设计意图:让一条 CRUSH 规则能被多个不同副本数的池复用——规则本身不写死数量,而是从池的 size 参数动态读取

num 如果写死成 3,那这条规则就只能给 size=3 的池用,其他池得另建规则


单节点 + 默认规则 = 矛盾

你的单节点 CRUSH 树:

Terminal window
root default
└─ host Ceph-201 < 只有 1 台主机!
├─ osd.0 (sdb)
├─ osd.1 (sdc)
└─ osd.2 (sdd)

CRUSH 尝试放置 3 个副本的过程:

Terminal window
选第 1 台 host > Ceph-201 > 挑 osd.0 > 放副本① ✅
选第 2 台 host > 树里只有 Ceph-201,但它已被选过 > 不能再选 > 失败 ❌
选第 3 台 host > 同上 > 失败 ❌
最终结果:3 个副本只放下了 1 个

“只能选 1 块盘”这句话的真正含义:

你有 3 块盘(sdb、sdc、sdd),盘是够的

但 CRUSH 规则的第一关不是”找盘”,而是”找不同的主机”

每台主机只能被选一次,1 台主机 > 只能过第一关一次 > 只能选到 1 块盘

  • 3 块盘 ≠❌️ 3 个副本存放位置
  • 3 台主机 =✅️ 3 个副本存放位置 < CRUSH 要的是这个

单节点 HEALTH_WARN 复现#

Terminal window
'主要是在单节点下进行添加OSD设备'
# 我这里是进行了恢复快照
root@Ceph-201 ~# ceph orch host ls
HOST ADDR LABELS STATUS
Ceph-201 10.0.0.201 _admin
1 hosts in cluster
'不把其他两台主机添加到集群' <-- 它俩关机状态
root@Ceph-201 ~# ceph orch daemon add osd Ceph-201:/dev/sdb
Created osd(s) 0 on host 'Ceph-201'
# 然后直接添加OSD设备
root@Ceph-201 ~# ceph orch daemon add osd Ceph-201:/dev/sdc
Created osd(s) 1 on host 'Ceph-201'
root@Ceph-201 ~# ceph orch daemon add osd Ceph-201:/dev/sdd
Created osd(s) 2 on host 'Ceph-201'
root@Ceph-201 ~# ceph -s
cluster:
id: fdc2219c-5344-11f1-8042-000c2990a57e
health: HEALTH_OK
'在我添加完, 立马查看状态 ✅️ OK'
可是并没有看到 HEALTH_WARN ❌️

⚠️ 加完 3 块 OSD 立刻 ceph -s 看到 HEALTH_OK,是因为 PG 还没完成创建/peering

实测等一会儿再查,状态就变换了❌️,不是版本差异,纯粹是时序问题

Terminal window
root@Ceph-201 ~# ceph -s
cluster:
id: fdc2219c-5344-11f1-8042-000c2990a57e
health: HEALTH_WARN ❌️ "告警暴露出来了"
Reduced data availability: 1 pg inactive --> 'PG 不活跃'
Degraded data redundancy: 1 pg undersized --> '副本数不足'
# 要 3 个只放了 1 个
root@Ceph-201 ~# ceph osd pool ls detail
'显示集群中所有存储池的详细配置信息'
pool 1 '.mgr' replicated size 3 min_size 2 crush_rule 0...
replicated size 3 # 副本数=3 > 要放 3 份
min_size 2 # 最少 2 个副本才允许读写I/O
crush_rule 0 # crush_rule 0 = 默认规则 (type = host)
📌 只有 1 台主机 > CRUSH 只能选出 1 块盘 > PG undersized '副本数不足'

创建以 OSD 为故障域的规则#

命令作用一句话
ceph osd crush rule ls列出所有规则
==只列名字==
“有哪些规则”
ceph osd crush rule dump <规则名>查看规则内部细节
==完整 JSON==
“这条规则内部长什么样”
ceph osd crush rule create-replicated <规则名> <根节点> <故障域>创建副本规则“起名 + 定根 + 定故障域,三步搞定”
ceph osd crush rule create-erasure <规则名> <profile名>创建纠删码规则“引用 profile,让规则知道 k/m 和编码算法”
对比维度副本规则 create-replicated纠删码规则 create-erasure
参数规则名 + 根节点 + 故障域规则名 + 纠删码 profile
故障域在哪指定命令里直接写(host / osd / rack)不在命令里——profile 已声明 k+m,CRUSH 据此选盘
为什么不同副本 = 简单 copy,不需要额外配置纠删码要提前定义 k+m 比例、编码算法(jerasure / lrc 等),这些全在 profile 里
Terminal window
root@Ceph-201 ~# ceph osd crush rule ls
replicated_rule < 默认,type = host
1)导出并反编译 CRUSH Map
root@Ceph01 ~# ceph osd getcrushmap -o /tmp/crushmap.bin
69
# 导出整个“CRUSH 地图”(包含所有设备、主机、机架拓扑和所有规则)
root@Ceph01 ~# file /tmp/crushmap.bin
/tmp/crushmap.bin: data
`二进制文件没有办法直接通过cat查看`
root@Ceph01 ~# apt -y install ceph-base
root@Ceph01 ~# crushtool -d /tmp/crushmap.bin -o /tmp/crushmap.txt
'反编译后得到可读文本'
root@Ceph01 ~# file /tmp/crushmap.txt
/tmp/crushmap.txt: ASCII text
2)看默认规则
root@Ceph01 ~# grep -A6 "rule replicated_rule" /tmp/crushmap.txt
rule replicated_rule {
id 0
type replicated
step take default
step chooseleaf firstn 0 type host
step emit
}
'step take default → 从 root default 这棵树开始'
'step chooseleaf firstn 0 type host → 选叶子,故障域是 host(保证副本跨主机)'
'step emit → 输出这一组 OSD'
=======优先用命令创建新的规则=======
`可以直接编辑对应的CRUSH Map总的配置文件`
root@Ceph01 ~# vim /tmp/crushmap.txt
'编译回二进制'
root@Ceph01 ~# crushtool -c /tmp/crushmap.txt -o /tmp/crushmap-new.bin
root@Ceph01 ~# ls /tmp | grep crush*
crushmap.bin
crushmap-new.bin
crushmap.txt
'应用新地图'
root@Ceph01 ~# ceph osd setcrushmap -i /tmp/crushmap-new.bin
=======优先用命令创建新的规则=======
3)创建新规则(故障域从 host 降为 osd)
'语法:ceph osd crush rule create-replicated <规则名> <根节点> <故障域级别>'
root@ceph:~# ceph osd crush rule create-replicated rule_osd default osd
root@ceph:~# ceph osd crush rule ls
replicated_rule < 默认,type = host
rule_osd < 新建,type = osd
4)对比两条规则
root@ceph:~# ceph osd crush rule dump rule_osd
'指定查看我们刚创建的规则 rule_osd'
# dump后面紧跟规则名
{
"rule_id": 1, <-- 新建规则 ✅️
"rule_name": "rule_osd",
"type": 1,
"steps": [
{ "op": "take", "item": -1, "item_name": "default" },
{ "op": "choose_firstn", "num": 0, "type": "osd" },
{ "op": "emit" }
]
}

📌 choose_firstn + osd VS chooseleaf_firstn + host

type = osd(choose_firstn)

root default

osd.0 → 副本①

osd.1 → 副本②

osd.2 → 副本③

type = host(chooseleaf_firstn)

root default

host Ceph-201

同一 host 只能被选 1 次

osd.0 → 副本① ✅

osd.1 ✗

osd.2 ✗

只能放 1 个副本 ❌

3 个副本全部放下 ✅

都在同一台主机上也没关系

type = osd(choose_firstn)

root default

osd.0 → 副本①

osd.1 → 副本②

osd.2 → 副本③

type = host(chooseleaf_firstn)

root default

host Ceph-201

同一 host 只能被选 1 次

osd.0 → 副本① ✅

osd.1 ✗

osd.2 ✗

只能放 1 个副本 ❌

3 个副本全部放下 ✅

都在同一台主机上也没关系

  • ① chooseleaf_firstn + host:先选 host → 再在 host 下挑 OSD,同一 host 只能被选一次
  • ② choose_firstn + osd:直接在 OSD 层选,不管 OSD 属于谁,任何 OSD 都可被独立选中

关联存储池到新规则#

Terminal window
ceph osd pool set <存储池名称> <参数名> <参数值>
# 将存储池关联到新规则
root@Ceph-201 ~# ceph osd pool set .mgr crush_rule rule_osd
# rule_osd 我们新建的规则
set pool 1 crush_rule to rule_osd
===================================
`.mgr` 是什么❓️
1.Manager 守护进程的内部存储池,bootstrap(初始化集群) 时自动创建
2.Manager 用它来存设备健康+数据、性能指标、Dashboard 配置等"内部账本",不存用户数据
3.点号开头是命名惯例,表示"系统池"
4.集群启动后第一个池就是它——所以 单节点 HEALTH_WARN 也是它先暴露出来的
`Dashboard` 是什么❓️
1.就是 Ceph 自带的 Web 管理界面(端口 8443)
2.你浏览器打开后能看集群健康状态、OSD列表、性能图表、存储池信息等等
✅️ Dashboard 配置存在 .mgr 池里指的是
1.你通过 Web 界面做的设置(比如改了登录密码、调了监控告警阈值)
2.Manager进程把这些配置数据写到 .mgr 池里持久化保存
3.这样即使 Manager 重启,配置也不会丢
root@Ceph-201 ~# ceph osd pool ls detail
'显示集群中所有存储池的详细配置信息'
pool 1 '.mgr' ... crush_rule 1 ...
✅️ rule_id 从 0 变成 1
# 由默认规则 --> 到新建规则
root@Ceph-201 ~# ceph -s
cluster:
health: HEALTH_OK ✅️
...
pgs: 1 active+clean 🏷️

场景速查表#

场景故障域副本数CRUSH 规则结果
多节点(≥3 台)host3chooseleaf_firstn + host✅ HEALTH_OK
单节点 + 默认规则host3chooseleaf_firstn + host❌ PG undersized
副本数不足
单节点 + 手动改规则osd3choose_firstn + osd✅ HEALTH_OK
单节点 + --single-host-defaultsosd2choose_firstn + osd✅ HEALTH_OK

🧱 一句话总结:默认 CRUSH 规则 type=host 的本质是**“同一个数据的多个副本必须放在不同主机上”**

  • 宁可少放,也不能全堆在同一台主机(主机一挂所有副本全丢)
  • 单节点实验要么用 --single-host-defaults,要么手动创建 type=osd 的规则

要在单个主机上部署 Ceph 集群,请在引导时使用 --single-host-defaults 标志

此类集群通常不适合生产环境

该标志会自动设置以下配置选项:

  • global/osd_crush_chooseleaf_type = 0 — 故障域从 host 降为 OSD 级别
    • 默认规则直接就是 osd 故障域,无需手动改
  • global/osd_pool_default_size = 2 — 默认副本数从 3 降为 2
  • mgr_standby_modules = False — standby MGR 不预加载 Python 模块(进程仍在,仅节省资源)

集群删除(完整流程)#

Terminal window
root@Ceph-201 ~# ceph orch device ls
'查看集群可用设备' --> 它们已经添加为OSD(已经被 Ceph 占用,不能再加第二次)
--> NO(不可用,不能再次添加了) Has a FileSystem(有了文件系统)
Ceph-201 /dev/sdb hdd 300G No❌️
Ceph-201 /dev/sdc hdd 500G No❌️
Ceph-201 /dev/sdd hdd 1024G No❌️
====================================
AVAILABLE = No 不是"坏了",是"已上岗" --> 表示磁盘上有 Ceph 数据
1)禁用 cephadm 模块(停止所有编排操作)
root@Ceph-201 ~# ceph mgr module disable cephadm
2)获取集群 FSID
root@Ceph-201 ~# ceph fsid
fdc2219c-5344-11f1-8042-000c2990a57e
3)在所有主机上清除 Ceph 守护程序和数据
'⚠️ 所有节点都要执行!'
root@Ceph-201 ~# cephadm rm-cluster --force --zap-osds --fsid fdc2219c-5344-11f1-8042-000c2990a57e
--force # 强制删除 --> "别问我确认,直接干"
--zap-osds # 清除磁盘上的 OSD 数据
--fsid fdcxxx # 指定FSID
Deleting cluster with fsid: fdc2219c-...xxx
Zapping /dev/sdb...
Zapping /dev/sdc...
Zapping /dev/sdd...
'初始化集群自动创建的文件也都删除了'
# No such file or directory
root@Ceph-201 ~# ls /etc/ceph/ceph.pub
# 到处分发的公钥
'都删除了'
root@Ceph-201 ~# ls /etc/ceph/ceph.conf
# 最小配置文件
root@Ceph-201 ~# ls /etc/ceph/ceph.client.admin.keyring
# 管理员密钥环
4)清理残留
root@Ceph-201 ~# ceph -s
Error initializing cluster client: ObjectNotFound(...) --> ✅️ 集群已不存在
root@Ceph-201 ~# rm -rf /etc/ceph/rbdmap
root@Ceph-201 ~# > /root/.ssh/authorized_keys
'清空 authorized_keys 文件,移除 cephadm bootstrap 写入的 SSH 公钥'

⚠️ 注意:

  • cephadm rm-cluster 需要在所有集群节点上执行

  • --zap-osds 会彻底清除磁盘上的所有 Ceph 数据

    • ☠️ 清空 OSD 盘上的所有数据
      • ✅️ 不加 —zap-osds 还有救(盘上数据还在,重建 Monitor 就行)
      • 参照下面👇重建集群
    • 你要是想保留数据只重建 Monitor 不加 —zap-osds

手动指定集群 FSID#

  • 它只有一个场景:集群坏了要重建,但你不想丢数据
    • Ceph数据、还在机器还在、盘还在
Terminal window
正常装集群:cephadm bootstrap
└── 自动生成一个随机 FSID,OSD 盘上标记的就是这个 ID
'FSID 就是集群的"身份证号"'
root@Ceph-201 ~# ceph fsid
fdc2219c-5344-11f1-8042-000c2990a57e
# 获取当前FSID号
root@Ceph-201 ~# cephadm bootstrap --fsid fdc221...xxx
--fsid 用旧 ID > 磁盘上的 OSD 还认得这个 FSID,数据能恢复

单节点部署#

Terminal window
'单节点 + --single-host-defaults'
1)设置主机名
root@Ceph-201 ~# tail -3 /etc/hosts
10.0.0.201 Ceph-201
10.0.0.202 Ceph-202
10.0.0.203 Ceph-203
2)使用 --single-host-defaults 重新引导
root@Ceph-201 ~# cephadm bootstrap \
--mon-ip 10.0.0.201 \
--single-host-defaults \
--initial-dashboard-password=Oldboy123.com \
--dashboard-password-noupdate \
--allow-fqdn-hostname \
--skip-pull
Ceph Dashboard is now available at:
URL: https://Ceph-201:8443/
User: admin
Password: Oldboy123.com
'单节点优化模式已生效'
3)查看默认 CRUSH 规则(故障域已是 osd 级别)
root@Ceph-201 ~# ceph osd crush rule dump replicated_rule
# dump后紧跟的是默认的规则名
{
"rule_id": 0, ✅️ 这个0也能说明它是默认的规则
"rule_name": "replicated_rule",
"type": 1,
"steps": [
{ "op": "take", "item": -1, "item_name": "default" },
{ "op": "choose_firstn", "num": 0, "type": "osd" }, <-- ✅️已经是 osd 级别
{ "op": "emit" }
]
}
4)逐个添加 OSD(也可逐个指定磁盘)
root@Ceph-201 ~# ceph orch daemon add osd Ceph-201:/dev/sdb
Created osd(s) 0 on host 'Ceph-201'
root@Ceph-201 ~# ceph orch daemon add osd Ceph-201:/dev/sdc
Created osd(s) 1 on host 'Ceph-201'
root@Ceph-201 ~# ceph orch daemon add osd Ceph-201:/dev/sdd
Created osd(s) 2 on host 'Ceph-201'
root@Ceph-201 ~# ceph -s
cluster:
id: 3ca027a7-5400-11f1-a4e3-000c2990a57e
health: HEALTH_OK ✅️
services:
mon: 1 daemons, quorum Ceph-201 (age 49m) [leader: Ceph-201]
mgr: Ceph-201.ylifrh(active, since 47m), standbys: Ceph-201.eukksl
# 部署了两个 mgr
'一台机器上跑了两个 MGR 守护进程 ——> 一个 active,一个 standby'
osd: 3 osds: 3 up (since 39m), 3 in (since 39m)
5)验证最终状态
root@Ceph-201 ~# ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 1.78130 root default
-3 1.78130 host Ceph-201
0 hdd 0.29300 osd.0 up 1.00000 1.00000
1 hdd 0.48830 osd.1 up 1.00000 1.00000
2 hdd 1.00000 osd.2 up 1.00000 1.00000
root@Ceph-201 ~# ceph osd pool ls detail
pool 1 '.mgr' replicated size 2 min_size 1 crush_rule 0 ...
'副本数size 2, min_size 1' # --single-host-defaults 的效果

💡 推荐:实验/学习环境用 --single-host-defaults,生产环境严格多节点部署

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

相关文章智能推荐
1
K8s故障排查 & 控制器与Service实战
Kubernetes故障排查三板斧describe/logs/exec与command&args,容器三种状态与pause基础架构容器,env环境变量部署WordPress,Deployment副本控制与滚动更新回滚,Service四类型ClusterIP/NodePort/LoadBalancer/ExternalName,kube-proxy+iptables底层实现,名称空间,CoreDNS服务发现与跨ns解析,deploy+svc部署WordPress及跨名称空间连库实战
2
K8s开篇 & kubeadm集群部署实战
KubernetesK8s核心概念与架构详解,基于kubeadm从零部署高可用集群,Flannel网络配置,Pod基础使用与YAML声明式管理
3
Prometheus 告警 && etcd 集群实战
Prometheus监控Alertmanager 告警路由/模板/静默/抑制 + 钉钉插件,etcd 3.7 TLS 高可用集群部署/备份恢复/Prometheus 监控,复用既有 kpyun CA 体系
4
Prometheus存储实战 && HTTPS认证 && 黑盒监控
Prometheus监控VictoriaMetrics单机部署+remote_write远端存储,Prometheus启用HTTPS+Basic Auth认证,node-exporter黑白名单,标签管理(relabel/metric_relabel),blackbox-exporter HTTP/ICMP/TCP黑盒探测,Grafana存储迁移到MySQL
5
Prometheus自定义监控 && 服务发现 && 联邦模式
Prometheus监控部署 pushgateway 实现短期任务/自定义指标的推送式监控(API 推送删除、honor_labels、TCP 12 状态、丢包率脚本),用 Go + client_golang 开发自定义 exporter(静态编译零依赖),落地 file_sd 与 consul 服务发现(consul 2.0.3 集群 + consul_exporter),最后用 3 台 Prometheus server 搭建联邦模式实现分布式采集汇总
Profile Image of the Author
久棹
不是先学好了再干,而是先干起来再学习,干中学!
分类
站点统计
文章
115
分类
15
标签
272
总字数
306,562
运行时长
0 天
最后活动
0 天前
文章目录