MongoDB Docker 最小集群(三节点副本集)部署实战(含踩坑记录)

本文记录了我在 Ubuntu 24.04 上,用 Docker 搭建 MongoDB 三节点副本集(启用 `keyFile + auth`)的完整过程。内容尽量聚焦实操和常见坑,适合作为一篇可直接复用的部署手册。

一、先说结论:最容易踩的 3 个坑

  1. keyFile 权限必须严格正确,否则容器会反复重启。
  2. keyFile 的属主需要与容器内 MongoDB 进程用户匹配(本文镜像为 uid=101 gid=65534)。
  3. 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

根因

  1. 副本集成员当前配置为 mongo1/mongo2/mongo3(Docker 内部 DNS 名称)。
  2. 外部客户端连接后会获取拓扑信息,并尝试解析这些主机名。
  3. 局域网客户端无法解析容器名,导致报错。

方案 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

九、生产环境建议

  1. 不建议直接暴露公网 27017,优先内网、VPN、堡垒机等方式接入。
  2. 三节点建议分布在三台主机,使用稳定私网 IP 或可解析域名。
  3. 副本集成员 host 必须对客户端可解析、可达。
  4. 备份建议采用“全量 + oplog 增量”,并定期做恢复演练。
  5. 监控至少覆盖:副本集状态、主从延迟、连接数、磁盘、内存、慢查询。

十、常见误区清单

  1. curl 的返回当作 MongoDB 不可用的依据。
  2. keyFile 权限设为 644 或属主设置错误。
  3. 只做了 Docker 端口映射,忘了放行 UFW 或云安全组。

结语

如果你只想快速搭一个“可认证、可副本集、可外部访问”的 MongoDB 最小集群,这套流程已经足够稳定。核心就在三点:keyFile 权限、副本集 host 可解析、以及用正确工具验证连通性。

评论加载中...