用 docker-compose 启动三个 mongodb 容器不等于副本集建成,必须配置 --replset、自定义网络、健康检查,并通过 entrypoint 脚本在所有节点就绪后仅由首节点执行 rs.initiate()。

直接上结论:用 docker-compose 启动三个 MongoDB 容器 ≠ 副本集就建好了。不加 --replSet、没统一网络、没健康检查、没控制 rs.initiate() 执行时机,rs.status() 一定会报 NoReplicationEnabled。
docker-compose.yml 必须显式声明 --replSet 和自定义网络
副本集不是靠数量自动形成的,每个节点启动时必须带相同名称的 --replSet 参数,且所有容器必须能通过可解析主机名互相访问。
- 每个服务的
command必须包含["mongod", "--replSet", "rs0"](rs0大小写敏感,所有节点必须一致) -
hostname必须显式设置(如mongo1),不能依赖默认随机名 - 所有服务必须挂到同一个
networks下(如mongo-net),且该网络类型为bridge或overlay,不能用默认bridge - 端口映射只用于宿主机连接,副本集成员间通信必须用容器内 host(如
mongo1:27017),不能写127.0.0.1或宿主机 IP
healthcheck 是 rs.initiate() 成功的前提
depends_on 只判断容器是否启动,不保证 mongod 已监听并响应命令。没有健康检查,rs.initiate() 很可能在其他节点还没 ready 时就执行,导致初始化失败或部分节点无法加入。
在 Linux 上通过 Docker 运行 OpenClaw,并使用 Tailscale 实现远程访问。⚠️ 涉及 sudo、Docker、Tailscale和凭证挂载——请先查阅安全章节...
- 推荐 healthcheck:
mongosh --eval "db.runCommand({ping:1})" - 超时和重试要足够宽松(例如
timeout: 20s,retries: 10) - 必须等全部节点 healthcheck 通过后,再让首节点执行初始化——这不能靠
depends_on实现,得靠 entrypoint 脚本判断
entrypoint 脚本必须控制 rs.initiate() 仅执行一次
多个节点同时执行 rs.initiate() 会报错 already initialized;漏执行则副本集不成立。必须用明确条件(如 hostname == mongo1)触发,且只在所有 peer 健康后运行。
- 脚本逻辑应为:启动
mongod→ 循环检查其他节点mongosh --eval "db.runCommand({ping:1})"是否成功 → 判断自身 hostname 是否为mongo1→ 执行rs.initiate()和rs.add() - 别用环境变量传“是否初始化”,容易因启动顺序错乱;用
hostname最可靠 -
rs.initiate()的 config 中host字段必须写容器内可解析名("mongo1:27017"),不能写"localhost"或 IP
keyFile 权限和属主出错会导致 mongod 直接退出
开启认证(生产必需)时,keyFile 不只是生成就行。权限或属主不对,mongod 启动失败,日志里只有模糊错误,比如 Failed to start up WiredTiger under any compatibility version 或静默退出。
- 生成命令必须用:
openssl rand -base64 756 > mongodb.key - 权限必须是
400:chmod 400 mongodb.key - 属主必须是 UID 999(MongoDB 官方镜像默认用户):
chown 999:999 mongodb.key - 挂载路径在所有节点上需完全一致(如都挂到
/etc/mongo/mongodb.key),且内容一字不差 - 启动参数加
--keyFile /etc/mongo/mongodb.key --auth,缺一不可
最容易被忽略的是 healthcheck 的实际效果和 entrypoint 中对 peer 状态的等待逻辑——这两点不到位,哪怕 docker-compose up 显示 all services are up,rs.status() 依然为空或报错。副本集不是“启动了就自动组成”,而是“所有节点准备好 + 显式初始化 + 认证合规”三者同时满足才行。










