离线部署Ceph Reef版做RBD,这事儿我前后折腾了大半个月。说句实话,难点根本不在Ceph本身,而在“离线”这两个字。生产环境断外网是常态,尤其数据机房、内网项目,你没法指望在一台能上外网的机器上随便pull镜像、装依赖。一旦源没备齐、镜像版本没对上、时间忘了同步,后面每一步都是连环坑。
这篇文章就是我这次从零部署Ceph 18.2.4(Reef)并交付RBD块设备的完整记录,写给所有要在隔离网络里搞Ceph的人。你可能是运维、虚拟化工程师,也可能只是自己搭个测试集群,只要目标环境没有外网,这篇就值得你花十分钟从头看到尾,尤其是第2节准备工作,我敢说80%的人第一遍都会栽在那里。
1. 离线部署的整体思路:先搞清楚“离线”到底断在哪
1.1 三种离线程度的判断
我接手这个项目时,第一件事不是装包,而是确认现场的网络边界到底什么样。离线这个词太笼统了,至少分三种情况,处理方式完全不同:
- 完全隔离:目标机房不通外网,连DNS解析外网域名都做不到,所有软件包、容器镜像、文档都必须提前备好带进去。
- 内网有镜像源:机房虽然没外网,但内部有一台软件源服务器(比如已同步的OS镜像站、内部Artifactory),这种情况下Ceph软件包可以直接指向内网源,但容器镜像可能还是需要手动导入。
- 外网受限:能做HTTP代理访问部分域名,但拉取容器镜像仍然不可靠。这种反而最麻烦,因为你会抱着“试试看”的心态浪费时间。
我这次遇到的是第一种,完全隔离。确定了这一点,后面所有策略都围绕“一次性带够所有需要的物料”来展开。这一步绝对不能省,我见过有人连环境都没看就按在线部署流程跑,结果卡在拉取镜像上整整两天。
1.2 为什么选择cephadm而不是ceph-ansible
Ceph部署工具目前主流有两套:cephadm(Ceph官方推荐,基于容器)和ceph-ansible(基于传统软件包)。我直接选了cephadm,核心原因有三个:
第一,Reef这个版本(18.x系列)已经把ceph-ansible生命周期维护降到了很低的优先级,官方文档里主推的就是cephadm。你用ceph-ansible去部署18.x,很多新特性默认配置都接不上,纯给自己找活干。
第二,cephadm把整个集群组件(mon、mgr、osd等)都容器化了,版本升级、服务重启都统一走容器管理。这对离线环境反而是个优势——你只要搞定了一个容器镜像,所有节点都用同一个镜像在跑,管理逻辑非常干净。
第三,cephadm bootstrap只需要一个root或sudo权限的SSH环境,不用预先把所有包装到每个节点上。它会通过SSH把容器镜像分发下去,省掉很多手工操作。
有人可能会说Rook也支持Ceph,但Rook是Kubernetes原生的方案,如果你没有K8s底座,就没必要为了Ceph再拉一套K8s集群。RBD本身就是一个通用的块存储协议,不依赖K8s也能活得很好。
1.3 最终架构和网络规划
我这次的目标集群是3个节点,每个节点既跑MON也跑OSD(生产环境建议MON单独部署,但测试和中小型项目这么干完全够用)。节点角色规划:
| 节点 | 角色 | 系统 | 数据盘 |
|---|---|---|---|
| node1 | mon + mgr + osd | CentOS Stream 9 | 2块 1TB SSD |
| node2 | mon + osd | CentOS Stream 9 | 2块 1TB SSD |
| node3 | mon + osd | CentOS Stream 9 | 2块 1TB SSD |
网络方面需要注意两点:一是节点间内网要通,二是如果你有单独的集群公共网络,一定要规划好。Ceph集群内部通信对延迟敏感,管理网和数据网最好分离开,否则大流量OSD回填的时候,SSH都可能掉线。我这次条件有限,管理网和数据网共用了一个交换机,虽然能用,但回填期间其他节点操作明显卡顿,能用和好用是两回事。
2. 离线环境准备:源、镜像、时间,一个都不能少
2.1 软件仓库准备(RPM/DEB)
离线部署Ceph,第一步是解决软件包装哪来的问题。Ceph的官方命名对应关系是:每个大版本对应一个主版本号,Reef对应18.2.x系列,发行包里会包含cephadm、ceph-common、librados等核心组件。
我在一台能上外网的Ansible中控机上执行了仓库同步。CentOS Stream 9下,直接同步Ceph官方EL9源到本地目录,然后生成repo文件:
# 在有外网的机器上同步ceph源(这里是el9版本,arm64或x86_64注意架构) mkdir -p /data/ceph-repo/$basearch dnf reposync --repoid=ceph-el9 --download-metadata --destdir=/data/ceph-repo/ # 在目标机器上配置本地repo cat > /etc/yum.repos.d/ceph-local.repo <<EOF [ceph-local] name=Ceph Local Repo baseurl=file:///data/ceph-repo/x86_64 gpgcheck=0 enabled=1 EOF yum clean all yum makecache如果你现场连内网源服务器都没有,那就把整个/data/ceph-repo目录打包,拷到每个节点上解压。这里要特别注意一件事:Ceph依赖的第三方包非常多,包括boost、fmt、python3等,在整个OS原厂源里。你在外网同步时,光同步Ceph自己的仓库是不够的,最好把系统的基础AppStream和BaseOS源也同步一份到内网,否则到了现场一执行yum install cephadm直接报依赖缺失,那才叫欲哭无泪。
Ubuntu/Debian系操作类似,用apt-mirror或dpkg-scanpackages生成Packages索引,架构上也分amd64/arm64,不再赘述。
2.2 容器镜像的准备:每个组件都在容器里跑
Cephadm和传统部署最大的区别在于,它把mon、mgr、osd全部装进容器。所以除了rpm包,你还要准备一个关键物料:Ceph Reeft容器镜像。官方默认镜像地址是quay.io,离线环境下载直接失败。
我在外网机器上预先拉好镜像并导出,然后打成tar包带到现场:
# 在外网机器上 podman pull quay.io/ceph/ceph:v18.2.4 # 导出镜像 podman save -o ceph-v18.2.4.tar quay.io/ceph/ceph:v18.2.4 # 打包相关人员(镜像tar本身约1.5GB,用外网下载后压缩传输) tar -czf ceph-img.tar.gz ceph-v18.2.4.tar到了现场,每台节点先加载镜像(或者只加载到bootstrap节点,后续cephadm会把镜像分发到其他节点):
podman load -i ceph-v18.2.4.tar # 确认镜像已加载 podman images | grep ceph这里有个大坑:镜像版本必须和你要部署的Ceph版本严格一致。cephadm的很多内部命令和服务管理逻辑与镜像版本绑定,你要是bootstrap的时候指定了v18.2.4,后面节点上却加载了其他版本的镜像,轻则告警,重则服务起不来。建议用标签锁定版本,避免用latest这种模糊写法。
如果你现场有多套环境,更优雅的方式是搭一个内网Registry,把镜像push到内网仓库,然后cephadm通过--image参数指向内网地址。一个简单的做法是拿另外一台机器跑个官方Registry容器,然后cephadm直接指定registry.internal/ceph/ceph:v18.2.4。好处是后续扩容节点时不用每台都手动load,遇到横向扩展的场景省事很多。
2.3 主机初始化:时间同步、主机名、SSH免密、磁盘清理
这一步看起来基础,却是离线环境最容易反复出问题的环节。我把每台节点在部署前都过了一遍这套动作:
- 时间同步:Ceph对mon和osd节点间的时钟偏差极其敏感,默认超过0.05秒就会不停报clock skew告警。离线环境没外网NTP可用,最稳妥的方式是挑一台节点作内网NTP服务器,其他节点指向它。我用chrony手动配置:
# 时间服务器节点 cat > /etc/chrony.conf <<EOF server 127.127.1.0 iburst local stratum 10 allow all EOF systemctl restart chronyd # 其他节点 cat > /etc/chrony.conf <<EOF server node1 iburst EOF systemctl restart chronyd chronyc sources -v要注意allow all只适用于内网可信环境,如果节点跨了不可信网段,务必写死允许的网段,否则也是隐患。
主机名和/etc/hosts:每台节点的主机名最好规范化,然后所有节点的/etc/hosts里都添加全部节点的主机名映射。Ceph集群内通信极度依赖主机名解析,你要是漏了某条记录,cephadm ssh免密或OSD启动时就直接卡住。
SSH免密:cephadm bootstrap所在节点需要能免密SSH登录到所有其他节点。这个直接生成密钥然后分发:
ssh-keygen -t rsa -b 4096 -f /root/.ssh/id_rsa -N '' for host in node1 node2 node3; do ssh-copy-id -i /root/.ssh/id_rsa.pub $host done- 磁盘清理:这次每台节点的2块SSD之前都有分区和旧文件系统。Ceph OSD接管磁盘时会要求磁盘无文件系统残留,否则会报
device is in use。提前用wipefs清理:
wipefs -a /dev/sdb wipefs -a /dev/sdc清理命令执行后最好重启一下节点,让内核的块设备状态完全刷新。这一步跳过的话,后面添加OSD时非常容易抽风。
2.4 首节点bootstrap:跳过可选的监控栈
物料备齐后,开始部署第一个节点。在bootstrap节点上执行:
# 注意--skip-monitoring-stack跳过prometheus/grafana,离线环境省掉一大堆事 # --skip-prepare-host跳过安装系统依赖 # --image指向本地已加载的镜像 cephadm bootstrap \ --mon-ip 192.168.10.10 \ --ssh-user root \ --image 127.0.0.1:5000/ceph/ceph:v18.2.4 \ --skip-monitoring-stack \ --skip-prepare-host或者,如果你镜像不是通过内网Registry而是直接在每台节点load的,那直接把--image换成镜像名quay.io/ceph/ceph:v18.2.4也行(前提是镜像已经load进podman本地存储)。这里给几个参数的解释:
--skip-monitoring-stack:这个我强烈建议,除非你要上Grafana看清监控面板,否则离线环境部署Prometheus/Grafana/Alertmanager容器纯属自虐。等集群稳定后需要的监控手段可以通过别的方式补。--skip-prepare-host:跳过cephadm试图通过yum安装podman、chrony等基础包的步骤。离线环境如果这些包没在源里,这个步骤会报错,直接跳过再手工装反而是省心方案。--mon-ip:指定第一个mon的IP地址,必须确保这个IP是其他节点能访问到的。
bootstrap结束后的输出里会有一段命令行的提示,包括dashboard访问地址、admin密钥等。这些信息先保存好。随后看到Ceph Dashboard is now available就说明bootstrap成功了一半。
3. 集群配置:从bootstrap到OSD就绪
3.1 检查bootstrap结果和集群状态
bootstrap结束后,先确认Ceph集群的初始状态:
ceph -s正常情况下你会看到一个health: HEALTH_WARN的集群,因为现在还没有任何OSD。只要没有报MON_DOWN这样的严重错误,就可以继续。
下一步是把另外两个节点加入集群。cephadm会自动通过SSH在节点上创建mon/mgr等守护进程。但在此之前,更合理的做法是先想好OSD的设计。
3.2 磁盘规划与OSD添加
我这次每台节点2块盘,总共6块SSD,副本数默认3副本。添加OSD的方式推荐直接用ceph orch apply,让编排器自己来管理盘。
首先查看节点上是否有磁盘可以被Ceph识别:
ceph orch device ls如果没有列出预期磁盘,通常是因为磁盘上有分区或者LVM残留。这时需要:
# 针对每台节点的sdX盘做zap操作,相当于彻底的磁盘清理 ceph orch device zap node1 /dev/sdb --force ceph orch device zap node1 /dev/sdc --force # node2 / node3 同理然后直接让ceph编排OSD覆盖所有可用盘:
ceph orch apply osd --all-available-devices这里要事先想清楚一个问题:如果磁盘本身是混闪设备或不同用途,--all-available-devices可能会把系统盘之外的乱七八糟设备也纳入。稳妥的做法是先用ceph orch device ls确认所有被识别的盘,再写一个OSD spec文件,把数据盘的角色限定清楚。
等OSD全部起来后,看集群状态:
ceph osd tree ceph -s正常情况下会出现6个osd,并且health: HEALTH_OK。如果出现PG_AVAILABILITY或OSD_UP告警,按第5节的方法排查。
3.3 副本数与CRUSH规则
RBD场景默认数据副本数建议为3,这也是Ceph的默认值。如果OSD数量不够(比如你只有2台节点3块盘),可以先改成2副本:
ceph osd pool create rbd 128 128 # 等待PG创建完成这里有个实操经验:Ceph的副本数是池级别的设置,不是全局的。创建RBD池前就要想好这个池是双副本还是三副本。如果是三副本,6块ODS勉强支撑;如果后续osd故障需要降级,三副本会更稳健。但双副本在空间利用率和性能上都明显更好,适合对数据冗余要求稍低的场景。我在这个项目里用的是默认三副本。
4. RBD服务的配置与客户端对接
4.1 创建RBD池并初始化
Ceph中,RBD的数据存放在一个独立的池中。默认池名为rbd,虽然可以自定义,但建议遵循社区惯例:
ceph osd pool create rbd 128 # 初始化RBD池,这是一个非常容易漏掉的步骤 rbd pool init rbdrbd pool init会在池内创建一些RBD元数据对象,漏掉这一步,后续创建镜像时会直接报错pool rbd was not initialized。这个错我遇到过不止一次,每次都是同一件事:忘了初始化。
PG数量的选择逻辑:RBD池的PG数量直接影响集群的性能和稳定性。已知6个OSD、3副本的情况下,总PG数建议按公式(OSD数 * 100 / 副本数)估算,即6*100/3=200,然后取最接近的2的幂次,所以128比较稳妥。PG太少会导致单个PG内数据过多,性能不均衡;太多则会让osd维护开销增大。中小规模环境128是一个保守但可靠的选择。
4.2 创建RBD镜像并裁剪特性
池创建完毕,再创建块设备镜像:
# 创建10GB的测试镜像 rbd create rbd/demo-image --size 10240新创建的RBD镜像默认会启用很多现代特性,例如object-map、fast-diff、deep-flatten。这些特性在某些老版本内核模块中并不支持,手动映射时会报Operation not supported。所以我的习惯是一上来就裁剪掉它们:
rbd feature disable rbd/demo-image object-map fast-diff deep-flatten只保留最基础的layering特性(一般默认就会保留),这个是内核rbd模块最少依赖的特性,兼容性最好。
4.3 客户端离线环境的安装与密钥下载
RBD的客户端安装其实很简单,本质就是装一个ceph-common包。但离线环境里,你要做两件事:
- 把包含ceph-common的软件包拷贝到客户端机器上,并配置好仓库(同2.1)。
- 从集群导出客户端需要的配置和密钥:
# 在bootstrap节点上 ceph config get mon host >> ceph.conf # 或者直接拷贝bootstrap生成的配置 cp /etc/ceph/ceph.conf . # 创建rbd客户端认证权限 ceph auth get-or-create client.rbd mon 'profile rbd' osd 'profile rbd pool=rbd' -o ceph.client.rbd.keyring这里解释一下权限字符串:mon 'profile rbd'表示MON权限使用rbd预设角色,osd 'profile rbd pool=rbd'表示OSD权限限定在rbd池,这是最小权限原则,比直接给全权osd allow *要安全得多。
然后把ceph.conf和ceph.client.rbd.keyring拷到客户端机器的/etc/ceph/目录下。客户端机器上不用装完整的Ceph软件包,只需要ceph-common提供的rbd命令行工具。
4.4 RBD设备映射、格式化和挂载
客户端一切都准备好后,开始实际使用RBD:
# 检查是否能列出来 rbd ls rbd # 映射rbd镜像到内核块设备 rbd device map rbd/demo-image # 成功后会出现一个/dev/rbd0设备 ls /dev/rbd0 # 格式化 mkfs.xfs /dev/rbd0 # 挂载 mount /dev/rbd0 /mnt/test如果你碰到rbd device map报错说内核不支持某些feature,回到4.2把那些特性禁用掉就行。如果内核rbd模块本身没加载,执行modprobe rbd。
要是内核版本实在很旧装不了新驱动,Ceph还提供了用户态的rbd-nbd方案:
rbd device map --device-type nbd rbd/demo-image这个不需要内核rbd模块,兼容性更好,代价是性能和稳定性略逊内核方案。生产上用内核方案优先。
客户端要开机自动挂载的话,需要在/etc/fstab里写一条rbd的特殊记录,但更推荐的方式是由上层虚拟化平台(比如某虚拟机管理平台)通过librbd直接对接,而不是依赖操作系统层的设备映射。RBD在虚拟化场景下最经典的做法是作为QEMU/KVM的后端存储,由hypervisor直接管理块设备,省掉内核映射这一层。
5. 踩坑实录与排查技巧
5.1 时钟偏差:集群健康的隐形杀手
部署完集群后,最容易被忽视但影响最大的问题就是时钟偏差。离线环境没有NTP源,即使配了内网chrony,有时候也会因为防火墙或配置问题没有真正生效。
现象是ceph -s里出现HEALTH_WARN,点开一看写着:
clock skew detected on mon.node2, mon.node3这时候不需要怀疑Ceph本身,先去各节点检查:
chronyc tracking chronyc sources -v如果发现某台节点的时钟和bootstrap节点差了很多,直接手动校准:
# 用ntpdate对时,或者用chronyc makestep chronyc makestep然后重启所有相关Ceph守护进程。这台机器上的mon/mgr/osd容器全部重启一遍,Ceph会对新时间做校正。
我的经验是:离线环境一定要在用cephadm bootstrap之前就把时间调到一致,不要指望集群启起来后自己去同步。Ceph内部对时间偏差的容忍度很低,越早处理,越少后续的莫名其妙问题。
5.2 OSD启动失败:多半是磁盘问题
这次部署里唯一一次真正的故障出现在添加OSD时。ceph orch apply osd --all-available-devices执行后,有两个OSD一直起不来,卡在osd.N down状态。
排查思路是按顺序来:
- 先看osd日志:
cephadm logs,如果是bluestore mount failed或device busy,说明磁盘状态不对。 - 查看设备列表:
ceph orch device ls,能看到哪些磁盘被Ceph标记为unavailable、哪些是rejected。 - 检查磁盘分区残留:用
lsblk和blkid看磁盘上是否残留LVM元数据。
最终定位原因:那两块磁盘之前做过LVM,虽然wipefs清了分区表,但LVM元数据没有清干净,Bluestore拒绝接管。解决办法:
# 彻底清理LVM元数据 pvcreate -ff /dev/sdb # 或者直接创建成lvm然后删除 lvremove /dev/... vgremove ...清干净之后,再次执行:
ceph orch device zap <node> /dev/sdb --force ceph orch daemon restart osd.N就能正常起来了。这里要记住一点:wipefs -a并不保证清理LVM元数据,它主要清的是分区表。对Ceph来说,磁盘必须完全白纸一张,最稳妥的方式是直接把系统盘以外所有盘做成空pv再删除掉,确保LVM卷组信息不残留。
5.3 RBD映射时的“Operation not supported”
这可能是RBD使用过程中最常见的报错之一。执行rbd device map时,命令行提示:
rbd: sysfs write failed RBD: image not found或者:
rbd: map failed: (95) Operation not supported95号错误基本就是特性问题,解决方式就是4.2里的rbd feature disable。如果是在虚拟化平台里用的,也要检查一下这个平台使用的librbd/rbd-NG版本是否支持这些特性。
另一个原因可能是权限不足,也就是client.rbd没有正确配置osd 'profile rbd pool=rbd'。用:
ceph auth get client.rbd查看keyring里的权限是否生效。如果没有权限,你会看到rbd ls rbd都能正常列出(因为有mon权限),但map时OSD层报权限拒绝。
5.4 客户端离线安装ceph-common缺依赖
有一次我在客户端机器上yum install ceph-common时,安装直接报错,提示缺少librados.so.2()。这个崩溃瞬间就能把离线部署的人搞疯。
原因很简单:ceph-common的依赖不全,你只同步了Ceph仓库但没同步系统基础仓库里的依赖包。解决办法是预先在第2节的仓库同步阶段就把OS基础的AppStream和BaseOS全部打包拖进内网,然后配置好基础repo源:
cat > /etc/yum.repos.d/local-base.repo <<EOF [local-base] name=BaseOS baseurl=file:///data/packages/BaseOS gpgcheck=0 enabled=1 EOF离线环境里,我建议你在olly准备阶段就打包这三个仓库:BaseOS、AppStream、Ceph相关源。三者缺一不可。这个坑的本质是:装客户端不是只装Ceph那一个rpm,它依赖系统库的一百多个包,缺一个就装不上。
结语:离线部署的最终心得
我做完这个项目最深的体会是,离线部署Ceph和在线完全不是一个难度等级。在线环境你跟着官方文档走,几乎不会遇到依赖问题;离线环境的所有坑都集中在“物料准备”这个阶段。
- 软件包:不只是Ceph仓库,系统基础源、第三方依赖源都要齐
- 容器镜像:版本锁死,别用latest,能导入内网Registry最好
- 时间同步:一定要在bootstrap之前搞定
- 客户端:别忘记ceph-common的依赖同样来自系统源
- RBD特性:新镜像创建后记得裁剪object-map等特性,否则内核模块分分钟教你做人
还有一个容易被忽略的小建议:写一份部署前确认清单,列明所有物料和版本,逐项打勾。尤其是离线这种操作,你没法临时上网查错,所有工具链都靠自己预先构思,清单越细,现场踩坑概率越低。
Ceph的RBD方案在离线环境里完全可行,它足够成熟,也足够稳定。只要把准备工作做足,你就能在一个完全隔离的网络里跑起一套好用的分布式块存储系统。