Java-159 MongoDB 副本集容器化 10 分钟速查卡|keyfile + –auth + 幂等 init 附 docker-compose

TL;DR

  • 场景 :用 Docker 在本机快速起一个 MongoDB 7 副本集,带内网鉴权与管理员账号。
  • 结论 :生成 keyfiledocker compose up -d → 一次性容器自动 rs.initiate + createUser;明确开启 --auth
  • 产出docker-compose.yml、幂等初始化脚本、连接URI与校验清单。

集群搭建1-容器版

最小可运行示例MRE

shell 复制代码
# 1) 生成副本集 keyfile(权限必须 600)
openssl rand -base64 756 > mongo-keyfile && chmod 600 mongo-keyfile

# 2) 启动
docker compose up -d

# 3) 校验:查看 primary 与成员状态
docker exec -it mongo1 mongosh --eval "rs.status().members.map(m=>({host:m.name,state:m.stateStr}))"

# 4) 用管理员连接(容器内DNS)
docker exec -it mongo1 mongosh "mongodb://admin:admin123@mongo1:27017/?replicaSet=rs0&authSource=admin"

版本信息

组件 已验证 备注
MongoDB 7.0.x 镜像 mongo:7.0
Docker 24+ 本地/服务器均可
Compose v2 docker compose 子命令
OS Ubuntu 22.04/24.04、macOS 任一即可

准备 keyfile

集群内鉴权必须需要有 keyfile:

shell 复制代码
openssl rand -base64 756 > mongo-keyfile
chmod 600 mongo-keyfile

注意keyfile的内容不要泄露了,我这里是本地测试,后续就不用了:

docker-compose

准备 docker-compose 文件如下所示:

yaml 复制代码
version: "3.9"
services:
  mongo1:
    image: mongo:7.0
    container_name: mongo1
    hostname: mongo1
    ports:
      - "27017:27017"
    volumes:
      - ./mongo1-data:/data/db
      - ./mongo-keyfile:/etc/mongo-keyfile:ro
    command: ["mongod","--replSet","rs0","--bind_ip_all", "--keyFile", "/etc/mongo-keyfile"]
    networks: [mongo-net]

  mongo2:
    image: mongo:7.0
    container_name: mongo2
    hostname: mongo2
    volumes:
      - ./mongo2-data:/data/db
      - ./mongo-keyfile:/etc/mongo-keyfile:ro
    command: ["mongod","--replSet","rs0","--bind_ip_all", "--keyFile", "/etc/mongo-keyfile"]
    networks: [mongo-net]

  mongo3:
    image: mongo:7.0
    container_name: mongo3
    hostname: mongo3
    volumes:
      - ./mongo3-data:/data/db
      - ./mongo-keyfile:/etc/mongo-keyfile:ro
    command: ["mongod","--replSet","rs0","--bind_ip_all", "--keyFile", "/etc/mongo-keyfile"]
    networks: [mongo-net]

  # 一次性初始化副本集 + 创建管理员账号
  init-rs:
    image: mongo:7.0
    container_name: init-rs
    depends_on: [mongo1, mongo2, mongo3]
    networks: [mongo-net]
    entrypoint: [ "bash", "-lc" ]
    command: |
      '
      # 等待 primary 可用
      until mongosh --host mongo1 --quiet --eval "db.adminCommand({ping:1})" >/dev/null 2>&1; do
        echo "waiting mongo1..."
        sleep 2
      done
      mongosh --host mongo1 << "EOF"
      rs.initiate({
        _id: "rs0",
        members: [
          { _id: 0, host: "mongo1:27017", priority: 2 },
          { _id: 1, host: "mongo2:27017", priority: 1 },
          { _id: 2, host: "mongo3:27017", priority: 1 }
        ]
      })
      // 等待选主
      function waitPrimary() {
        while (true) {
          s = rs.status();
          if (s.members && s.members.some(m => m.stateStr === "PRIMARY")) { break; }
          sleep(1000);
        }
      }
      waitPrimary();

      // 创建 root 管理员
      use admin
      db.createUser({
        user: "admin",
        pwd:  "admin123",
        roles: [ { role: "root", db: "admin" } ]
      })
      print("ReplicaSet initialized and admin user created.")
      EOF
      '
    restart: "no"

networks:
  mongo-net:
    driver: bridge

启动服务

我们启动服务:

容器外(本机)直连 primary(开发调试):

shell 复制代码
mongodb://admin:admin123@localhost:27017/?replicaSet=rs0&authSource=admin

容器内/同网络(更推荐,具备副本集感知):

shell 复制代码
mongodb://admin:admin123@mongo1:27017,mongo2:27017,mongo3:27017/?replicaSet=rs0&authSource=admin

我们输入数据库的地址进行连接:

shell 复制代码
mongodb://admin:admin123@localhost:27017/?directConnection=true&authSource=admin

可以看到如下情况:

快速检查清单

shell 复制代码
# 1) 成员与角色
docker exec -it mongo1 mongosh --eval 'rs.status().members.map(m=>m.name+" -> "+m.stateStr)'

# 2) 权限有效(应返回1)
docker exec -it mongo1 mongosh "mongodb://admin:admin123@mongo1:27017/admin?replicaSet=rs0" --eval 'db.runCommand({ping:1}).ok'

# 3) 写入与读回
docker exec -it mongo1 mongosh "mongodb://admin:admin123@mongo1:27017/test?replicaSet=rs0" --eval 'db.t.insertOne({ok:1}); printjson(db.t.findOne())'

回滚/销毁剧本(谨慎,会删数据)

shell 复制代码
# 停止
docker compose down

# 清理数据目录(危险)
sudo rm -rf mongo1-data mongo2-data mongo3-data
rm -f mongo-keyfile

常见报错

症状 根因 快排
BadValue: permissions on keyfile are too open mongo-keyfile 非 600 chmod 600 mongo-keyfile,确保挂载为 :ro
NotYetInitialized 连接在 rs.initiate 前 等待 init-rs 完成或手动执行 rs.initiate()
Authentication failed 密码特殊符号/错库 在 URI 中对特殊字符转义;确认 authSource=admin
ReplicaSetNoPrimary 还未选主或优先级配置不当 再等几秒;检查 priority 与容器 DNS 可达性

FAQ

  • 为啥只映射 27017? 开发机只需连主即可;副本发现靠 replicaSet 参数自动解析。
  • keyfile 会泄露吗? 生产必须妥善保管并限制权限;本文示例为本地环境。
  • 如何固定某一台为 Primary? 调整 priority,并确保网络可达。
  • 如何扩容到 5 节点? 新增服务并 rs.add,或在 init 脚本里扩展 members。
  • 如何接入 Spring Boot? 使用 spring.data.mongodb.uri,保持 replicaSet 与 authSource 参数一致。

其他系列

🚀 AI篇持续更新中(长期更新)

AI炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究 ,持续打造实用AI工具指南!
AI-调查研究-108-具身智能 机器人模型训练全流程详解:从预训练到强化学习与人类反馈
🔗 AI模块直达链接

💻 Java篇持续更新中(长期更新)

Java-154 深入浅出 MongoDB 用Java访问 MongoDB 数据库 从环境搭建到CRUD完整示例

MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务正在更新!深入浅出助你打牢基础!
🔗 Java模块直达链接

📊 大数据板块已完成多项干货更新(300篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!
大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解
🔗 大数据模块直达链接

相关推荐
峥嵘life4 小时前
Android EDLA开发认证说明和开发流程
开发语言·1024程序员节
含目的基因的质粒4 小时前
Python的数据容器
1024程序员节
兜兜风d'4 小时前
RabbitMQ 发送方确认机制详解
spring boot·分布式·rabbitmq·java-rabbitmq·1024程序员节
工大张学友4 小时前
[MySQL]表——删除数据
1024程序员节
m0_748233644 小时前
C++ 模板初阶:从函数重载到泛型编程的优雅过渡
java·c++·算法·1024程序员节
zz-zjx4 小时前
MySQL 索引深度指南:原理 · 实践 · 运维(适配 MySQL 8.4 LTS)
运维·数据库·mysql
Hyt的笔记本4 小时前
【C++】异步操作
c++·1024程序员节
薛定谔的zhu4 小时前
如何设计通用 ATS 代理销售激励系统(从业务到架构的通盘思考)
金融·1024程序员节
笑脸惹桃花4 小时前
【笑脸惹桃花】1024,阶段性回望与小结
1024程序员节