前阵子我帮朋友搭一套内部测试用的分布式存储,手头只有三台普通服务器,预算不多,时间也紧。如果按老办法把Ceph直接装在裸机上,光系统调优、包管理、版本兼容就能折腾一整天。后来我换了个思路,直接用Docker把整套Ceph集群容器化拉起来,从零到三节点集群跑起来,一共只花了半天。
这篇文章就是把那次实践完整复盘一遍。我尽量按我实际操作时的顺序写:从为什么选容器化、节点和磁盘怎么规划、编排文件怎么写、容器之间如何互相发现并组成高可用集群,到最后的故障演练和排错技巧。适合有点Linux和Docker基础、但没接触过Ceph的同学参考;如果你已经会用Ceph但想快速搭一套测试环境,也可以直接跳到第3节抄配置。
这里先说清楚一个核心观点:用Docker部署Ceph并不是要替代官方推荐的cephadm或裸机方案,而是提供一条低成本、可重现、易销毁的路径。尤其在实验、研发、预生产场景下,容器化带来的灵活性和可迁移性,远比手动装包划算。接下来我会按一条完整的主线,把从零搭建的每一步都拆开讲。
1. 为什么选Docker部署Ceph:先想清楚方案再动手
很多人一听到Ceph就头大,monitor、manager、OSD、MDS、RGW,一堆角色,还要考虑网络、磁盘、认证。其实它的核心思路不复杂:把多台机器的磁盘聚合成一个统一的存储池,对外提供块存储、文件存储和对象存储。难点不在概念,而在于把这么多组件从裸机搭起来并保持高可用。
1.1 Ceph集群的“家庭成员”都有谁
Ceph集群里常见的角色其实就几个:
- MON(Monitor):负责维护集群的元数据和状态,比如谁在、谁不在、哪些PG处于什么状态。集群至少要有奇数个,否则没法选主。
- MGR(Manager):负责集群的监控、资源平衡、Dashboard等功能。有了它,
ceph -s才更好看,也才有图形化界面可看。 - OSD(Object Storage Daemon):真正干活的角色,每一块数据盘对应一个OSD进程。它负责存储数据、处理复制和恢复。
- MDS(Metadata Server):只有在用CephFS文件系统时才需要,负责文件系统的目录、文件名等元数据。
- RGW(RADOS Gateway):提供S3兼容的对象存储接口,需要时可以单独起。
我最初接触Ceph时觉得这些角色塞在一起好乱,后来发现一个很形象的类比:MON是“议事会”,MGR是“管家”,OSD是“仓库管理员”,MDS是“图书管理员”,RGW是“对外快递站”。你把角色脑补成人,整个集群的分工就清晰了。
1.2 容器化部署的适用场景和不适用场景
容器化Ceph的优点,我实测下来最明显的是这几条:
- 部署速度快:镜像拉下来,容器起来,初始化命令一执行,集群就活了,不用纠结依赖和版本。
- 环境隔离好:每个角色一个容器,日志、配置、数据目录分开,排查问题时很舒服。
- 版本切换方便:想升级镜像就换tag,想测试新版就另起一套目录。
- 销毁重建容易:测试环境里弄坏了,直接删容器重建,不用重装系统。
但也要提醒你别踩我当年踩过的坑:容器化Ceph并不适合追求极致性能或超大规模的场景。性能敏感的话,容器网络和存储卷会带来额外开销。我见过有人硬要用Docker部署一套几十个节点的生产Ceph,结果容量和性能都很难调,最后只能全部迁移到裸机。所以我通常的建议是:实验环境、开发测试、边缘节点、临时交付,可以放心用容器化;核心生产环境,数据量特别大或者对IO路径非常敏感,还是优先考虑cephadm或裸机部署。
1.3 “高可用”到底是怎么高起来的
高可用不是靠某一个容器永远不死,而是靠“多个副本 + 自动选主”来实现。Ceph设计里,数据默认保存3个副本(production环境下常用3副本),分散在不同的服务器上。一台机器彻底挂了,其他两台的副本仍然完好,集群会通过Peering机制把缺失的副本重新补回来。
MON的高可用依赖于多数派投票。3个MON里只要有2个活着,集群就能正常对外服务;如果只剩1个,它就无法形成法定人数,整个集群会进入只读或拒绝服务的保护状态。所以节点数量最好选3或5,避免偶数节点导致投票陷入僵局。这条规则我后面做故障演练时会实际验证。
2. 部署前准备:硬件、系统与网络规划
动手之前把硬件和网络规划好,后面就能少走很多弯路。我这套方案的推荐节点数是3台,既能满足MON的多数派要求,也够放3份副本。如果只有单机,硬要跑起来也不是不行,但那就不是真正的高可用,只能当作演示。
2.1 节点角色与资源规划建议
我在三台机器上分别部署了完全相同的角色:一台机器上同时跑MON、MGR、OSD。这样三台机器互为冗余,谁挂了都不至于完全瘫痪。
资源规划可以参考下面这个表,实际是我这次用的配置:
| 节点 | CPU | 内存 | 系统盘 | 数据盘 |
|---|---|---|---|---|
| node1 | 4核 | 8GB | 60GB SSD | 1块500GB HDD或SSD |
| node2 | 4核 | 8GB | 60GB SSD | 1块500GB HDD或SSD |
| node3 | 4核 | 8GB | 60GB SSD | 1块500GB HDD或SSD |
这里的重点不是配置高低,而是“每台机器至少有一块独立的数据盘给OSD”。如果你把系统盘和数据盘混在一起,容器写日志、读镜像会和OSD抢IO,集群一忙起来性能就崩。我自己的经验是:OSD进程一定跑在独立裸设备或独立分区上,不要直接用一个目录挂到容器里,否则可调试性和性能都会下降。
2.2 磁盘怎么分:系统盘和数据盘必须分离
Ceph最理想的存储介质是裸盘,也就是整个磁盘不分区,直接交给OSD使用。这样OSD自己管理磁盘元数据,生命周期更干净。Docker部署时,把主机的/dev/sdb直接挂载进容器,容器里的OSD才能拿到完整的块设备。
如果你手里机器不多,只分了一块数据盘,那也至少要在docker-compose.yml里把数据盘以devices方式传给OSD容器,而不是给一个/data目录。目录走的是主机文件系统,一旦文件系统损坏,数据恢复会非常痛苦。裸盘模式下,Ceph内部有自己的文件系统逻辑,故障恢复能力会强不少。
2.3 基础环境初始化:Docker、时间同步与内核参数
三台机器先装Docker。CentOS或者Ubuntu都有对应的Docker官方源,装完记得把docker加入开机自启,并且给当前用户加到docker组里,避免每条命令都要 sudo。我平时用Ubuntu比较多,执行这几条就能起步:
sudo apt update sudo apt install -y docker.io docker-compose-v2 sudo systemctl enable --now docker sudo usermod -aG docker $USER装完Docker别急着拉镜像,先解决两个基础问题。第一个是时间同步,Ceph对节点间时钟偏差非常敏感,偏差过大会导致MON之间无法正常通信。我统一用chrony做NTP同步,配置文件里指定国内可用的NTP服务器即可。第二个是容器主机名规划,我习惯在/etc/hosts里把三台节点的主机名和IP写死,因为容器启动时可能自己解析不出其他节点。
192.168.10.101 node1 192.168.10.102 node2 192.168.10.103 node3再顺手调整几个内核参数,虽然普通测试环境下不调也可能跑起来,但为了更接近生产习惯,我会把文件描述符上限和网络缓冲区调一下:
cat >> /etc/sysctl.conf <<EOF fs.file-max=1000000 net.core.rmem_default=262144 net.core.wmem_default=262144 net.core.rmem_max=16777216 net.core.wmem_max=16777216 EOF sysctl -p这里必须说明,上面这些参数不是Ceph性能调优的全部,只是基础防线。测试环境里不做这些也能启动集群,但如果你后面想做性能压测,就最好提前把基础打好,避免后续被无关因素干扰。
2.4 容器网络和端口规划
Docker容器默认用bridge网络,容器之间靠IP通信。Ceph集群内部各组件通信,需要以下几个端口:
| 端口 | 用途 | 说明 |
|---|---|---|
| 3300 | MON服务端口 | v2版本协议,新版Ceph默认用这个 |
| 6789 | MON服务端口 | v1版本协议,老版本常用 |
| 6800-7300 | OSD通信端口 | 每个OSD会占用不同端口 |
| 8080或8443 | RGW服务端口 | 对象存储网关使用,看配置 |
| 8443/8080 | Dashboard | MGR的页面端口 |
只要没有防火墙拦截这些端口,且各节点主机名能互通,容器之间就可以自由通信。我在三台节点上都临时关掉了firewalld,测试集群图省事,生产环境还是更推荐在安全组或iptables里精确放行。
3. 编写编排文件:让容器按角色就位
Docker化部署Ceph通常有两种姿势:一种是官方早已弃用的ceph/daemon镜像,另一种是自己用基础镜像 + 安装脚本定制。我这次用的是社区常用的ceph/daemon镜像,原因很简单——这个镜像内置了所有Ceph组件入口,你通过command指定角色即可,省去自己写一堆安装脚本的麻烦。
3.1 镜像选择与拉取
镜像我选择的是ceph/daemon:latest,实际上它会把Ceph的几个主力版本都囊括在内,具体版本号要看镜像tag。拉取命令:
docker pull quay.io/ceph/daemon:latest如果你在国内,Docker Hub拉着慢的话,可以配个镜像加速,或者直接把上面的quay.io/ceph/daemon改成你本地镜像仓库里的同步地址。我拉的时候大约三百多MB,耐心等一会儿就到了。
有个细节要提前讲:ceph/daemon镜像的启动命令比较特殊,它会根据环境变量CEPH_DAEMON或容器的command来决定自己是MON、MGR还是OSD。你不需要在容器里手动跑ceph-mon -i mon1,直接传command: mon即可。
3.2 编排MON容器:先把集群“大脑”立起来
MON是集群的“大脑”,第一步必须先把第一个MON初始化好,否则后面所有组件都找不到集群状态。我当时的目录结构是这样的:
/opt/ceph/ ├── docker-compose.yml ├── etc-ceph/ # 挂载到容器 /etc/ceph └── var-lib-ceph/ # 挂载到容器 /var/lib/ceph写一个基本的MON的compose服务,大概长这样:
services: mon: image: quay.io/ceph/daemon:latest container_name: ceph-mon hostname: node1 command: mon environment: - CLUSTER=ceph - CEPH_DAEMON=mon - MON_IP=192.168.10.101 - CEPH_PUBLIC_NETWORK=192.168.10.0/24 - CEPH_CLUSTER_NETWORK=192.168.10.0/24 - MON_NAME=node1 networks: ceph-net: ipv4_address: 172.20.0.10 volumes: - ./etc-ceph:/etc/ceph - ./var-lib-ceph:/var/lib/ceph注意几个重要点:
- CEPH_PUBLIC_NETWORK 要填你的物理网络网段,容器之间以及外部客户端都是走这个网络找MON的。
- MON_IP 要填宿主机实际IP,或者容器IP。如果填错,MON会一直等待集群连接。
- 挂载
./etc-ceph是为了把集群钥匙文件持久化到宿主机,这个目录丢了,整个集群等于失忆,千万不能删。
我用compose时喜欢自定义容器IP,避免每次重建后IP变动导致其他节点找不到MON。其实Ceph本身可以通过monmap来发现,但自定义IP会让日志看起来更清晰,排查问题时不至于眼花。
3.3 编排MGR、OSD容器:加入存储节点
第一个MON跑起来后,后面两台节点上的MON、MGR、OSD才能通过admin keyring加入集群。所以我会把三台机器的compose分开管理:node1的compose里先跑一个mon,node2、node3的compose分别启动mon、mgr、osd。
MGR的compose片段:
mgr: image: quay.io/ceph/daemon:latest container_name: ceph-mgr hostname: node2 command: mgr environment: - CLUSTER=ceph - CEPH_DAEMON=mgr volumes: - ./etc-ceph:/etc/ceph - ./var-lib-ceph:/var/lib/ceph depends_on: - monOSD的compose片段,重点是把整块数据盘传进去:
osd: image: quay.io/ceph/daemon:latest container_name: ceph-osd hostname: node2 command: osd privileged: true environment: - CLUSTER=ceph - CEPH_DAEMON=osd - OSD_DEVICE=/dev/sdb devices: - /dev/sdb:/dev/sdb volumes: - ./etc-ceph:/etc/ceph - ./var-lib-ceph:/var/lib/ceph如果你和我一样,每台机器上有多块数据盘,想一次性都交给OSD,可以把OSD_DEVICE写成/dev/sdb:/dev/sdc这样的逗号分隔形式。注意容器必须加privileged: true,否则OSD没有足够权限操作块设备、挂载文件和执行分区操作。这也是很多新手卡壳最多的地方:不加privileged,OSD起来后会说找不到设备或权限不够。
3.4 实际启动顺序:先mon,再mgr/osd,最后验证
在node1上先把MON拉起来:
cd /opt/ceph docker compose up -d mon等待几十秒,确认容器起来后,用docker logs ceph-mon看日志,看到类似mon.node1 is up and running就能放心了。这时再在node2、node3上分别启动mgr和osd。如果三台机器都只用同一个compose文件且包含所有服务,那么启动顺序会是MON先等初始化完成,MGR和OSD轮询加入集群。生产上我更推荐先在node1单独起mon,等集群钥匙生成后再一次性起来其他角色节点。
这里要特别提醒:第一台MON生成集群配置和钥匙后,其他节点的./etc-ceph目录下的文件会被自动填充。如果你是用git去分发compose文件,务必把etc-ceph目录加入.gitignore,它属于敏感文件,里面存放着admin keyring,泄露出去等于集群大门敞开。
4. 初始化集群并完成基本配置
容器都启动后,真正的初始化工作才开始。很多人以为容器起来了集群就自动好了,其实不是。你需要利用容器的CLI进到集群内部,执行几个关键命令,让MON握手、MGR接管监控、OSD被识别并加入树。
4.1 创建MON并生成集群钥匙
首次启动MON容器后,我们进入容器内部查看情况:
docker exec -it ceph-mon bash在容器里先检查是否已经生成集群钥匙:
ls -l /etc/ceph/正常情况下会看到ceph.conf和ceph.client.admin.keyring等文件。如果没看到,多半是MON初始化失败。我遇到过最典型的情况是MON_IP写错,导致集群无法形成初始monmap。
确认keyring存在后,在容器里执行:
ceph mon stat ceph quorum_status --format json-pretty如果quorum_status里能看到三个MON节点,说明monitor层已经完成了多数派选举。假如只有1个节点也没事,因为我们还没在node2、node3上启动MON。
4.2 创建MGR和OSD,激活存储能力
MGR和OSD容器起来之后,在同一个容器内执行:
ceph -s正常情况下你应该看到类似这样的输出摘要:
cluster: id: 4b5c8e5e-xxxx-xxxx-xxxx-xxxxxxxxxxxx health: HEALTH_WARN OSD count 0 < osd_min_initial_allocs services: mon: 3 daemons, quorum node1,node2,node3 mgr: 1 daemons active如果OSD还没出现,需要手动引导。ceph/daemon镜像的OSD容器在启动时会自动扫描设备并创建OSD,但有时因为权限、设备路径或卷挂载问题会失败。我建议在每台机器上检查OSD的日志:
docker logs ceph-osd看到类似create osd 0 on host node1的输出,说明OSD已经成功识别。如果没有,执行手动引导命令:
docker exec -it ceph-mon ceph osd tree然后逐个手动创建OSD所在节点的认证权限。不过在容器化方案里,更简便的做法是重启对应的OSD容器,让启动脚本重新扫描并配置。很多情况下,重启容器就能解决问题。
4.3 调整PG数量与创建存储池
OSD全部起来后,ceph -s里的HEALTH_WARN一般会变成HEALTH_OK,但还需要创建存储池才能真正使用。Ceph的每个池由若干PG(Placement Group)组成,PG数量直接关系到数据分布的均匀程度。
PG数量的经验公式不是固定的,常见经验是:每个OSD大约分配50到100个PG。比如我有3个OSD,那么严格的PG总量大约是150到300,但因为还有多个池,每个池的PG不能太大。我这次只创建一个测试池,设置PG数为32,避免数量爆炸:
ceph osd pool create mypool 32 32创建后还要设置副本数。默认是3副本,如果只有3个OSD,可以保持3副本;如果只有2个OSD,建议改成2副本,否则数据会一直处于degraded状态。
ceph osd pool set mypool size 3 ceph osd pool set mypool min_size 2这里的min_size 2表示即使有一个副本暂时不可用,集群仍然允许读写。要是不设min_size,一旦有节点故障,整个池会卡在只读状态。这个细节很多人忽略,实际运行中非常关键。
4.4 用rados bench做一次集群体检
集群看似正常不代表读写一定没问题。我最喜欢的验证方式是直接用Ceph自带的rados bench写几个测试对象进去,看IO是否真的能打通:
rados -p mypool bench 30 write --no-cleanup rados -p mypool bench 30 seq rados -p mypool bench 30 rand如果能看到Total time run和Bandwidth (MB/sec)正常输出,说明集群的写入链路已经通了。我实测在三台普通SATA盘上,顺序写大约在80到120MB/s,不算快,但对测试环境已经足够。建议在测试完用下面的命令清理掉测试对象,免得占着空间又影响后续调试:
rados -p mypool cleanup5. 把存储用起来:RBD、对象存储与CephFS
Ceph集群本身像个大仓库,对外还得提供好多接口。作为容器化存储平台,最常用的接入方式有三种:块设备、对象存储和文件系统。我在这套测试环境里全部拉起来验证了一遍。
5.1 RBD块设备:最常用的接入方式
RBD(RADOS Block Device)是最常用的方式,KVM虚拟化、OpenStack、Kubernetes大多走这个接口。先在mypool里创建一个块设备镜像:
rbd create mypool/test-image --size 10G然后在一台能够连到集群的机器上映射这个块设备(一般需要装ceph-common或使用容器内的客户端):
rbd map mypool/test-image mkfs.ext4 /dev/rbd0 mount /dev/rbd0 /mnt/ceph-rbd映射后你就可以把它当成一块普通磁盘用。容器化环境里我们常常不在宿主机上直接挂载RBD,而是让Kubernetes通过CSI插件来动态创建卷,原理一样,只是每次创建/删除卷都由插件自动完成。
5.2 RGW对象存储:一条命令启一个网关
对象存储网关RGW也就是提供S3兼容接口的服务。容器化下启用RGW非常方便,在compose文件里加一个rgw服务:
rgw: image: quay.io/ceph/daemon:latest container_name: ceph-rgw hostname: node1 command: rgw environment: - CLUSTER=ceph - CEPH_DAEMON=rgw - RGW_NAME=rgw.node1 ports: - "7480:7480" volumes: - ./etc-ceph:/etc/ceph - ./var-lib-ceph:/var/lib/ceph容器起来后,RGW默认监听在7480端口(新版ceph/daemon镜像可能是7480),你可以用一个S3客户端去连接。Ceph官方更推荐将RGW放在单独的节点上,避免和OSD抢资源,但小规模测试环境同机部署完全没问题。
5.3 CephFS文件系统:挂载成目录直接用
CephFS需要先启用MDS服务。在每个需要承担文件系统元数据的节点上开一个MDS容器,类似这样:
mds: image: quay.io/ceph/daemon:latest container_name: ceph-mds hostname: node1 command: mds environment: - CLUSTER=ceph - CEPH_DAEMON=mds volumes: - ./etc-ceph:/etc/ceph - ./var-lib-ceph:/var/lib/cephMDS起来后,在MON容器里执行:
ceph fs volume create cephfs ceph fs status cephfs然后就能在客户端用内核模块直接挂载:
mount -t ceph node1:6789:/ /mnt/cephfs -o name=admin,secretfile=/etc/ceph/ceph.client.admin.keyringCephFS适合多个客户端共享同一个文件系统的场景,比如多个Web节点共享上传目录、数据分析任务共享数据集。不过它比RBD多一层元数据服务,延迟会高一点,IO频率极高的数据库场景不建议优先选用。
6. 高可用演练与经典问题排查
集群搭建完成只是第一步,真正让我觉得这事靠谱的,是把节点挨个干掉以后看它还能不能自己恢复。我在测试环境下做了两轮故障模拟,结果都符合预期。
6.1 模拟故障:MON挂掉会怎样
先在node1上停止MON容器:
docker stop ceph-mon然后进入node2或node3的MON容器,检查:
ceph mon stat正常情况下仍然能看到quorum node1,node2,node3,只不过node1标记为down。因为3个MON中有2个还活着,多数派选举依然有效,集群对外服务不中断。如果我把node2的MON也停掉,只剩1个活着的MON,这时再用ceph -s就会看到类似mon is allowing insecure global id reclaim的告警,或者直接报quorum lost。这说明法定人数不足,集群进入了保护模式。恢复后,MON会自动重新加入,quorum也会恢复。
6.2 模拟故障:OSD挂掉会怎样
OSD容器的挂掉是最常见的高可用场景。我随机停掉一台节点的OSD:
docker stop ceph-osd然后看集群状态:
ceph -s ceph osd tree你会看到某个OSD状态变为down,集群健康变红,同时PG开始处于degraded。等我把OSD容器重新启动,它会自动重新加入集群,数据会重新平衡。这个过程可能持续几分钟甚至更久,取决于数据总量。
这里有个重点:Ceph的服务质量在数据自愈期间受copy和刷盘影响,IO会有所下降,这是正常现象。生产上建议把osd_pool_default_size和min_size设置好,确保即使有一个OSD挂掉,也不会影响业务写入。
6.3 常见问题速查与避坑技巧
我在搭建和运维过程中踩过不少坑,整理成一张表,你直接对着查:
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| MON容器反复重启,日志提示“clock skew detected” | 节点间时间偏差过大 | 部署ntp/chrony,等时间同步后重启容器 |
| OSD容器提示“device not found” | 设备路径写错或未加privileged | 检查/dev/sdb是否存在,compose里加privileged: true |
| ceph -s显示“auth: unable to find a keyring” | 容器内没有挂载正确keyring | 检查etc-ceph目录的keyring权限,重建容器 |
| 创建pool时提示“pg num too small” | PG数量设置过小 | 把PG数调大,比如从8改成32 |
| 集群一直HEALTH_WARN,提示“too few PGs per OSD” | 池数量或PG数量不足 | 增加新池时需要重新规划PG数量 |
| 客户端连接RGW失败 | RGW端口被防火墙拦截 | 放行对应端口,查看docker logs ceph-rgw |
避坑技巧方面,我想额外强调三点:
- keyring文件是命根子,多节点共享一个etc-ceph目录,不能只在一台机器上留备份。
- 容器化部署时,OSD的数据卷不要用Docker volume管理,直接用
devices映射裸盘,否则重启容器容易丢设备映射。 - 每次改动compose文件后,记得用
docker compose config验证一下,避免YAML格式错误导致容器起不来。
7. 优化方向与我的实操心得
容器化搭建Ceph到这个程度,已经可以正常服务了。但我还是想分享几个后续优化方向,以及我自己踩过坑之后换来的经验。它们不一定每次都必要,但会让你的集群更耐用。
7.1 资源限制与容器日志
容器化最大的好处之一是可以给服务设资源上限。我给MON和MGR容器设置了CPU和内存限制,比如cpu_count和mem_limit,避免某个角色的进程吃掉整机资源。OSD不建议限制得太死,因为它在重平衡时非常吃内存和CPU,限制太紧反而会拖慢恢复速度。
日志方面,Ceph容器默认会把日志输出到控制台,也就是docker logs。时间久了会非常大,我习惯在compose里加上日志轮转配置,比如:
logging: driver: json-file options: max-size: "100m" max-file: "3"这样容器日志不会无限膨胀。排查问题的时候主要看docker logs ceph-mon、ceph-osd,再不行就去var-lib-ceph目录里看Ceph自身的日志文件。
7.2 从容器化走向生产的三点提醒
如果你不是做测试,而是想认真用这套方案上生产,我建议你再多考虑三步:监控、备份、升级策略。监控可以用Prometheus采集Ceph exporter的指标,在MGR上启用prometheus模块即可。备份则要多备份etc-ceph下的keyring和ceph.conf,这是整个集群的“户口本”。升级策略更别懒,不要随手拉latest的daemon镜像,必须锁定具体版本tag,并在测试环境先跑完升级流程再动生产。
容器化方案确实灵活,但在生产环境里,我建议优先考虑官方推荐的cephadm,它对系统服务和升级路径的处理更完备。容器化更适合用来快速验证功能、做实验、搭培训环境,不能因为“能用”就忽略它在稳定性、性能和运维工具链上的短板。
7.3 我个人踩过的几个坑,希望你别再踩
第一个坑是有一天我发现集群突然进入HEALTH_WARN,查了半天发现是某一个OSD容器重启后没有自动挂载之前的数据盘。后来才发现,我把OSD数据目录放在了Docker的默认volume里,而不是直接挂载宿主机目录。从那以后我坚持用devices映射裸盘。
第二个坑是MON的MON_IP配置。一开始我在三台机器上都把MON_IP写成了各自容器IP,结果集群monmap乱掉,查了好久才意识到应该填宿主机物理IP。容器IP是给外部客户端访问用的,MON之间握手走的是物理网络。
第三个坑比较隐蔽:在一个节点上同时跑了MON、MGR、OSD、RGW四个容器,内存只有8GB,结果某次压测时整机swap偏高,OSD因为内存不足被内核杀了。所以如果你在一台机器上什么都想干,内存一定要给足,我的建议是至少16GB。否则就老老实实把角色分散到多台机器。
整个容器化Ceph集群搭建过程,其实就是先用Docker把各角色快速编排出来,再通过Ceph自己的集群网络把它们拧在一起。我操作完之后最大的感受是:Docker降低了Ceph的上手门槛,让你不用太早陷入依赖安装和系统调优的泥潭。但对“为什么这么配”“故障时怎么恢复”这些底层逻辑,还是需要你保持敬畏心。建议你先用这套方案把集群跑熟,再一点点往业务和性能压测上靠,遇到问题再回到第6章的表里排查,基本都能找到答案。