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案例 详解
🔗 大数据模块直达链接

相关推荐
豐儀麟阁贵1 分钟前
8.2异常的抛出与捕捉
java·开发语言·python
老华带你飞3 分钟前
社区养老保障|智慧养老|基于springboot+小程序社区养老保障系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·小程序·毕设·社区养老保障
码龄3年 审核中3 分钟前
Linux record 03
java·linux·运维
q***87606 分钟前
springboot下使用druid-spring-boot-starter
java·spring boot·后端
程序员西西6 分钟前
SpringBoot无感刷新Token实战指南
java·开发语言·前端·后端·计算机·程序员
东南门吹雪7 分钟前
Spring的Bean相关
java·spring·bean·aop
q***69777 分钟前
Y20030018基于Java+Springboot+mysql+jsp+layui的家政服务系统的设计与实现 源代码 文档
java·spring boot·mysql
摇滚侠9 分钟前
2025最新 SpringCloud 教程,Nacos-配置中心-数据隔离-动态切换环境,笔记18
java·笔记·spring cloud
Seven9714 分钟前
剑指offer-42、和为S的两个数字
java