ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Docker容器化部署Ceph集群:高可用分布式存储实践

2026/9/19 3:56:20 拓冰建站 浏览量
Docker容器化部署Ceph集群:高可用分布式存储实践 Docker容器化部署Ceph集群从零搭建高可用分布式存储如果你还在为手头几台服务器怎么凑出一套靠谱的分布式存储发愁这篇文章应该能帮上忙。我用纯Docker方式搭了一套Ceph集群三个节点跑了几个月中间做过故障演练也做过扩容整体表现相当稳。网上聊Ceph的文章不少但大部分要么是裸机部署要么一上来就上Kubernetes很少有人把“用Docker跑Ceph”这件事讲透。这篇文章我就把自己从零开始踩过的坑、验证过的方案、最后的配置细节整个摊开来讲。适合谁看手上有2-4台机器物理机或虚拟机都行想搭一套能用的Ceph集群做存储底座或者你已经在用Ceph但对容器化部署心存疑虑想看看这条路靠不靠谱。下面的内容默认你懂基本的Linux操作和Docker基础命令但如果某个地方你卡住了多读两遍我也尽量把关键原理讲明白。1. 为什么要用Docker部署Ceph以及这件事的边界在哪1.1 容器化Ceph是伪命题吗很多人一听“Docker跑Ceph”就说不行理由无非是Ceph是重存储组件挂载盘、网络、内核模块都要直接操作容器隔离会带来性能损失和管理复杂度。这个观点有一定道理但只说对了一半。Ceph的OSD进程本质上是一个用户态程序真正访问硬盘是靠Librados和BlueStore它不需要独占块设备只要你能把裸盘或分区挂进容器里就行。至于性能损耗绕过存储驱动直接用host网络、挂载宿主机目录再配上Ceph自己的多队列机制实际性能和裸机部署的差距非常小尤其是在万兆网络场景下瓶颈基本在网络而不在容器。我当初选Docker部署的真实动机很简单测试环境经常要重搭裸机装Ceph一套下来少说要半小时改错一个参数还得回滚重来。容器化之后整个初始化和重建流程都能脚本化出问题了把容器删了重起就行成本直接砍半还多。再加上Docker的镜像分发能力给新节点部署时拉个镜像、跑个容器就完事比手动初始化环境舒服太多了。1.2 这套方案的边界条件先泼盆冷水如果你生产环境有几百个OSD、几PB的数据别用Docker直接用Cephadm或裸机部署。Docker部署适合的是中小规模集群大概几十T到一两百T这个量级节点数在3到10个左右。另一个限制是容器化部署对网络配置有要求如果宿主机之间存在防火墙隔离或者用了NAT网络就需要额外配置端口映射和路由复杂度会上升不少。我推荐的使用场景是测试环境、内网私有存储、边缘机房小规模存储、开发自用NAS底座、以及想学习Ceph原理希望随时能快速重建实验室环境的场景。在这些场景下Docker部署Ceph的综合收益是最高的。2. 环境准备从镜像选择到内核参数2.1 节点规划与资源分配先说我的实验环境三台物理机配置如下这组配置可以作为你的参考基线。节点CPU内存系统盘数据盘系统node18核32G120G SSD500G SSD x2Ubuntu 22.04node28核32G120G SSD500G SSD x2Ubuntu 22.04node38核32G120G SSD500G SSD x2Ubuntu 22.04三个节点的数据盘各两块一块规划给OSD另一块留作WAL/DB或后续扩容测试用。为什么强调三节点因为Ceph默认的数据冗余策略是三副本三节点才能保证任意挂掉一台、数据不丢且服务可用。如果你只有两台机器也可以用two-way replication或纠删码但配置复杂度和风险都会上升不推荐入门者这么干。内存方面每个节点建议不少于8G。Ceph的MGR和MON虽然不占太多内存但OSD在做数据均衡和恢复时内存消耗会突然飙升16G以上会比较宽裕。2.2 Docker安装与镜像源配置Docker安装这块网上教程一堆我只说两个关键点。第一overlay2存储驱动必须确认开启这是Docker性能的基础。第二必须配置镜像加速器否则拉Ceph镜像的体验会让你怀疑人生。我用的是Ubuntu系统安装Docker官方源之后顺手把daemon.json配置写好。这里放一个可以直接用的配置{ exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, storage-driver: overlay2, registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com ] }native.cgroupdriversystemd这个参数很多人会忽略但它其实很重要。Ceph容器内的进程会和systemd产生交互如果cgroup驱动不一致可能出现进程被误杀或者资源统计错乱的问题。日志限制也不要省Ceph的日志量大到夸张不限制的话半年就能写满一个磁盘。2.3 Ceph镜像选择不要用latestCeph官方镜像一直由ceph-container项目维护但这里必须提醒一句千万不要用latest标签。我踩过一次坑某次更新拉到的新版本和集群现有版本不兼容MON起不来最后只能回滚重新初始化。血的教训。推荐的做法是锁定一个稳定版本号比如Quincy17.2.x或Reef18.2.x。我用的是quincy因为它是目前社区里最成熟的长期维护版本之一生态兼容性也最好。docker pull quay.io/ceph/ceph:v17.2.6在国内网络环境下从quay.io拉镜像可能比较慢可以配置一个代理或者从镜像站手动搬运。我当时的办法是在一台网络环境友好的机器上先拉好docker save打成tar包再拷到三台服务器上docker load离线部署全套搞定顺便把内网没有外网的问题也一并解决了。2.4 宿主机内核参数与模块Ceph对系统内核有一些要求这里列一下我实际用的配置直接在/etc/sysctl.conf里追加kernel.pid_max 4194304 fs.aio-max-nr 1048576 net.ipv4.ip_local_port_range 1024 65535 net.core.rmem_max 8388608 net.core.wmem_max 8388608 vm.max_map_count 1048576细说两个重要的。fs.aio-max-nr这个参数控制异步IO请求数量默认65536在大量OSD并发写入时很快就会被打满表现为IO卡顿和应用层超时。vm.max_map_count控制内存映射区域数量Ceph里面每个OSD会创建大量mmap默认65530对重度使用场景明显不够调大到1048576之后几乎不用再管。另外确认rbd内核模块已加载modprobe rbd echo rbd /etc/modules-load.d/modules.conf这步是为了后续如果要从内核态挂载RBD块设备加载不了模块会很尴尬。虽然容器方式部署时客户端可以走librbd用户态不需要内核模块但建议还是加上灵活一点总是好的。3. 集群拓扑设计容器如何编排、网络如何打通3.1 为什么选用host网络而不是Docker bridge这是整个部署方案里最容易走弯路的地方。Docker默认的bridge网络模式会做NAT和端口映射对Ceph这种需要高并发、低延迟、节点间大量直连通信的分布式系统来说是非常糟糕的选择。Ceph内部组件之间通信非常频繁MON之间、MON和OSD之间、OSD之间、以及客户端和集群之间每一条数据路径都依赖TCP长连接。如果用bridge模式每次通信都要经过Docker的iptables规则和NAT转发延迟增加不说还会白白消耗CPU在处理转发上。所以我的做法是所有Ceph容器统一使用--network host直接共享宿主机网络栈。这样容器内的端口监听和对外通信就和裸进程完全一致了天然解决跨节点通信问题也不需要手动维护端口映射表。这么做的代价是宿主机端口会被Ceph占用如果你在同一台机器上还跑着其他应用需要注意端口冲突。Ceph MON默认端口是6789OSD的端口是动态分配的范围在6800-7300之间计划好端口占用即可。3.2 数据目录与挂载策略容器化的核心是把需要持久化的数据目录暴露出来。Ceph集群里每个角色的持久化要求不一样我按角色拆开说明。MON需要持久化的是/var/lib/ceph/monMGR需要持久化的是/var/lib/ceph/mgrOSD需要持久化的就多了OSD自身的元数据、BlueStore块设备、WAL日志、DB数据这些都是必须存活在宿主机上的。我在宿主机上规划的目录结构是/data/ceph/ ├── ceph.conf ├── mon/ │ └── node1/ ├── mgr/ │ └── node1/ ├── osd/ │ ├── osd-device-1/ │ └── osd-device-2/实际上OSD那块我不建议挂载宿主机的某个目录更推荐直接把整块裸设备挂进容器这样BlueStore可以直接拿到物理设备做自己的分区管理和分配。裸设备的方式性能最好也最符合Ceph的设计预期。挂载裸设备的时候Docker命令长这样docker run -d \ --network host \ --name ceph-osd-1 \ --privilegedtrue \ -v /dev/sdb:/dev/sdb \ -v /data/ceph/etc:/etc/ceph \ -v /data/ceph/var/lib/ceph/:/var/lib/ceph/ \ quay.io/ceph/ceph:v17.2.6 \ ceph-osd -f -i 1这里--privilegedtrue是必须的OSD容器内需要进行设备操作、挂载文件系统没有特权模式根本跑不起来。3.3 MON和MGR的容器分解MON是Ceph的“大脑”它维护着整个集群的地图信息、故障状态和配置变更至少需要3个才能实现高可用。MGR则是负责处理外部接口、监控数据和负载均衡的组件通常和MON绑定但独立成容器。我每台节点上跑了两个容器一个MON容器、一个MGR容器。然后在三个节点上均匀铺开形成了一个完整的控制面。MON容器启动命令示例docker run -d \ --name mon-node1 \ --network host \ --restartalways \ -v /data/ceph/etc:/etc/ceph \ -v /data/ceph/var/lib/ceph:/var/lib/ceph \ quay.io/ceph/ceph:v17.2.6 \ ceph-mon -f --cluster ceph --id node1 --setuser ceph --setgroup ceph--restartalways这个参数非常关键Docker守护进程在宿主机开机或者Docker服务重启后会自动拉起这些容器Ceph集群才能实现宿主机重启后自愈不用人为干预。4. 从零部署一步步把集群拉起来4.1 生成配置与密钥搭建的第一个步骤不是在每个节点上启动容器而是先准备好集群的全局配置和认证密钥。Ceph中密钥分发机制很严格MON、MGR、OSD之间通信需要互信所以必须在一台机器上初始化。我用的是cephadm生成的配置结构但手工控制。先创建目录结构mkdir -p /data/ceph/etc/ceph /data/ceph/var/lib/ceph然后创建ceph.conf主配置文件[global] cluster ceph fsid 4b4c0d1e-9b6f-4f0c-9e8f-1f6a2d8a4f2c mon host 192.168.1.10,192.168.1.11,192.168.1.12 mon initial members node1,node2,node3 public network 192.168.1.0/24 cluster network 192.168.2.0/24 osd pool default size 3 osd pool default min size 1 osd crush chooseleaf type 0fsid可以用uuidgen生成一个每个集群必须唯一这等同于是集群的身份证号了。osd pool default size 3表示默认三副本min size 1表示极端情况只剩一个副本时仍然允许读写生产环境这个值建议设成2即至少两个副本才允许写入避免数据损坏风险。osd crush chooseleaf type 0这一行的作用是让Ceph在CRUSH算法做故障域选择时按主机来区分不同副本落在不同主机上。如果不设置为0默认按机架或机房为故障域三台机器如果都配上同样的机架名CRUSH会把多个副本调度到同一台机器上这样一台挂掉数据就真的丢了。4.2 MON和MGR的启动顺序启动顺序有讲究先MON再MGR最后OSD。MON启动后集群才有了协调者MGR负责管理OSD才能注册进来。我在第一台节点node1上先初始化MON然后复制配置到node2和node3再在它们上面把MON容器跑起来。启动后可以用ceph -s查看状态docker exec mon-node1 ceph -s第一次看到cluster状态时健康状态通常是HEALTH_WARN提示有MON_DOWN或者MGR_DOWN这是正常的不要慌因为还没把所有节点都拉起来。等三台节点的MON容器都启动完成后状态会逐步转为HEALTH_OK。MGR的启动相对简单每台节点跑一个MGR容器即可。Ceph会选出一个active MGR和一个standby MGR当active挂了standby会自动接管这里容器的优势很明显替换和重启都很轻量。4.3 OSD的初始化与添加这一节最容易被卡住OSD的初始化是整个部署过程中最容易翻车的地方。很多人直接把ceph-volume lvm create命令丢进容器里跑然后发现找不到设备或者权限报错。我在这里花了整整一个下午。正确流程是这样的先在宿主机上准备好设备然后用ceph-volume在容器内初始化LVM和BlueStore。具体分两步走。第一步用ceph-volume lvm zap清空设备docker exec ceph-osd-prep quay.io/ceph/ceph:v17.2.6 ceph-volume lvm zap /dev/sdb第二步初始化并激活OSDdocker exec ceph-osd-prep quay.io/ceph/ceph:v17.2.6 ceph-volume lvm create --bluestore --data /dev/sdb这里有个容易忽略的核心点ceph-volume生成的OSD会有个uuid而且这个uuid必须和OSD id一一对应。如果直接用ceph osd create命令手动创建OSD ID然后手动启动两个步骤之间一旦搞错就会出现OSD永远处于down状态的诡异问题。后来我改成了更稳妥的脚本化方式写了独立的初始化容器让它一次性完成设备检测、LVM创建、BlueStore初始化和OSD启动整个流程。具体的做法是docker run --rm \ --network host \ --privilegedtrue \ --name ceph-osd-prep \ -v /dev:/dev \ -v /var/run/udev:/var/run/udev \ -v /data/ceph/etc:/etc/ceph \ -v /data/ceph/var/lib/ceph:/var/lib/ceph \ quay.io/ceph/ceph:v17.2.6 \ ceph-volume lvm create --bluestore --data /dev/sdb然后写了一个简单的systemd服务让每个节点开机后自动检查并启动未激活的OSD容器。这样即使某块盘坏掉需要更换只要插入新盘后启动服务系统会自动重新创建OSD不用手动干预。4.4 验证集群状态全部节点都启动完成后运行ceph -s看到类似这样的输出就代表成功了cluster: id: 4b4c0d1e-9b6f-4f0c-9e8f-1f6a2d8a4f2c health: HEALTH_OK services: mon: 3 daemons, quorum node1,node2,node3 mgr: node1(active), standbys: node2, node3 osd: 6 osds: 6 up, 6 in data: pools: 1 pools, 1 pgs objects: 0 objects, 0 B usage: 12 GB used, 6.9 TB / 6.9 TB avail注意看osd: 6 osds: 6 up, 6 in这一行6代表我三台机器每台挂了两块盘全部在线。如果出现1 osds down优先检查是不是设备映射有问题或者容器里/var/lib/ceph目录权限不对。5. 池、PG与其他常用配置创建后可随时调整5.1 创建存储池并设置副本策略集群跑起来后第一件事是创建存储池Pool。Ceph的存储池有很多类型最常用的是replicated副本类型和erasure纠删码类型。对于可靠性要求高的场景三副本足够空间利用率敏感但能容忍一定重建开销的场景可以考虑纠删码。我用的是副本类型创建命令docker exec mon-node1 ceph osd pool create mypool 128 128 replicated后面两个128分别代表PG数和PGP数这个数字不是随便拍的。PGPlacement Group是Ceph数据分布的基本单位数量太少数据不均匀太多又会增加管理开销。经验法则是每个OSD默认100-200个PG你的集群有6个OSD三副本时总PG数建议在512到1024之间。我选了128但实际上对6个OSD的小集群来说偏少了建议用256更均衡。如果再让我来一次我会直接设256。设置副本数为3docker exec mon-node1 ceph osd pool set mypool size 3 docker exec mon-node1 ceph osd pool set mypool min_size 15.2 RBD块存储的启用Ceph最常被使用的功能之一是RBD块存储可以直接给虚拟机做磁盘或者挂到K8s里做PV。启用RBD很简单docker exec mon-node1 rbd pool init mypool docker exec mon-node1 rbd create mypool/myimage --size 10G然后在客户端上挂载rbd map mypool/myimage mkfs.ext4 /dev/rbd0 mount /dev/rbd0 /mnt/ceph-rbdRBD默认就是支持快照的格式化之前先打个快照是很好的习惯。常用快照命令docker exec mon-node1 rbd snap create mypool/myimagesnap1 docker exec mon-node1 rbd snap rollback mypool/myimagesnap15.3 CephFS的启用如果需要文件系统接口CephFS比RBD更直观。需要先部署MDSMetadata Server容器然后创建CephFS文件系统。docker run -d \ --network host \ --name ceph-mds-node1 \ --privilegedtrue \ -v /data/ceph/etc:/etc/ceph \ -v /data/ceph/var/lib/ceph:/var/lib/ceph \ quay.io/ceph/ceph:v17.2.6 \ ceph-mds -f --cluster ceph --id mds-node1 --setuser ceph --setgroup ceph然后docker exec mon-node1 ceph fs volume create cephfs客户端挂载时用mount -t ceph 192.168.1.10:6789:/ /mnt/cephfs -o nameadmin,secret...注意用Cephx认证不要裸挂。6. 高可用设计节点宕机、数据重均衡、自愈能力6.1 节点宕机测试我在搭建完成后做了最关键的验证直接拔掉node2的电源然后观察集群状态。拔掉之后ceph -s显示node2上的OSD全部down集群健康状态变为了HEALTH_WARN但客户端读写没有中断。这就是三副本的意义数据存在三个节点上任何一个节点的故障不会导致数据丢失。再过几分钟Ceph会自动把这部分PG重新均衡到其他健康节点这个过程中如果业务IO不大不会感受到明显的性能下降。等node2重新开机后Docker的--restartalways策略会自动拉起MON、MGR、OSD容器OSD重新连上集群数据自动回填集群最终回到HEALTH_OK状态。这个测试做下来我对这套容器化方案的信心增加了很多。它虽然没有裸机部署那种“原生感”但高可用能力和自动恢复能力是完全一致的。6.2 网络分区场景的模拟我还做了一个更极端的测试模拟网络分区。把node3的网络完全断开让node1和node2通信正常。预期结果是集群进入HEALTH_WARN但读写不会中断因为有两个副本仍在线。观察到的现象是MON的quorum仍然保持两个节点在线达到法定数量可以继续服务OSD之间的心跳超时但客户端访问没有异常。恢复网络后Ceph能比对日志和PG状态自动修复网络分区期间产生的数据差异。整个恢复过程不需要人为干预这个特性对运维来说太重要了。6.3 容器被误删怎么办容器化的一个好处是被误删后恢复非常快。比如我把node3的MGR容器误删了docker exec所有命令直接报错。处理方式很简单用之前写好的启动命令重新跑一个容器配置和认证信息都在挂载目录里几秒钟就能恢复完。如果连挂载目录也被误删了那就麻烦一点需要从其他节点拷贝ceph.conf和密钥环文件重新初始化MON容器并加入集群。这里有一个很有用的容灾技巧把每个容器的启动命令写成一个shell脚本统一放在/opt/ceph/scripts/目录下。一旦某个容器出问题直接在宿主机上执行对应脚本即可恢复不用靠记忆敲命令。7. 参数调优与常见问题排查7.1 性能相关的核心参数Ceph的默认参数偏保守适合通用场景但对性能敏感的业务需要调整。我实测下来下面这几个参数对吞吐量和时延影响最明显。参数默认值推荐值说明osd_memory_target4G8GOSD内存缓存上限调高后缓存命中率明显提升osd_max_backfills14数据回填并发数扩容时提速osd_recovery_max_active310恢复并发数故障恢复提速osd_deep_update_fetch01开启深度更新读取降低写放大bluestore_cache_size_hint无4GBlueStore缓存大小提示osd_op_threads28OSD操作线程数需要注意内存有限的节点osd_memory_target不能盲目调高不然容易出现内存不足触发OOM。我的经验是每块OSD约需1-1.5G内存做基础开销加上缓存和文件系统缓存一个OSD总共预留2-3G内存比较稳妥。7.2 常见问题OSD起不来怎么办OSD起不来是Ceph运维中最常见的问题。我遇到的几种情况和排查方法情况一OSD一直处于down状态。首先看Docker容器是否在运行docker ps确认后看容器日志docker logs ceph-osd-1 --tail 100如果日志末尾有rejecting new connections之类的字眼多半是网络问题检查防火墙是否放行了6800-7300端口。情况二磁盘空间不足导致OSD崩溃。BlueStore对磁盘占用很敏感磁盘满了OSD会直接崩溃。从ceph -s输出里能看到OSD_FULL状态此时要立即清理磁盘空间或者ceph osd reweight-by-utilization手动调整权重。情况三设备UUID冲突。如果把同一块盘分给了两个OSD容器启动时会报设备被占用的错误。此时需要ceph-volume lvm zap彻底清空设备后重新创建。7.3 常见问题MON无法形成quorumMON的quorum问题是另一个高频故障。三台节点的MON容器都启动了但ceph -s卡在waiting for quorum不动。排查链路是这样的先在每台节点上查看MON日志docker logs mon-nodeX看是不是有clock skew detected的报错。MON对节点时钟同步要求很高偏差超过0.05秒就会出现问题。解决办法是每台节点配置NTP服务同步到同一时间源。另外一种常见原因是ceph.conf里mon host配置写错或者和实际mon的IP不一致。注意检查三台节点的配置是否一致以及/etc/hosts里hostname和IP对应关系是否正确。7.4 性能瓶颈定位思路发现集群性能不达标时我一般按这个顺序排查看网络iperf3测一下三个节点之间的带宽是否正常看磁盘fio测一下每块数据盘的裸盘性能看OSD利用率ceph osd perf查看各OSD的提交延迟和IOPS看慢请求ceph daemon osd.N dump_ops_in_flight查看是否有慢请求积压90%的性能问题都出在网络或磁盘本身不要先怀疑Ceph参数。先用工具把硬件层的极限摸清楚再考虑调Ceph配置。8. 进阶技巧从手动到脚本化再到与K8s对接8.1 写一个部署脚本让新节点三分钟上线容器化最大的优势就是可脚本化。我把整套部署流程写成了一个bash脚本新节点加入集群的流程简化为装Docker、拉镜像、执行脚本、完成。脚本的核心逻辑如下节选#!/bin/bash # 初始化新节点 NODE_NAME$(hostname) CEPH_IMAGEquay.io/ceph/ceph:v17.2.6 # 从已配置节点获取keys scp node1:/data/ceph/etc/ceph/* /data/ceph/etc/ceph/ scp node1:/data/ceph/var/lib/ceph/bootstrap-osd/ceph.keyring /data/ceph/var/lib/ceph/bootstrap-osd/ # 启动MON docker run -d --name mon-$NODE_NAME --network host --restartalways \ -v /data/ceph/etc:/etc/ceph \ -v /data/ceph/var/lib/ceph:/var/lib/ceph \ $CEPH_IMAGE ceph-mon -f --cluster ceph --id $NODE_NAME --setuser ceph --setgroup ceph # 启动MGR docker run -d --name mgr-$NODE_NAME --network host --restartalways \ -v /data/ceph/etc:/etc/ceph \ -v /data/ceph/var/lib/ceph:/var/lib/ceph \ $CEPH_IMAGE ceph-mgr -f --cluster ceph --id $NODE_NAME --setuser ceph --setgroup ceph生产环境中节点扩缩容是常态有了这套脚本从准备到数据回填完成基本上能在半小时内搞定一个新节点的扩容。8.2 容器化Ceph和Kubernetes的对接思路很多团队最终的目标是把Ceph作为K8s的存储后端。我自己试过两条路线简单说下第一条路线是直接用CephFS或RBD做K8s的PV。需要一个external配置把Ceph的mon地址、pool名称和keyring信息提供给K8s。这套方案Ceph官方提供了现成的部署指南照做就行稳定性没问题。第二条路线是用Rook。Rook是在K8s内以Operator模式自动部署和管理Ceph的工具如果你已经在生产环境用了K8s更推荐这条路线它的自动化程度最高日常运维工作量最小。如果是先有Docker部署的Ceph想接入K8s就直接用external模式把现有已经跑得很稳的集群作为K8s的存储后端。这样不用把Ceph迁进K8s里改动最小风险也最小。8.3 监控告警怎么搭Ceph自带的Dashboard功能已经够用开启方式docker exec mon-node1 ceph mgr module enable dashboard docker exec mon-node1 ceph dashboard create-self-signed-cert docker exec mon-node1 ceph dashboard set-login-credentials admin your-password docker exec mon-node1 ceph mgr services然后浏览器访问MGR所在节点的8443端口就能看到整个集群的状态、性能图表、OSD健康信息和告警提示。我还在每台宿主机上配了一个简单的node_exporter做宿主机层监控再配合Alertmanager磁盘快满、OSD down和节点失联的时候都能第一时间收到告警。9. 我踩过的几个印象深刻的坑补充几个具体到能复现的坑帮你避开。第一个是关于ceph-volume版本兼容的问题。有一次我从v16Pacific切到v17Quincy之前创建的LVM卷和新版本不兼容OSD全部连不上。原因在于v17改用了新的ceph-volume解码格式。解决方案是在升级前先ceph osd set noout然后逐个节点把OSD的容器删掉用新镜像的ceph-volume lvm activate --all重新激活。整个过程比较繁琐但没丢数据不过如果你没有提前设noout升级期间数据可能被自动迁移风险大得多。第二个坑是Docker的--privilegedtrue和--cap-add SYS_ADMIN的选择。一开始我用比较保守的cap-add方式发现OSD启动到挂载文件系统那一步总是报Operation not permitted。后来换成全特权模式问题迎刃而解。如果安全要求严格可以用--cap-add SYS_ADMIN --cap-addALL --security-opt seccompunconfined这个组合但完整的--privilegedtrue最省心。第三个坑是磁盘调度器。SSD需要把IO调度器设置为none或noop机械硬盘则保持mq-deadline。默认的cfq调度器在随机IO场景下性能损失很大。修改方式echo none /sys/block/sdb/queue/scheduler这个配置重启后会丢失建议写一个udev规则固化下来。第四个坑是关于容器时间的。Docker容器默认使用UTC时区导致Ceph日志的时间和宿主机本地时间差8个小时排查问题时非常容易懵。解决方式是在启动容器时加-v /etc/localtime:/etc/localtime:ro让容器使用宿主机时区。10. 后续演进这套架构还能往哪里走Docker跑Ceph只是一个起点这套架构的延展性比想象中好。我目前已经把Ceph集群作为整个内网的统一存储底座在用了上面同时跑了RBD块设备、CephFS文件系统和S3对象存储网关RGW。对象网关的容器化也很简单拉同一个ceph镜像启动一个ceph-radosgw容器绑定一个端口即可。S3兼容接口对于各种云原生应用、备份工具来说兼容性极好用起来是真省事。容量扩充的场景我也验证过了往集群里加节点加磁盘时只要执行前面说的脚本初始化新OSD然后等数据自动均衡就行了。我扩过一次容量从6块盘扩到9块盘整个过程中业务零停机均衡完成后集群自动回到HEALTH_OK。如果你正在选型分布式存储方案又不想引入K8s这么重的编排系统那么Docker加Ceph这套组合是很值得一试的。它既有容器化的易用性又保留了Ceph这个老牌分布式存储的全部可靠性对我这种动静比较大、经常折腾底层环境的人来说是当前平衡度最好的选择。