简介:这份PDF文档面向具备一定存储架构经验的云服务管理人员及开源分布式存储爱好者,系统讲解Ceph块存储的部署与应用。内容以三节点实验集群为背景,在Ubuntu 18.04环境下完成RBD池创建、块设备镜像管理、镜像映射至Linux块设备、格式化挂载及集群健康检查等完整流程,并给出具体命令示范,帮助读者掌握搭建稳定Ceph集群的能力,为虚拟化环境提供高效块存储方案。资源包共1个PDF文件,大小约286KB,内容紧凑、步骤清晰,适合按章节对照实操。目前已有70人学习。读者可从中获得从集群规划、存储池与镜像操作到映射读写、状态监控的完整操作链路,并理解基础部署方式与后续参数调整、高级特性研究的衔接思路,适合作为Ceph块存储入门的实战参考。
1. CEPH 块存储到底解决什么问题:从三副本到 RBD 的落地判断
很多团队第一次接触 CEPH,都是被“统一分布式存储”这句话吸引进来的:一套集群同时提供块、文件、对象三种接口,看起来能把机房里的存储孤岛一次性收编。但真正落地时,绝大多数业务只需要其中一种——块存储。虚拟机要盘、数据库要盘、K8s 的 PVC 要盘,这些场景要的是 RBD(RADOS Block Device),而不是 CEPHFS 或 RGW。所以这篇实战指南只聚焦一件事:把 CEPH 的块存储从零部署起来,接到真实业务上,并且知道它在什么边界内可靠、什么情况下会翻车。
CEPH 块存储的核心价值在于:数据以固定大小对象的形式打散到整个集群,通过 CRUSH 算法决定落盘位置,靠多副本或纠删码保证冗余,靠 PG(Placement Group)做归置单元。你不需要 RAID 卡,不需要双控阵列,一台普通 x86 服务器加几块盘就能组成一个可横向扩展的存储池。代价是:网络要求高、调优参数多、故障域规划不好会埋雷。适合有 3 台以上同构服务器、能接受运维复杂度的团队;如果只有两台机器或者对延迟极度敏感的交易库,我一般会劝退,直接上本地 NVMe 或传统阵列更省心。
2. 部署前的硬件与拓扑决策:别让第一块盘就选错
2.1 节点角色与最小规模
CEPH 集群里节点分三类角色:MON(Monitor,维护集群地图)、MGR(Manager,提供监控和管理接口)、OSD(Object Storage Daemon,真正存数据的进程)。生产环境最小可用规模是 3 台物理机,每台同时跑 MON + MGR + OSD。为什么是 3 台?因为 MON 需要多数派仲裁,3 个 MON 允许挂 1 个,2 个 MON 挂 1 个就整个集群只读。少于 3 台不是不能跑,而是没有容错余量,只适合实验室。
网络方面,我强烈建议至少两张网卡:一张 public network 跑客户端和 MON/MGR 通信,一张 cluster network 跑 OSD 之间的数据复制。如果只有一张网,复制流量和业务流量抢带宽,延迟抖动会非常明显。万兆起步,25G 更好。千兆网跑 CEPH 块存储,在并发写入场景下基本等于自残。
2.2 磁盘选型:HDD、SSD 还是 NVMe
块存储对 IOPS 敏感,尤其是数据库和虚拟机场景。常见做法是:OSD 数据盘用 SSD 或 NVMe,WAL/DB 单独放在更快的 NVMe 上。如果预算有限,可以用 HDD 做容量池、SSD 做缓存池,但不要指望 HDD 池能扛住随机写。
| 盘类型 | 适用场景 | 单 OSD 建议 | 备注 |
|---|---|---|---|
| HDD 7200转 | 冷数据、备份、大容量块 | 4TB~16TB | 随机 IOPS 低,必须配 SSD 做 DB |
| SATA SSD | 通用虚拟机、中等负载 | 1TB~4TB | 性价比高,注意 DWPD |
| NVMe | 数据库、高并发块存储 | 1TB~8TB | 延迟低,但要注意散热和 PCIe 通道 |
注意:不要用 RAID 卡把多块盘做成 RAID0 再给 CEPH,CEPH 自己管副本,RAID 只会增加故障域和写放大。直通模式(HBA/JBOD)才是正确姿势。
2.3 操作系统与基础环境准备
我一般用 Ubuntu 22.04 LTS 或 CentOS Stream 9。部署前每台机器要做的事:设置主机名、配置 hosts 解析、关闭 swap、调整内核参数、同步时间。下面是一段可复用的初始化脚本,在每台节点上执行。
# 设置主机名,按节点角色命名,例如 ceph-node1 hostnamectl set-hostname ceph-node1 # 写入 hosts,三台互相解析 cat >> /etc/hosts <<'EOF' 192.168.10.11 ceph-node1 192.168.10.12 ceph-node2 192.168.10.13 ceph-node3 EOF # 关闭 swap,CEPH OSD 对内存延迟敏感 swapoff -a sed -i '/swap/s/^/#/' /etc/fstab # 调整内核参数:增大文件句柄和网络缓冲区 cat >> /etc/sysctl.conf <<'EOF' fs.file-max = 1048576 net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 net.ipv4.tcp_rmem = 4096 87380 16777216 net.ipv4.tcp_wmem = 4096 65536 16777216 vm.swappiness = 0 EOF sysctl -p # 时间同步,CEPH 对时钟偏移敏感 apt install -y chrony systemctl enable --now chrony这段脚本做了四件事:主机名和 hosts 保证节点间能按名字通信;关闭 swap 避免 OSD 进程被换出导致心跳超时;内核参数提升网络吞吐和文件句柄上限;chrony 保证 MON 仲裁不受时钟漂移影响。参数里vm.swappiness=0是血泪经验,默认值 60 会让 OSD 在内存压力下频繁换页,表现为集群间歇性卡顿。
3. 用 cephadm 部署集群:从引导到 OSD 上线
3.1 安装 cephadm 与引导第一个 MON
从 Nautilus 之后,官方主推 cephadm 部署方式,基于容器运行所有守护进程。相比老旧的 ceph-deploy,cephadm 的升级、扩缩容、证书管理都更顺。下面在第一台节点上操作。
# 安装 cephadm,以 Ubuntu 22.04 为例 apt update apt install -y cephadm # 引导集群,指定第一台 MON 的 IP 和网段 cephadm bootstrap \ --mon-ip 192.168.10.11 \ --initial-dashboard-user admin \ --initial-dashboard-password Ceph@2024 \ --dashboard-password-noupdate # 引导完成后会输出 dashboard 地址和 ceph 命令的使用方式 # 把 admin 密钥拷贝出来,后续节点需要 ceph config generate-minimal-conf > /etc/ceph/ceph.conf--mon-ip必须是第一台节点的固定 IP,不能写 127.0.0.1。--initial-dashboard-password设置 Web 控制台密码,生产环境务必改掉默认值。引导成功后,当前节点会自动跑起一个 MON 和一个 MGR。用ceph -s能看到集群状态,此时 HEALTH 会提示MON_DISK_LOW或OSD_COUNT之类的告警,属于正常,因为还没加 OSD。
3.2 把其他节点加入集群
在第二、第三台节点上安装 cephadm,然后回到第一台执行加入命令。cephadm 通过 SSH 分发公钥和配置。
# 在第一台节点上,把公钥推给其他节点 ssh-copy-id root@ceph-node2 ssh-copy-id root@ceph-node3 # 添加节点到集群 ceph orch host add ceph-node2 192.168.10.12 ceph orch host add ceph-node3 192.168.10.13 # 给节点打标签,方便按角色调度 ceph orch host label add ceph-node1 mon,mgr,osd ceph orch host label add ceph-node2 mon,mgr,osd ceph orch host label add ceph-node3 mon,mgr,osd # 查看节点列表 ceph orch host ls加入节点后,cephadm 会自动在新节点上部署 MON 和 MGR(如果标签匹配)。用ceph orch ps可以看到所有守护进程状态。如果某个节点一直显示offline,先检查 SSH 是否免密、防火墙是否放行 6789/3300/6800-7300 端口。
3.3 添加 OSD:让磁盘真正开始存数据
OSD 是 CEPH 的存储单元,一块盘对应一个 OSD。cephadm 支持自动发现可用磁盘并批量创建。
# 查看所有节点上可用的磁盘 ceph orch device ls # 自动创建 OSD,只使用未挂载、无分区的裸盘 ceph orch apply osd --all-available-devices # 或者手动指定某块盘创建 OSD ceph orch daemon add osd ceph-node1:/dev/sdb # 查看 OSD 树和状态 ceph osd tree ceph osd df--all-available-devices会扫描所有节点上满足条件的盘,自动创建 OSD。条件是:盘没有被挂载、没有分区、没有文件系统。如果你有系统盘和数据盘混在一起,务必先确认盘符,否则可能把系统盘吃掉。我一般会先lsblk人工核对一遍,再执行自动创建。ceph osd df能看到每个 OSD 的容量、使用率和 PG 分布,如果某个 OSD 使用率明显高于其他,说明 CRUSH 权重没调好。
3.4 创建块存储池与 RBD 镜像
OSD 上线后,默认会有一个rbd池,但生产环境我建议按业务单独建池,方便做配额和权限隔离。
# 创建三副本池,pg_num 根据 OSD 数量调整 ceph osd pool create k8s-pool 128 128 # 设置副本数为 3 ceph osd pool set k8s-pool size 3 ceph osd pool set k8s-pool min_size 2 # 启用 RBD 应用模式 ceph osd pool application enable k8s-pool rbd # 创建 RBD 镜像,大小 100G rbd create k8s-pool/vm-disk-01 --size 100G # 查看镜像信息 rbd info k8s-pool/vm-disk-01pg_num的设置有个经验公式:(OSD 总数 * 100) / 副本数,然后向上取到 2 的幂。比如 12 个 OSD、三副本,就是 400,取 512。PG 太少会导致数据分布不均,太多会增加 MON 内存开销。min_size 2表示至少两个副本在线才允许写入,避免脑裂时数据不一致。创建完镜像后,可以用rbd map映射成块设备,格式化后挂载使用。
4. 块存储接入业务:RBD 映射、K8s PVC 与性能验证
4.1 在物理机上映射 RBD 块设备
最直接的用法是把 RBD 镜像映射成本地块设备,然后格式化挂载。
# 映射镜像到本地,内核模块会自动加载 rbd map k8s-pool/vm-disk-01 # 查看映射结果,通常为 /dev/rbd0 rbd showmapped # 格式化并挂载 mkfs.xfs /dev/rbd0 mkdir -p /mnt/rbd-data mount /dev/rbd0 /mnt/rbd-data # 写入测试数据 dd if=/dev/zero of=/mnt/rbd-data/testfile bs=1M count=1024 oflag=directoflag=direct绕过页缓存,测的是真实落盘性能。如果顺序写只有几十 MB/s,先查网络是不是千兆,再查 OSD 是否都在同一块盘上。rbd map依赖内核 RBD 模块,如果报modprobe: module rbd not found,需要安装linux-modules-extra或对应内核包。
4.2 对接 Kubernetes:StorageClass 与 PVC
K8s 场景下,CEPH RBD 通过 CSI 驱动接入。常见做法是部署ceph-csi,然后创建 StorageClass。
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: ceph-rbd provisioner: rbd.csi.ceph.com parameters: clusterID: ceph-cluster pool: k8s-pool imageFeatures: layering csi.storage.k8s.io/provisioner-secret-name: ceph-secret csi.storage.k8s.io/provisioner-secret-namespace: ceph-csi csi.storage.k8s.io/node-stage-secret-name: ceph-secret csi.storage.k8s.io/node-stage-secret-namespace: ceph-csi reclaimPolicy: Delete allowVolumeExpansion: trueclusterID要和 ceph-csi 配置里的一致,pool填前面创建的池名。allowVolumeExpansion: true允许在线扩容 PVC,但底层 RBD 镜像扩容后还需要在 Pod 内扩展文件系统。创建 PVC 后,如果一直 Pending,先看 ceph-csi 的 provisioner pod 日志,常见原因是 secret 里的 key 权限不对,或者 pool 没有启用 rbd 应用。
4.3 用 fio 验证块存储真实性能
部署完不测性能,等于没部署。我一般用 fio 做三组测试:4K 随机写、4K 随机读、1M 顺序写。
# 4K 随机写,模拟数据库负载 fio --name=randwrite --ioengine=libaio --direct=1 \ --bs=4k --size=2G --numjobs=4 --rw=randwrite \ --runtime=60 --group_reporting --filename=/mnt/rbd-data/fio-test # 4K 随机读 fio --name=randread --ioengine=libaio --direct=1 \ --bs=4k --size=2G --numjobs=4 --rw=randread \ --runtime=60 --group_reporting --filename=/mnt/rbd-data/fio-test # 1M 顺序写 fio --name=seqwrite --ioengine=libaio --direct=1 \ --bs=1M --size=4G --numjobs=1 --rw=write \ --runtime=60 --group_reporting --filename=/mnt/rbd-data/fio-test重点看iops和lat(延迟)。三副本 SSD 池,4K 随机写通常能到几千到上万 IOPS,延迟在几毫秒以内。如果 IOPS 只有几百,检查numjobs是否太小、网络是否丢包、OSD 是否用了 HDD。--direct=1必须加,否则测的是缓存。测试完记得删除测试文件,避免占满池。
5. 避坑与排查:CEPH 块存储最常见的五个翻车现场
5.1 HEALTH_ERR: PG 一直 active+undersized+degraded
现象:ceph -s显示 PG 状态异常,写入变慢甚至阻塞。原因:某个 OSD 掉线,副本数不足,PG 处于降级状态。如果min_size设成 2,而只剩 1 个副本,写入会被拒绝。解决:先ceph osd tree找到 down 的 OSD,检查磁盘是否故障、进程是否崩溃。如果是临时重启,等 OSD 重新上线后 PG 会自动恢复。如果磁盘彻底坏了,用ceph osd out <id>把它踢出集群,等数据回填完再更换磁盘。
5.2 OSD 创建后使用率严重不均
现象:ceph osd df里某些 OSD 使用率 80%,另一些只有 20%。原因:CRUSH 权重默认按磁盘容量算,但如果盘的实际可用空间和标称差距大,或者 PG 数太少,分布就会倾斜。解决:先确认pg_num是否足够,按公式重新计算并调整。如果 PG 数没问题,用ceph osd reweight手动微调权重,把高使用率的 OSD 权重调低。调整后数据会重新平衡,但这个过程会占用网络带宽,建议在业务低峰期做。
5.3 RBD 映射后写入速度极慢
现象:dd测试只有几十 MB/s,但网络和磁盘看起来都正常。原因:常见有三种——客户端没启用rbd cache、OSD 的journal和data在同一块慢盘上、网络走了千兆。解决:在ceph.conf的[client]段加rbd cache = true和rbd cache writethrough until flush = true。检查 OSD 是否把 DB/WAL 放在 NVMe 上,如果没有,考虑重建 OSD 并指定--data和--db设备。网络用iperf3实测带宽,低于 900Mbps 就换万兆。
5.4 MON 仲裁失败导致集群只读
现象:ceph -s卡住,提示monclient: hunting for new mon。原因:3 个 MON 挂了 2 个,或者 MON 之间网络不通、时钟偏移过大。解决:先恢复网络和时钟同步,然后逐个重启 MON 进程。如果 MON 数据损坏,需要用ceph-mon --extract-monmap从健康 MON 上恢复。预防措施:MON 节点不要和 OSD 混部在高负载机器上,时钟同步必须严格。
5.5 K8s PVC 扩容后 Pod 内空间没变
现象:PVC 改了大小,kubectl get pvc显示新容量,但 Pod 里df -h还是旧值。原因:CSI 只扩容了 RBD 镜像,文件系统没有扩展。解决:进入 Pod 执行resize2fs(ext4)或xfs_growfs(xfs)。如果是 xfs,必须挂载点在线才能扩。更省事的做法是在 StorageClass 里配置csi.storage.k8s.io/fstype: ext4,并确保 CSI 驱动支持在线扩容。
6. 进阶技巧:用 crush rule 把块存储池钉在指定故障域
集群规模上去之后,默认的 CRUSH 规则会把副本撒到所有 OSD 上。但块存储往往有冷热分层需求:数据库池要全 SSD,备份池可以混 HDD。这时候就要自定义 CRUSH rule,把池绑定到指定设备类。
# 给 SSD 和 HDD 分别打上设备类 ceph osd crush set-device-class ssd osd.0 osd.1 osd.2 ceph osd crush set-device-class hdd osd.3 osd.4 osd.5 # 创建针对 SSD 的 crush rule ceph osd crush rule create-replicated ssd-rule default host ssd # 把池应用到该规则 ceph osd pool set k8s-pool crush_rule ssd-rule # 验证池的 CRUSH 规则 ceph osd pool get k8s-pool crush_rulecreate-replicated的参数依次是规则名、根(default)、故障域类型(host)、设备类(ssd)。故障域选host表示同一主机的 OSD 不会同时持有同一 PG 的两个副本,这是生产环境的最低要求。如果机房有多排机架,可以把故障域提升到rack,但需要先定义 bucket 层级。
验证方法:用ceph osd upmap或ceph pg map <pgid>查看某个 PG 的副本落在哪些 OSD 上,确认都在 SSD 设备类里。如果发现副本跑到了 HDD,说明规则没生效,检查池是否真的绑定了ssd-rule,以及 OSD 的设备类是否打对。
我自己的习惯是:任何池创建后,先ceph osd pool get <pool> all把参数全部打印一遍,确认size、min_size、crush_rule、pg_num四个值符合预期,再接入业务。这个动作花不了一分钟,但能避免后面半夜被叫起来处理数据分布问题。希望帮到你。
本文还有配套的精品资源,点击获取