docker部署mongodb分片集群必须分步初始化:config server强制要求副本集模式(即使单节点也要rs.initiate),shard节点需启用同名副本集且地址用容器名,所有服务须在同一自定义网络,bind_ip必须设为0.0.0.0。

mongos 连不上 config server,或 sh.addShard() 报错 “no reachable servers”。
为什么 config server 必须是副本集,哪怕只用 1 个节点?
因为 MongoDB 7.x(及 6.0+)强制要求 config server 启用副本集模式,即使你只部署单节点,也得用 replSet 参数并调用 rs.initiate(),否则 mongos 启动时会直接拒绝连接,报错:Failed to connect to config server: No replica set configuration could be found。
实操要点:
-
config server容器必须带--configsvr参数(或配置文件中设configsvr=true),端口默认为27019,不能和mongod默认的27017冲突 - 哪怕只起 1 个 config 节点,也要在
docker-compose.yml中显式定义replSet: configRepl,并在初始化脚本里执行rs.initiate({ _id: "configRepl", members: [{ _id: 0, host: "mongo-config-1:27019" }] }) - 如果用多个 config 节点(推荐生产用 3 个),它们的
replSet名必须完全一致,且初始化时需一次性写入全部成员,不能逐个添加
shard 节点怎么配才不会被 mongos 拒绝?
常见错误是 shard 容器没启用副本集,或副本集名与 sh.addShard("shard1/...") 中写的不一致。MongoDB 要求每个 shard 必须是独立副本集(哪怕单节点),且 sh.addShard() 的地址格式必须是 replSetName/host:port。
实操建议:
- 每个 shard 容器启动时加
--replSet shard1(或配置文件中设replSet=shard1),确保shard1和后续sh.addShard("shard1/mongo-shard1-1:27017")里的名字严格一致(区分大小写) - 不要用
localhost或127.0.0.1作为 shard 地址——Docker 容器间通信靠服务名,sh.addShard()里填的是容器名(如mongo-shard1-1),不是宿主机地址 - shard 初始化必须早于
mongos启动:先让所有 shard 容器运行、完成rs.initiate(),再启动mongos容器,否则sh.addShard()会超时
docker-compose.yml 里哪些字段最容易漏?
不是所有字段都可省略。少写一个关键项,整个集群就卡在初始化环节。
必须显式声明的配置项:
-
networks:所有服务(config、shard、mongos)必须在同一个自定义网络里,否则 DNS 解析失败,mongo-shard1-1找不到mongo-config-1 -
command或entrypoint:不能全靠镜像默认命令。config server 要加--configsvr --port 27019;shard 要加--replSet shard1;mongos 必须指定--configdb configRepl/mongo-config-1:27019,mongo-config-2:27019,mongo-config-3:27019 -
healthcheck:建议给每个mongod加健康检查(如echo 'db.runCommand("ping").ok' | mongosh --quiet --host mongo-config-1:27019),避免mongos启动时 config 还没 ready 就去连
初始化脚本该放在哪?谁来执行?
不能靠人肉进容器敲命令。集群规模稍大(比如 3 config + 6 shard + 2 mongos),手动操作极易出错且不可复现。
推荐做法:
- 把初始化逻辑写成 shell 脚本(如
init-config.sh),挂载进 config 容器,在容器启动后自动执行rs.initiate() - mongos 容器启动后,用
wait-for-it.sh等待 config server 就绪,再执行sh.addShard()和sh.enableSharding("db_name") - 所有脚本必须设好权限(
chmod +x),且挂载路径在容器内有执行权限;否则/bin/sh: ./init.sh: Permission denied
bind_ip 必须设为 0.0.0.0,否则其他容器根本连不上。这个值不在环境变量里,只能通过配置文件或 --bind_ip 参数硬编码进去。











