本文记录了我在 Ubuntu 24.04 上,用 Docker 搭建 MongoDB 三节点副本集(启用 `keyFile + auth`)的完整过程。内容尽量聚焦实操和常见坑,适合作为一篇可直接复用的部署手册。
一、先说结论:最容易踩的 3 个坑
keyFile权限必须严格正确,否则容器会反复重启。keyFile的属主需要与容器内 MongoDB 进程用户匹配(本文镜像为uid=101 gid=65534)。- 用
curl访问27017返回Empty reply from server是正常现象,MongoDB 不是 HTTP 服务。
二、部署目标与适用场景
- 目标:单机 Docker 三节点副本集,启用副本集内部认证与账号认证。
- 适用:开发、测试、功能验证。
- 不适用:生产高可用(生产建议至少三台主机部署三节点)。
三、docker-compose.yml(可直接使用)
建议固定镜像版本,避免 latest 带来的不可预期变更。以下示例保留你当前配置逻辑:
services:
mongo1:
image: docker.1ms.run/mongodb/mongodb-community-server:latest
container_name: mongo1
ports:
- 27017:27017
volumes:
- mongo1-data:/data/db
- ./secrets/mongodb-keyfile:/etc/mongo-keyfile:ro
command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--auth", "--keyFile", "/etc/mongo-keyfile"]
restart: unless-stopped
networks:
- mongo-net
mongo2:
image: docker.1ms.run/mongodb/mongodb-community-server:latest
container_name: mongo2
ports:
- 27018:27017
volumes:
- mongo2-data:/data/db
- ./secrets/mongodb-keyfile:/etc/mongo-keyfile:ro
command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--auth", "--keyFile", "/etc/mongo-keyfile"]
restart: unless-stopped
networks:
- mongo-net
mongo3:
image: docker.1ms.run/mongodb/mongodb-community-server:latest
container_name: mongo3
ports:
- 27019:27017
volumes:
- mongo3-data:/data/db
- ./secrets/mongodb-keyfile:/etc/mongo-keyfile:ro
command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--auth", "--keyFile", "/etc/mongo-keyfile"]
restart: unless-stopped
networks:
- mongo-net
volumes:
mongo1-data:
mongo2-data:
mongo3-data:
networks:
mongo-net:
driver: bridge
四、目录准备与权限设置(关键步骤)
示例目录结构:
tree /home/pengqian/program/mongodb/
/home/pengqian/program/mongodb/
├── docker-compose-mongo-backup.yaml
├── docker-compose.yml
├── keyfile
└── secrets
└── mongodb-keyfile
1)确认镜像内运行用户
sudo docker run --rm docker.1ms.run/mongodb/mongodb-community-server:latest id
uid=101(mongodb) gid=65534(nogroup) groups=65534(nogroup),101(mongodb)
2)设置 keyFile 权限
cd /home/pengqian/program/mongodb
sudo chown 101:65534 ./secrets/mongodb-keyfile
sudo chmod 400 ./secrets/mongodb-keyfile
# 父目录需要可遍历权限,否则可能出现 Permission denied
sudo chmod 755 ./secrets
sudo chmod 755 .
五、启动容器并检查状态
cd /home/pengqian/program/mongodb
sudo docker compose down
sudo docker compose up -d
sudo docker compose ps -a
sudo docker compose logs -f --tail=200 mongo1
如果日志里出现权限相关报错,优先回到上一节重新检查 chown/chmod。
六、初始化副本集与管理员账号
1)初始化副本集(仅首次执行)
sudo docker exec -it mongo1 mongosh --eval "rs.initiate({_id:'rs0',members:[{_id:0,host:'mongo1:27017'},{_id:1,host:'mongo2:27017'},{_id:2,host:'mongo3:27017'}]})"
2)创建管理员(仅首次执行)
sudo docker exec -it mongo1 mongosh --eval "db.getSiblingDB('admin').createUser({user:'root',pwd:'请替换为强密码',roles:[{role:'root',db:'admin'}]})"
3)验证认证与副本集状态
sudo docker exec -it mongo1 mongosh -u root -p '请替换为强密码' --authenticationDatabase admin --eval "db.runCommand({ping:1})"
sudo docker exec -it mongo1 mongosh -u root -p '请替换为强密码' --authenticationDatabase admin --eval "rs.status()"
七、访问排障:为什么 27017 看起来“不通”
1)先确认端口监听
sudo ss -lntp | grep 27017
2)不要用 curl 判断 MongoDB 可用性
curl http://localhost:27017
curl http://192.168.50.100:27017
若返回 Empty reply from server,表示 TCP 已连通,但协议不匹配,这是正常结果。
3)用 mongosh 做正确连通性验证
mongosh "mongodb://root:请替换为强密码@127.0.0.1:27017/?authSource=admin"
4)局域网访问失败时检查防火墙
sudo ufw status verbose
sudo ufw allow 27017/tcp
sudo ufw reload
若在云服务器环境,还要同步放行云安全组/云防火墙端口。
八、Compass 报错 getaddrinfo ENOTFOUND mongo1 的处理
现象
在局域网其他设备使用 Compass 连接 192.168.50.100:27017 时,报错:
getaddrinfo ENOTFOUND mongo1
根因
- 副本集成员当前配置为
mongo1/mongo2/mongo3(Docker 内部 DNS 名称)。 - 外部客户端连接后会获取拓扑信息,并尝试解析这些主机名。
- 局域网客户端无法解析容器名,导致报错。
方案 A:快速可用(直连单节点)
mongodb://root:请替换为强密码@192.168.50.100:27017/?authSource=admin&directConnection=true
适合临时管理,不具备完整副本集感知能力。
方案 B:推荐方案(标准副本集外部访问)
前提:已对外暴露 27017/27018/27019。
在主节点执行 reconfig:
sudo docker exec -it mongo1 mongosh -u root -p '请替换为强密码' --authenticationDatabase admin --eval "cfg=rs.conf(); cfg.members[0].host='192.168.50.100:27017'; cfg.members[1].host='192.168.50.100:27018'; cfg.members[2].host='192.168.50.100:27019'; rs.reconfig(cfg,{force:true})"
验证:
sudo docker exec -it mongo1 mongosh -u root -p '请替换为强密码' --authenticationDatabase admin --eval "rs.status().members.map(m=>m.name)"
Compass 使用标准副本集连接串:
mongodb://root:请替换为强密码@192.168.50.100:27017,192.168.50.100:27018,192.168.50.100:27019/?replicaSet=rs0&authSource=admin
九、生产环境建议
- 不建议直接暴露公网
27017,优先内网、VPN、堡垒机等方式接入。 - 三节点建议分布在三台主机,使用稳定私网 IP 或可解析域名。
- 副本集成员
host必须对客户端可解析、可达。 - 备份建议采用“全量 + oplog 增量”,并定期做恢复演练。
- 监控至少覆盖:副本集状态、主从延迟、连接数、磁盘、内存、慢查询。
十、常见误区清单
- 把
curl的返回当作 MongoDB 不可用的依据。 - 把
keyFile权限设为644或属主设置错误。 - 只做了 Docker 端口映射,忘了放行 UFW 或云安全组。
结语
如果你只想快速搭一个“可认证、可副本集、可外部访问”的 MongoDB 最小集群,这套流程已经足够稳定。核心就在三点:keyFile 权限、副本集 host 可解析、以及用正确工具验证连通性。