基于 Docker 的 MongoDB 部署与使用指南

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: 本指南面向不同层级开发者,详解 MongoDB 6.0 + Docker 部署:从单节点开发环境到高可用副本集生产部署,涵盖初始化、备份恢复、安全认证、监控告警及常见问题排查,助力高效构建稳定可靠的 MongoDB 服务。

适用读者及版本说明

适用读者

  • 新手开发者:快速搭建 MongoDB 开发/测试环境,掌握基础操作
  • 中级开发者:实现数据持久化、初始化脚本、备份恢复等实用功能
  • 高级工程师/运维:部署生产级高可用副本集、配置安全策略与监控告警

版本兼容范围

  • MongoDB:6.0.x(LTS 长期支持版,支持至 2027 年,推荐 6.0.18 稳定版)
  • Docker:≥ 24.0.0
  • Docker Compose:≥ v2.26.1(兼容 version: "3.8" YML 配置)
  • 操作系统:Linux(CentOS 7+/Ubuntu 18.04+)、Windows 10+/Server 2019+、macOS 12+

1. MongoDB 简介

MongoDB 是面向文档的 NoSQL 数据库,以 BSON(类 JSON 格式)存储数据,兼顾灵活性与性能,适合不同技术栈用户:

核心特点

  • 灵活数据模型:无固定表结构,支持半结构化数据,适合快速迭代(如创业项目、需求频繁变更场景)。
  • 高性能与扩展性:支持分片(Sharding)、水平扩展,可应对 TB 级数据(生产大规模场景)。
  • 高可用保障:副本集(多节点备份)自动故障转移,避免单点故障(生产核心需求)。
  • 丰富生态:支持事务、全文搜索、地理空间索引、聚合分析(满足复杂业务场景)。

典型应用场景

场景类型 示例 适用用户
基础后端存储 网站用户数据、APP配置 新手(练手)
实时数据处理 日志存储、IoT设备数据 中级开发者
复杂业务系统 CMS内容管理、AI数据文档 高级工程师

官方资源

  • 国内镜像:https://xuanyuan.cloud/zh/r/library/mongo
  • 官方文档:https://www.mongodb.com/docs/manual

2. 部署前准备

新手需严格核对环境,避免后续报错;高级用户可重点关注生产级配置。

2.1 硬件要求

资源类型 开发环境(新手练手) 生产环境(业务使用) 说明
CPU ≥ 2 核 ≥ 4 核 生产需应对并发,避免卡顿
内存 ≥ 4 GB ≥ 16 GB MongoDB 内存占用较高,生产需预留
硬盘 ≥ 20 GB(SSD/HDD) ≥ 100 GB(建议 SSD) 生产用 SSD 提升 IO 性能

2.2 软件依赖(必装)

  • Docker:≥ 24.0.0(新手需先安装 Docker,参考 Docker 一键安装脚本 https://xuanyuan.cloud/install/linux
    检查版本:docker --version(输出如 Docker version 26.0.0, build 2ae903e 即合格)
  • Docker Compose:≥ v2.26.1(部分 Docker 已内置,无需单独安装)
    检查版本:docker compose version(输出如 Docker Compose version v2.27.0 即合格)

  • 一键安装配置脚本(推荐方案):
    该脚本支持多种 Linux 发行版,支持一键安装 Docker、Docker Compose 并自动配置轩辕镜像访问支持源。

    bash <(wget -qO- https://xuanyuan.cloud/docker.sh)
    

2.3 网络与安全基础

  • 端口:MongoDB 默认端口 27017(新手注意:开发环境可临时开放本地端口,生产环境严禁公网暴露!)
  • 镜像访问支持:国内用户需配置 Docker 镜像访问支持(推荐用轩辕镜像,直接拉取加速镜像即可)。
  • 版本兼容性提示:
    • Docker Compose v2.x 兼容 version: "3.8" 及以上 YML 配置
    • MongoDB 6.0 为 LTS(长期支持版,支持至 2027 年),6.2/6.3 为非 LTS 版本,不建议生产环境使用
    • Windows 与 Linux 路径差异:Linux 用 / 分隔,Windows 用 \ 分隔;Windows 挂载目录无需手动配置权限

3. MongoDB 镜像下载

推荐用轩辕镜像(避免国外网络超时),步骤均已简化。

3.1 方式1:使用轩辕镜像

# 拉取 6.0.18 稳定版(指定patch版本,避免版本漂移,适合开发/生产)
docker pull docker.xuanyuan.run/library/mongo:6.0.18

# (可选)将镜像改名为官方标准名称
docker tag docker.xuanyuan.run/library/mongo:6.0.18 mongo:6.0.18
# 删除临时镜像标签,释放空间
docker rmi docker.xuanyuan.run/library/mongo:6.0.18

3.2 方式2:使用官方镜像

# 直接拉取 Docker Hub 官方镜像(指定patch版本)
docker pull mongo:6.0.18

3.3 验证镜像是否下载成功(新手必做)

执行命令 docker images,若输出如下内容,说明镜像下载成功:

REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
mongo        6.0.18    d3ad5c1a1b22   5 days ago     700MB

4. 快速上手:单节点部署

开发 vs 生产环境核心差异(一目了然)

对比项 开发/测试环境 生产环境
端口映射 启用 27017:27017 本地访问 禁用公网映射,使用内网/VPN/反向代理
密码管理 可临时使用简单密码(需标注) 强随机密码+.env文件管理+定期更换
资源限制 可选配置 必须配置(--memory/--cpus
数据持久化 Docker named volume 持久化卷+多副本备份
健康检查 可选启用 必须启用
自动重启 启用 unless-stopped 启用 always

单节点适合开发、测试场景,提供两种部署方式:docker run(快速启动)和 Docker Compose(推荐,便于后续维护)。

4.1 方式1:docker run 快速启动

# 提示:请勿在生产环境直接明文写密码,建议使用系统环境变量
# 示例:先导出环境变量 export MONGO_ROOT_PWD=$(openssl rand -base64 16)
docker run -d \
  --name mongo-dev \          # 容器名称(自定义,如 mongo-test)
  -e MONGO_INITDB_ROOT_USERNAME=admin \  # 初始化 root 用户名(必填,避免无密码风险)
  -e MONGO_INITDB_ROOT_PASSWORD=${MONGO_ROOT_PWD:-ReplaceWithStrongRandomPwd!} \  # 优先使用系统环境变量,强制提示替换强密码
  -v mongo-data:/data/db \    # 持久化数据(用 Docker named volume,避免权限问题)
  -p 27017:27017 \            # 开发环境映射端口,生产环境请删除此行
  --memory=4g \               # 资源限制:最大使用4G内存
  --cpus=2 \                  # 资源限制:最大使用2核CPU
  --restart unless-stopped \  # 容器异常时自动重启(开发/生产均推荐)
  --health-cmd "mongosh --eval 'db.runCommand({ping:1})' --quiet" \  # 健康检查:检测MongoDB可用性
  --health-interval=30s \     # 每30秒检查一次
  --health-timeout=5s \       # 检查超时时间5秒
  --health-retries=3 \        # 连续3次失败标记为不健康
  mongo:6.0.18                # 镜像名称:指定patch版本,避免版本漂移

关键参数解释

  • -e:设置环境变量,MONGO_INITDB_*首次启动(数据卷为空时)生效(初始化 root 用户)。
  • -v mongo-data:/data/db:用 named volume 持久化数据(比直接挂载宿主目录更安全,新手无需处理权限)。
  • --memory/--cpus:资源限制,避免容器占用宿主机全部资源(生产环境必须配置)。
  • --health-*:健康检查,避免容器状态显示 Up 但 MongoDB 服务不可用的情况。
  • --restart unless-stopped:避免容器意外退出后数据丢失(开发环境也建议开启)。

4.2 方式2:Docker Compose 部署(推荐,便于维护)

步骤1:创建 .env 文件(管理敏感信息,避免明文泄露)

# 在 docker-compose.yml 同级目录创建 .env 文件
# 提示:1. 替换为强随机密码(推荐用 openssl rand -base64 16 生成)
#      2. 添加 .env 到 .gitignore,避免提交到版本库
#      3. 定期更换密码并备份该文件
MONGO_INITDB_ROOT_USERNAME=admin
MONGO_INITDB_ROOT_PASSWORD=ReplaceWithStrongRandomPwd2024!
MONGO_INITDB_DATABASE=myappdb
MONGO_APP_USER=appuser
MONGO_APP_PASSWORD=AppUserStrongPwd2024!
MONGO_MEMORY_LIMIT=4g
MONGO_CPU_LIMIT=2

步骤2:创建 docker-compose.yml 文件(可直接复制)

version: "3.8"  # 兼容主流 Docker Compose v2.x 版本
services:
  mongo:
    image: mongo:6.0.18  # 指定patch版本,避免版本漂移
    container_name: mongo-dev
    env_file:
      - .env  # 引用 .env 文件,加载敏感环境变量,避免明文泄露
    volumes:
      - mongo-data:/data/db
      - ./initdb:/docker-entrypoint-initdb.d:ro  # 初始化脚本挂载(ro:只读,安全)
    # 生产环境请删除以下 ports 配置,禁止公网暴露端口
    ports:
      - "27017:27017"
    restart: unless-stopped  # 自动重启策略(生产环境可改为 always)
    mem_limit: ${
   MONGO_MEMORY_LIMIT}  # 从 .env 加载内存限制
    cpus: ${
   MONGO_CPU_LIMIT}          # 从 .env 加载CPU限制
    healthcheck:  # 健康检查(生产环境必须启用)
      test: ["CMD", "mongosh", "--eval", "db.runCommand({ping:1})", "--quiet"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s  # 容器启动后10秒再开始检查

# 声明 named volume(无需手动创建,Docker 会自动初始化)
volumes:
  mongo-data:

步骤3:创建 docker-compose.override.yml(开发环境专属配置,无需修改主配置)

# 开发环境覆盖配置,与 docker-compose.yml 同级目录
# 生产环境部署时,可通过 -f 指定主配置,忽略该文件:docker compose -f docker-compose.yml up -d
version: "3.8"
services:
  mongo:
    # 开发环境额外映射端口、开启调试日志
    ports:
      - "27017:27017"
    command: ["mongod", "--verbose"]  # 开启详细日志,便于开发调试

步骤4:启动容器

# 在 docker-compose.yml 所在目录执行
docker compose up -d

4.3 验证部署是否成功

步骤1:查看容器状态与健康状态

# 查看容器运行状态(健康状态显示 healthy 即为正常)
docker ps | grep mongo-dev

若输出包含 Uphealthy(如 Up 5 minutes (healthy)),说明容器与 MongoDB 服务均正常运行。

步骤2:连接 MongoDB 测试(两种方式)

  • 方式A:本地安装 mongosh 连接(适合有 mongosh 的用户):

    # 替换为你的用户名和密码
    mongosh "mongodb://admin:ReplaceWithStrongRandomPwd2024!@localhost:27017/admin"
    

    成功后会进入 mongosh 交互界面(显示 admin> 提示符)。

  • 方式B:容器内连接(新手推荐,无需安装 mongosh):

    # 替换为你的密码
    docker exec -it mongo-dev mongosh -u admin -p ReplaceWithStrongRandomPwd2024! --authenticationDatabase admin
    

    同样进入交互界面,输入 db.version() 可查看 MongoDB 版本(验证连接成功)。

5. 初始化脚本:自动创建用户与数据库

新手需自动初始化业务用户,高级用户可自定义脚本(如建索引、导入初始数据),脚本仅首次启动(数据卷为空时)执行。

5.1 编写初始化脚本(优化版:从.env注入密码,创建索引)

步骤1:创建脚本目录与文件

# 在 docker-compose.yml 所在目录创建 initdb 文件夹
mkdir -p initdb
# 创建初始化脚本(用 vim 或记事本编辑,新手可复制内容)
vim initdb/01-create-app-user-and-index.js

步骤2:脚本内容(密码从环境变量读取,增加索引创建)

try {
   
  // 从容器环境变量中读取业务用户配置(避免明文硬编码)
  const appUser = process.env.MONGO_APP_USER;
  const appPwd = process.env.MONGO_APP_PASSWORD;
  const targetDbName = process.env.MONGO_INITDB_DATABASE || "myappdb";

  // 校验环境变量是否存在
  if (!appUser || !appPwd) {
   
    throw new Error("业务用户配置缺失:请在 .env 中设置 MONGO_APP_USER 和 MONGO_APP_PASSWORD");
  }

  // 切换到预创建的业务数据库
  const targetDb = db.getSiblingDB(targetDbName);

  // 检查业务用户是否已存在,避免重复创建报错
  const existingUser = targetDb.getUser(appUser);
  if (existingUser) {
   
    print(`业务用户 ${
     appUser} 已存在,无需重复创建`);
    return;
  }

  // 创建业务用户(仅授予 targetDbName 的读写权限,遵循最小权限原则)
  targetDb.createUser({
   
    user: appUser,
    pwd: appPwd,
    roles: [
      {
    role: "readWrite", db: targetDbName }  // 仅授予业务数据库读写权限,禁止root权限
    ]
  });
  print(`业务用户 ${
     appUser} 创建成功`);

  // 创建常用索引(优化查询性能,生产环境必备)
  // 示例1:用户表按手机号创建唯一索引
  const userCollection = targetDb.createCollection("users");
  userCollection.createIndex({
    phone: 1 }, {
    unique: true, background: true });
  print("用户表 phone 唯一索引创建成功");

  // 示例2:日志表按时间戳创建索引
  const logCollection = targetDb.createCollection("operation_logs");
  logCollection.createIndex({
    createTime: -1 }, {
    background: true });
  print("日志表 createTime 倒序索引创建成功");

  // (可选)插入测试数据
  const insertResult = targetDb.testCollection.insertOne({
    
    name: "MongoDB_Init_Test", 
    time: new Date(),
    status: "success"
  });
  if (insertResult.insertedId) {
   
    print(`测试数据插入成功,ID:${
     insertResult.insertedId}`);
  } else {
   
    print("测试数据插入失败");
  }
} catch (err) {
   
  print(`初始化脚本执行异常:${
     err.message}`);
  // 抛出异常,让容器启动失败,便于发现问题
  throw err;
}

5.2 挂载脚本并重启(结合 Docker Compose)

步骤1:确认 docker-compose.yml 已挂载脚本目录

volumes:
  - mongo-data:/data/db
  - ./initdb:/docker-entrypoint-initdb.d:ro  # 已挂载,无需重复修改

步骤2:重启容器(首次执行脚本需清空旧数据卷)

# 警告:-v 参数会删除 mongo-data 数据卷,清空所有原有数据!
# 仅首次执行初始化脚本时使用,已有业务数据请勿执行此命令
docker compose down -v  
# 重新启动容器,执行初始化脚本
docker compose up -d

步骤3:验证脚本是否生效(必做,确保初始化成功)

# 方式1:容器内用业务用户连接测试
docker exec -it mongo-dev mongosh -u ${MONGO_APP_USER} -p ${MONGO_APP_PASSWORD} --authenticationDatabase myappdb
# 查看测试数据(若输出插入的文档,说明脚本生效)
db.testCollection.find().pretty();
# 查看索引(验证索引创建成功)
db.users.getIndexes();
db.operation_logs.getIndexes();

# 方式2:检查脚本执行日志(排查失败原因)
docker logs mongo-dev | grep -E "appuser|MongoDB_Init_Test|索引创建成功"

6. 备份与恢复(开发/生产必备,优化压缩/增量备份)

新手需掌握基础备份,高级用户需结合定时任务(如 crontab),推荐用官方工具 mongodump/mongorestore

6.1 备份数据(优化版:压缩备份+增量备份+权限对齐)

方式1:压缩备份(节省存储,推荐生产使用)

# 1. 定义带时间戳的备份目录
BACKUP_TIMESTAMP=$(date +%F-%H%M%S)
HOST_BACKUP_DIR="/backup/mongo/${BACKUP_TIMESTAMP}"
mkdir -p ${HOST_BACKUP_DIR}

# 2. 容器内执行压缩备份(gzip 压缩,减少存储占用)
docker exec -it mongo-dev bash -c "
  mongodump --uri='mongodb://admin:ReplaceWithStrongRandomPwd2024!@localhost:27017' \
    --gzip \  # 启用 gzip 压缩
    --out /tmp/backup_${BACKUP_TIMESTAMP}
"

# 3. 复制压缩备份到宿主机,并对齐 UID/GID(避免权限无法访问)
docker cp mongo-dev:/tmp/backup_${BACKUP_TIMESTAMP} ${HOST_BACKUP_DIR}
chown -R $(id -u):$(id -g) ${HOST_BACKUP_DIR}  # 对齐宿主机当前用户权限
echo "压缩备份完成,存储路径:${HOST_BACKUP_DIR}"

# 4. 删除容器内临时备份
docker exec -it mongo-dev rm -rf /tmp/backup_${BACKUP_TIMESTAMP}

方式2:增量备份(基于 oplog,适合大规模数据)

# 前提:仅副本集支持增量备份(单节点无 oplog 完整日志)
# 1. 先执行一次全量备份,记录 oplog 时间点
FULL_BACKUP_DIR="/backup/mongo/full-$(date +%F)"
mkdir -p ${FULL_BACKUP_DIR}
docker exec -it mongo1 mongosh -u admin -p ReplaceWithStrongRandomPwd2024! --authenticationDatabase admin --eval '
  var backupTimestamp = new Date();
  printjson({ fullBackupTime: backupTimestamp, ts: db.getReplicationInfo().latestOpTime.ts });
' > ${FULL_BACKUP_DIR}/backup-meta.json

# 2. 执行全量备份
docker exec -it mongo1 bash -c "
  mongodump --uri='mongodb://admin:ReplaceWithStrongRandomPwd2024!@localhost:27017' \
    --gzip \
    --out /tmp/full-backup \
    --oplog  # 记录备份期间的 oplog
"
docker cp mongo1:/tmp/full-backup ${FULL_BACKUP_DIR}
chown -R $(id -u):$(id -g) ${FULL_BACKUP_DIR}

# 3. 增量备份(基于上次全量备份的 oplog 时间点)
INCR_BACKUP_DIR="/backup/mongo/incr-$(date +%F-%H%M%S)"
mkdir -p ${INCR_BACKUP_DIR}
docker exec -it mongo1 bash -c "
  mongodump --uri='mongodb://admin:ReplaceWithStrongRandomPwd2024!@localhost:27017' \
    --gzip \
    --out /tmp/incr-backup \
    --oplogReplay \  # 重放 oplog 实现增量备份
    --sinceTimestamp $(cat ${FULL_BACKUP_DIR}/backup-meta.json | grep ts | awk -F ':' '{print $2}' | tr -d ' ,')
"
docker cp mongo1:/tmp/incr-backup ${INCR_BACKUP_DIR}
chown -R $(id -u):$(id -g) ${INCR_BACKUP_DIR}
echo "增量备份完成,存储路径:${INCR_BACKUP_DIR}"

6.2 恢复数据(导入)

# 替换为你的备份目录(带时间戳)
BACKUP_DIR="/backup/mongo/2024-10-01-143000"
# 恢复前建议停止业务服务,避免数据写入冲突
mongorestore --uri="mongodb://admin:ReplaceWithStrongRandomPwd2024!@localhost:27017" \
  --gzip \  # 若备份时启用压缩,恢复时需指定
  ${BACKUP_DIR}
echo "数据恢复完成"

注意事项

  • 恢复前建议停止业务服务,避免数据写入冲突。
  • 生产环境需定期测试恢复流程(避免备份文件损坏却未发现)。
  • 备份文件建议多副本存储(本地+云存储,如阿里云OSS/腾讯云COS)。
  • 备份目录权限:确保宿主机 UID/GID 与备份文件对齐,避免后续无法读取。

7. 进阶:副本集(Replica Set)部署(高可用需求)

副本集实现高可用(故障自动转移)、读写分离,是生产环境必备配置。本节分为「基础示例(新手学习)」和「生产优化(高级工程师)」,并补充图示与跨主机部署说明。

7.1 副本集核心概念(新手了解+图示)

核心节点说明

  • 主节点(Primary):处理所有写请求,同步数据到从节点,仅1个。
  • 从节点(Secondary):同步主节点数据,处理读请求,可多个,主节点故障后自动选举升级为主节点。
  • 仲裁节点(Arbiter):仅参与投票选举,不存储数据,无复制压力,适合资源紧张场景(3节点副本集可不用)。

副本集架构图示(文字版,便于新手理解)

# 3节点副本集(无仲裁节点,推荐生产使用)
┌─────────────┐     写请求     ┌─────────────┐
│  客户端     ├───────────────>│  Primary    │
│             │                │  (mongo1)   │
└─────────────┘                └──────┬──────┘
       ▲                             │
       │ 读请求(secondaryPreferred) │ 数据同步
       │                             │
┌──────┴──────┐                ┌──────▼──────┐
│ Secondary 1 │<───────────────│ Secondary 2 │
│ (mongo2)    │                │ (mongo3)    │
└─────────────┘                └─────────────┘
# 故障转移:当 mongo1 宕机后,mongo2/mongo3 自动选举新主节点,客户端无缝切换

7.2 基础示例:3 节点副本集部署(新手学习,无安全配置)

步骤1:创建 docker-compose-replica-basic.yml

version: "3.8"
# 自定义 Docker 网络,用于副本集节点内部通信(无需依赖端口映射)
networks:
  mongo-net:
    driver: bridge  # 单机部署使用 bridge 网络,跨主机使用 overlay 网络

services:
  # 主节点(初始,后续自动选举)
  mongo1:
    image: mongo:6.0.18
    container_name: mongo1
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]  # --replSet 指定副本集名称 rs0
    ports: ["27017:27017"]  # 开发环境映射,生产环境删除
    volumes: ["mongo1-data:/data/db"]
    restart: unless-stopped
    networks: [mongo-net]  # 加入自定义内部网络
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.runCommand({ping:1})", "--quiet"]
      interval: 30s
      timeout: 5s
      retries: 3

  # 从节点1
  mongo2:
    image: mongo:6.0.18
    container_name: mongo2
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
    ports: ["27018:27017"]  # 开发环境映射,生产环境删除
    volumes: ["mongo2-data:/data/db"]
    restart: unless-stopped
    networks: [mongo-net]
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.runCommand({ping:1})", "--quiet"]
      interval: 30s
      timeout: 5s
      retries: 3

  # 从节点2
  mongo3:
    image: mongo:6.0.18
    container_name: mongo3
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
    ports: ["27019:27017"]  # 开发环境映射,生产环境删除
    volumes: ["mongo3-data:/data/db"]
    restart: unless-stopped
    networks: [mongo-net]
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.runCommand({ping:1})", "--quiet"]
      interval: 30s
      timeout: 5s
      retries: 3

volumes:
  mongo1-data:
  mongo2-data:
  mongo3-data:

步骤2:启动副本集容器

docker compose -f docker-compose-replica-basic.yml up -d

步骤3:初始化副本集(基础版)

# 等待所有节点健康运行(约10秒)
sleep 10
# 进入 mongo1 容器,执行初始化命令
docker exec -it mongo1 mongosh --eval '
  rs.initiate({
    _id: "rs0",  # 副本集名称,需与 command 中 --replSet 一致
    members: [
      { _id: 0, host: "mongo1:27017" },  # 节点1(容器名:端口,内部网络通信)
      { _id: 1, host: "mongo2:27017" },  # 节点2
      { _id: 2, host: "mongo3:27017" }   # 节点3
    ]
  })
'

步骤4:验证副本集状态

# 进入 mongo1,查看副本集状态
docker exec -it mongo1 mongosh
# 执行命令查看状态("stateStr" 为 "PRIMARY" 的是主节点,"SECONDARY" 是从节点)
rs.status()

7.3 生产优化:3 节点副本集(启用 keyfile 认证+TLS/SSL 加密)

步骤1:生成 keyfile(节点间互信密钥,生产必备)

# 1. 创建 keyfile 存储目录
mkdir -p mongo-keyfile
# 2. 生成 keyfile(256位随机字符串,MongoDB 要求)
openssl rand -base64 756 > mongo-keyfile/keyfile
# 3. 设置权限为 600(MongoDB 强制要求,否则节点启动失败)
chmod 600 mongo-keyfile/keyfile
# 4. (Linux/Mac)修改所属用户(避免容器内权限问题)
chown 999:999 mongo-keyfile/keyfile  # 999 是 mongo 容器内默认用户ID

步骤2:生成 TLS/SSL 证书(测试用自签名/生产用正式证书)

# 方式1:生成自签名证书(仅测试环境使用,生产环境请使用 CA 签发证书)
mkdir -p mongo-tls
openssl req -x509 -newkey rsa:4096 -days 365 -nodes \
  -keyout mongo-tls/mongo.key \
  -out mongo-tls/mongo.crt \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=IT/CN=mongo.rs0.local"

# 设置证书权限
chmod 600 mongo-tls/mongo.key
chown 999:999 mongo-tls/mongo.key mongo-tls/mongo.crt

# 方式2:生产环境挂载 CA 签发证书(将证书放入 mongo-tls 目录即可,无需重新生成)

步骤3:创建 docker-compose-replica-prod.yml

version: "3.8"
networks:
  mongo-net:
    driver: bridge  # 跨主机部署时改为 overlay 网络(需 Docker Swarm/K8s)

services:
  mongo1:
    image: mongo:6.0.18
    container_name: mongo1
    command: [
      "mongod", 
      "--replSet", "rs0", 
      "--bind_ip_all", 
      "--keyFile", "/etc/mongo-keyfile/keyfile",  # 挂载 keyfile
      "--authorization", "enabled",  # 启用认证
      "--sslMode", "requireSSL",  # 强制启用 TLS/SSL 加密
      "--sslPEMKeyFile", "/etc/mongo-tls/mongo.crt",  # 证书(含公钥+私钥)
      "--sslCAFile", "/etc/mongo-tls/mongo.crt",  # CA 证书(自签名证书与服务端证书一致)
      "--sslAllowInvalidCertificates"  # 测试环境允许无效证书(生产环境删除此行)
    ]
    volumes:
      - mongo1-data:/data/db
      - ./mongo-keyfile:/etc/mongo-keyfile:ro  # 只读挂载 keyfile 目录
      - ./mongo-tls:/etc/mongo-tls:ro  # 只读挂载 TLS/SSL 证书目录
    restart: always
    networks: [mongo-net]
    mem_limit: 8g
    cpus: 4
    healthcheck:
      test: ["CMD", "mongosh", "-u", "admin", "-p", "${MONGO_ROOT_PASSWORD}", "--ssl", "--eval", "db.runCommand({ping:1})", "--quiet"]
      interval: 30s
      timeout: 5s
      retries: 3
    env_file:
      - .env.prod

  mongo2:
    image: mongo:6.0.18
    container_name: mongo2
    command: [
      "mongod", 
      "--replSet", "rs0", 
      "--bind_ip_all", 
      "--keyFile", "/etc/mongo-keyfile/keyfile",
      "--authorization", "enabled",
      "--sslMode", "requireSSL",
      "--sslPEMKeyFile", "/etc/mongo-tls/mongo.crt",
      "--sslCAFile", "/etc/mongo-tls/mongo.crt",
      "--sslAllowInvalidCertificates"  # 测试环境删除,生产环境保留CA验证
    ]
    volumes:
      - mongo2-data:/data/db
      - ./mongo-keyfile:/etc/mongo-keyfile:ro
      - ./mongo-tls:/etc/mongo-tls:ro
    restart: always
    networks: [mongo-net]
    mem_limit: 8g
    cpus: 4
    healthcheck:
      test: ["CMD", "mongosh", "-u", "admin", "-p", "${MONGO_ROOT_PASSWORD}", "--ssl", "--eval", "db.runCommand({ping:1})", "--quiet"]
      interval: 30s
      timeout: 5s
      retries: 3
    env_file:
      - .env.prod

  mongo3:
    image: mongo:6.0.18
    container_name: mongo3
    command: [
      "mongod", 
      "--replSet", "rs0", 
      "--bind_ip_all", 
      "--keyFile", "/etc/mongo-keyfile/keyfile",
      "--authorization", "enabled",
      "--sslMode", "requireSSL",
      "--sslPEMKeyFile", "/etc/mongo-tls/mongo.crt",
      "--sslCAFile", "/etc/mongo-tls/mongo.crt",
      "--sslAllowInvalidCertificates"  # 测试环境删除,生产环境保留CA验证
    ]
    volumes:
      - mongo3-data:/data/db
      - ./mongo-keyfile:/etc/mongo-keyfile:ro
      - ./mongo-tls:/etc/mongo-tls:ro
    restart: always
    networks: [mongo-net]
    mem_limit: 8g
    cpus: 4
    healthcheck:
      test: ["CMD", "mongosh", "-u", "admin", "-p", "${MONGO_ROOT_PASSWORD}", "--ssl", "--eval", "db.runCommand({ping:1})", "--quiet"]
      interval: 30s
      timeout: 5s
      retries: 3
    env_file:
      - .env.prod

volumes:
  mongo1-data:
  mongo2-data:
  mongo3-data:

步骤4:创建 .env.prod 文件(生产环境敏感信息)

MONGO_INITDB_ROOT_USERNAME=admin
MONGO_ROOT_PASSWORD=ReplaceWithStrongRandomPwd2024!  # 用 openssl rand -base64 16 生成
MONGO_INITDB_DATABASE=admin
MONGO_APP_USER=appuser
MONGO_APP_PASSWORD=AppUserStrongPwd2024!

步骤5:启动并初始化生产级副本集

# 1. 启动容器
docker compose -f docker-compose-replica-prod.yml up -d
# 2. 等待节点健康运行
sleep 10
# 3. 初始化副本集(启用 keyfile 认证+SSL)
docker exec -it mongo1 mongosh -u admin -p ReplaceWithStrongRandomPwd2024! --authenticationDatabase admin --ssl --eval '
  rs.initiate({
    _id: "rs0",
    keyFile: "/etc/mongo-keyfile/keyfile",  # 指定 keyfile 路径
    members: [
      { _id: 0, host: "mongo1:27017" },
      { _id: 1, host: "mongo2:27017" },
      { _id: 2, host: "mongo3:27017" }
    ]
  })
'
# 4. 验证副本集状态
docker exec -it mongo1 mongosh -u admin -p ReplaceWithStrongRandomPwd2024! --authenticationDatabase admin --ssl
rs.status()

步骤6:跨机房/跨宿主机部署注意事项

  1. 网络配置:Docker bridge 网络仅支持单机通信,跨宿主机需使用 Docker Swarm overlay 网络Kubernetes Service,确保节点间能访问 27017 端口。
  2. Hostname/DNS 配置:副本集节点地址需使用可解析的 hostname 或固定 IP,避免容器重启后 IP 变化导致同步失败。
  3. 资源隔离:不同宿主机需配置相同的资源限制(CPU/内存),避免节点性能差异导致选举异常。
  4. 容灾策略:3 个节点尽量分布在 2-3 个机房,避免单机房断电导致整个副本集不可用。
  5. 防火墙配置:仅开放节点间 27017 端口通信,禁止公网访问。

8. 生产环境核心注意事项

8.1 安全第一(重中之重)

  1. 严禁暴露 27017 端口到公网(用内网、VPN 或反向代理(如 Nginx)访问)。
  2. 启用认证(root 用户+业务用户分离,最小权限原则):
    • root 用户仅用于运维操作(备份/恢复/节点管理),禁止业务系统直接使用。
    • 业务用户仅授予对应业务数据库的读写权限,禁止授予 root/dbOwner 等高权限。
  3. 开启 TLS/SSL 加密(客户端与服务器、节点间通信均加密):
    • 生产环境使用 CA 签发的有效证书,禁止使用自签名证书。
    • 证书定期更换(建议每 1 年),并备份旧证书避免切换异常。
  4. 密码管理:
    • 强随机密码(长度≥16位,包含大小写字母、数字、特殊字符)。
    • 特殊字符处理:YAML 配置中用单引号包裹密码(如 'P@ssw0rd!123'),Shell 中用转义符(如 P\@ssw0rd\!123)。
    • 定期更换密码(建议每 90 天),更换时先更新 .env 文件,再重启容器。
  5. keyfile 权限严格设置为 600,仅授权运维用户访问,避免泄露;所有节点的 keyfile 内容必须一致。
  6. .envmongo-keyfilemongo-tls 等敏感文件添加到 .gitignore,禁止提交到版本库。

8.2 高可用保障

  1. 副本集至少 3 节点(1 主 2 从),跨机房部署(应对机房断电)。
  2. 配置 --restart always,确保容器异常后自动重启。
  3. 启用健康检查,及时发现服务不可用状态。
  4. 避免单点故障:数据卷使用持久化存储,备份文件多副本存储。
  5. 读写分离:客户端连接时指定 readPreference: "secondaryPreferred",将读请求分流到从节点,减轻主节点压力。

8.3 备份策略

  1. 每日自动备份(用 crontab 定时执行 mongodump),备份文件带时间戳,避免覆盖。
    # 添加 crontab 定时任务(每天凌晨 2 点执行压缩备份)
    crontab -e
    # 写入以下内容
    0 2 * * * /bin/bash /backup/mongo-backup-script.sh >> /var/log/mongo-backup.log 2>&1
    
  2. 备份文件存多份(本地+云存储),保留 30 天备份历史,过期自动清理。
  3. 每月测试恢复流程(确保备份可用,避免备份损坏未发现)。
  4. 大规模数据优先使用增量备份,减少备份时间与存储占用。

8.4 监控与告警(优化版:oplog 滞后监控+指标对应表)

  1. 部署监控工具:Prometheus + Grafana(监控 CPU、内存、磁盘 IO、连接数、oplog 滞后)。
  2. 简单监控配置示例(Prometheus + Grafana):
    • 步骤1:部署 MongoDB Exporter
      docker run -d \
        --name mongo-exporter \
        --net mongo-net \
        -e MONGODB_URI="mongodb://admin:ReplaceWithStrongPwd!@mongo1:27017?ssl=true" \
        prom/mongodb-exporter:latest
      
    • 步骤2:Prometheus 配置目标(添加到 prometheus.yml)
      scrape_configs:
        - job_name: 'mongodb'
          static_configs:
            - targets: ['mongo-exporter:9216']
      
    • 步骤3:Grafana 导入 MongoDB 监控仪表盘(ID:10494)
  3. oplog 滞后监控告警
    • 监控指标:mongodb_replset_member_optime_date_seconds(主从节点 oplog 时间差)。
    • 告警阈值:主从延迟 > 10s 触发警告,> 30s 触发紧急告警。
    • 手动查询滞后:rs.secondaryLag()(在主节点执行,返回从节点最大滞后时间)。
  4. 容器指标与 MongoDB 指标对应关系表
    | 容器指标(Docker) | MongoDB 内部指标 | 监控意义 | 告警阈值 |
    |--------------------|------------------|----------|----------|
    | CPU 使用率 | db.serverStatus().cpu | 节点计算压力 | > 80%(持续5分钟) |
    | 内存使用率 | db.serverStatus().mem | 内存占用情况 | > 90%(持续5分钟) |
    | 磁盘 IO 吞吐量 | db.serverStatus().diskIO | 存储读写压力 | > 80% 磁盘带宽 |
    | 网络吞吐量 | db.serverStatus().network | 节点间通信压力 | > 100MB/s(持续5分钟) |
    | 容器重启次数 | docker inspect | 节点稳定性 | > 3 次/小时 |

8.5 资源与性能

  1. 给容器配置资源限制(--memory/--cpus),避免占用宿主机全部资源。
  2. 优化内核参数:
    • 关闭 Transparent Huge Pages(THP):echo never > /sys/kernel/mm/transparent_hugepage/enabled
    • 增大文件描述符限制:ulimit -n 65535(永久生效需修改 /etc/security/limits.conf
  3. 合理设计索引,避免全集合扫描,定期优化聚合查询。
  4. 扩容 oplog 大小:默认 oplog 仅占磁盘 5%,生产环境可扩容至 10%-20%,避免从节点同步失败。

9. 常见问题排查(补充优化)

9.1 容器启动失败

  • 排查方法:查看日志 docker logs -f mongo-dev,常见原因:
    1. 端口被占用:netstat -tuln | grep 27017,杀死占用进程或换端口。
    2. 数据卷权限:用 named volume 替代宿主目录挂载(新手推荐),或执行 chmod 777 /path/on/host(临时测试,生产不推荐)。
    3. 密码含特殊字符:用单引号包裹密码,或通过 .env 文件加载。
    4. keyfile 权限错误:确保 keyfile 权限为 600,所属用户为 999(mongo 容器默认用户)。
    5. TLS 证书错误:确保证书文件存在且权限为 600,自签名证书需添加 --sslAllowInvalidCertificates 参数。

9.2 MONGOINITDB* 环境变量无效

  • 原因:仅首次初始化(数据卷为空)时生效,已有数据的卷不会重新执行。
  • 解决:删除旧数据卷 docker volume rm 项目名_mongo-data,重新启动容器(注意备份数据)。

9.3 初始化脚本不执行

  • 原因:数据卷非空,或脚本挂载路径错误,或脚本权限问题。
  • 解决:
    1. 删除旧数据卷 docker compose down -v
    2. 检查脚本挂载路径是否为 /docker-entrypoint-initdb.d
    3. 确保脚本后缀为 .js,权限为可读。
    4. 查看容器日志 docker logs mongo-dev,排查脚本执行异常。

9.4 副本集从节点无法同步数据

  • 排查步骤:
    1. 查看主节点 oplog 大小:use local; db.oplog.rs.stats().size(确保 oplog 足够大,默认仅存 24 小时数据)。
    2. 检查节点间网络:docker exec -it mongo1 ping mongo2(确保容器间能通信)。
    3. 确认 keyfile 配置:所有节点的 keyfile 内容必须一致,权限为 600。
    4. 查看节点日志:docker logs mongo2,排查认证或同步错误。
    5. 检查副本集配置:rs.conf(),确保节点地址正确且状态为 UP

9.5 副本集主节点切换异常

  • 常见原因:节点性能差异、网络延迟、投票数不足。
  • 排查步骤:
    1. 查看节点状态:rs.status(),确认是否有节点状态为 DOWNRECOVERING
    2. 检查节点日志:docker logs mongo1(查看选举失败原因)。
    3. 确认副本集投票数:3 节点副本集需至少 2 个节点正常运行才能完成选举。
    4. 恢复故障节点:重启故障容器,或重新添加节点到副本集(rs.add("mongo2:27017"))。

9.6 资源瓶颈导致 MongoDB 卡顿

  • 排查步骤:
    1. 内存瓶颈docker stats mongo-dev 查看内存使用率,若接近 100%,需扩容内存或优化查询。
    2. CPU 瓶颈:查看 CPU 使用率,若持续 > 80%,需排查慢查询(db.currentOp())或扩容 CPU。
    3. IO 瓶颈iostat -x 1 查看磁盘 IO 使用率,若 %util > 90%,需更换 SSD 或优化索引。
    4. 慢查询优化:开启慢查询日志(db.setProfilingLevel(1, { slowms: 100 })),排查并优化耗时查询。

9.7 连接超时

  • 新手:检查容器是否运行(docker ps)、端口是否映射(docker port mongo-dev)、防火墙是否开放端口。
  • 高级用户:检查防火墙(ufw statusiptables -L)、TLS 证书是否正确、副本集节点地址是否可访问、内部网络是否连通。

10. 后续学习路径

  • 新手:先熟悉单节点操作(创建集合、插入/查询数据)→ 学习 MongoDB 基本语法(参考 MongoDB 基础教程 https://www.mongodb.com/docs/manual/tutorial/getting-started)→ 尝试初始化脚本自定义数据。
  • 高级工程师:深入副本集原理→ 学习分片集群部署(应对 TB 级数据)→ 优化索引与聚合查询性能→ 掌握生产级监控与故障排查→ 实现 MongoDB 与业务系统的无缝集成。

附录

附录1:常用命令速查表

操作类型 命令示例 说明
容器启动 docker compose up -d 后台启动 MongoDB 容器
容器停止 docker compose down 停止并删除容器(保留数据卷)
容器停止(删除数据卷) docker compose down -v 停止容器并删除数据卷(谨慎使用)
查看容器状态 `docker ps grep mongo` 查看 MongoDB 容器运行状态与健康状态
查看容器日志 docker logs -f mongo-dev 实时查看容器日志(排查故障)
进入容器交互终端 docker exec -it mongo-dev bash 进入 MongoDB 容器内部
连接 MongoDB(容器内) docker exec -it mongo-dev mongosh -u admin -p 密码 --authenticationDatabase admin 无需本地安装 mongosh,直接连接
查看 MongoDB 版本 docker exec -it mongo-dev mongosh --eval 'db.version()' 快速查看 MongoDB 版本
备份数据(压缩) docker exec -it mongo-dev mongodump --uri=xxx --gzip --out /tmp/backup 容器内执行压缩备份
恢复数据(压缩) mongorestore --uri=xxx --gzip 备份目录 恢复 gzip 压缩的备份数据
查看副本集状态 docker exec -it mongo1 mongosh -u admin -p 密码 --ssl --eval 'rs.status()' 查看生产级副本集状态
查看慢查询 docker exec -it mongo-dev mongosh -u admin -p 密码 --eval 'db.currentOp({ "secs_running": { "$gt": 1 } })' 排查运行超过 1 秒的慢查询

附录2:.env.example 模板

# 复制此文件为 .env,修改为实际配置
# 生成强密码命令:openssl rand -base64 16
MONGO_INITDB_ROOT_USERNAME=admin
MONGO_INITDB_ROOT_PASSWORD=ReplaceWithStrongRandomPwd2024!
MONGO_INITDB_DATABASE=myappdb
MONGO_APP_USER=appuser
MONGO_APP_PASSWORD=AppUserStrongPwd2024!
MONGO_MEMORY_LIMIT=4g
MONGO_CPU_LIMIT=2

附录3:.env.prod.example 模板

# 生产环境环境变量模板
MONGO_INITDB_ROOT_USERNAME=admin
MONGO_ROOT_PASSWORD=ReplaceWithStrongRandomPwd2024!
MONGO_INITDB_DATABASE=admin
MONGO_APP_USER=appuser
MONGO_APP_PASSWORD=AppUserStrongPwd2024!
MONGO_MEMORY_LIMIT=8g
MONGO_CPU_LIMIT=4
目录
相关文章
|
2月前
|
消息中间件 存储 运维
RocketMQ监控与运维实战:从底层原理到生产落地全解析
本文深入解析RocketMQ监控与运维体系,涵盖核心架构、关键指标、实战工具及生产最佳实践,助你构建高可用消息系统。
187 4
|
网络协议 Linux 虚拟化
桥接方式: vmware虚拟机安装的centos7连接外网教程
桥接方式: vmware虚拟机安装的centos7连接外网教程
1854 0
桥接方式: vmware虚拟机安装的centos7连接外网教程
|
9月前
|
存储 关系型数据库 MySQL
大数据新视界--大数据大厂之MySQL 数据库课程设计:开启数据宇宙的传奇之旅
本文全面剖析数据库课程设计 MySQL,展现其奇幻魅力与严峻挑战。通过实际案例凸显数据库设计重要性,详述数据安全要点及学习目标。深入阐述备份与恢复方法,并分享优秀实践项目案例。为开发者提供 MySQL 数据库课程设计的全面指南,助力提升数据库设计与管理能力,保障数据安全稳定。
大数据新视界--大数据大厂之MySQL 数据库课程设计:开启数据宇宙的传奇之旅
|
4月前
|
存储 SQL 运维
速看!数据库与数据仓库的本质区别是什么?
本文深入解析了“数据库”与“数据仓库”的核心区别,涵盖设计目的、数据结构、使用场景、性能优化和数据更新五个维度。数据库主要用于支持实时业务操作,强调事务处理效率;数据仓库则面向企业分析决策,注重海量数据的整合与查询性能。二者在企业中各司其职,缺一不可。
|
4月前
|
NoSQL IDE MongoDB
Studio 3T 2025.17 (macOS, Linux, Windows) - MongoDB 的终极 GUI、IDE 和 客户端
Studio 3T 2025.17 (macOS, Linux, Windows) - MongoDB 的终极 GUI、IDE 和 客户端
344 1
Studio 3T 2025.17 (macOS, Linux, Windows) - MongoDB 的终极 GUI、IDE 和 客户端
|
算法 关系型数据库 数据库
德哥的PostgreSQL私房菜 - 史上最屌PG资料合集
看完并理解这些文章,相信你会和我一样爱上PostgreSQL,并成为PostgreSQL的布道者。 沉稳的外表无法掩饰PG炙热的内心 。 扩展阅读,用心感受PostgreSQL 内核扩展 《找对业务G点, 体验酸爽 - PostgreSQL内核扩展指南》https://yq.
59117 152
|
NoSQL Java Redis
深入理解Servlet Filter及其限流实践
深入理解Servlet Filter及其限流实践
354 44
|
Java 开发工具 git
【Python】已解决:ERROR: No matching distribution found for JPype1
【Python】已解决:ERROR: No matching distribution found for JPype1
1094 0
|
网络协议 Linux 开发工具
Centos7 /etc/sysconfig/network-scripts/ifcfg-<interface>网络配置
自动化网络配置:NetworkManager 可以自动检测网络连接,并根据网络环境自动配置网络。这使得用户可以无需手动配置即可连接到网络。 支持多种网络连接:NetworkManager 支持多种网络连接,包括有线、无线、VPN、Wi-Fi 热点等。这使得用户可以根据需要选择合适的网络连接。 提供图形化和命令行工具:NetworkManager 提供了图形化工具和命令行工具,用户可以根据自己的喜好选择使用。
1678 4
|
安全 Linux 网络安全
NAT模式下主机连接虚拟机
NAT模式下主机连接虚拟机,VMware虚拟机系统以CentOS7为例。
1217 0