適用讀者及版本説明

適用讀者

  • 新手開發者:快速搭建 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+

基於 Docker 的 MongoDB 部署與使用指南_MongoDB 部署文檔

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 等高權限。
  1. 開啓 TLS/SSL 加密(客户端與服務器、節點間通信均加密):
  • 生產環境使用 CA 簽發的有效證書,禁止使用自簽名證書。
  • 證書定期更換(建議每 1 年),並備份舊證書避免切換異常。
  1. 密碼管理:
  • 強隨機密碼(長度≥16位,包含大小寫字母、數字、特殊字符)。
  • 特殊字符處理:YAML 配置中用單引號包裹密碼(如 'P@ssw0rd!123'),Shell 中用轉義符(如 P\@ssw0rd\!123)。
  • 定期更換密碼(建議每 90 天),更換時先更新 .env 文件,再重啓容器。
  1. keyfile 權限嚴格設置為 600,僅授權運維用户訪問,避免泄露;所有節點的 keyfile 內容必須一致。
  2. .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
  1. 備份文件存多份(本地+雲存儲),保留 30 天備份歷史,過期自動清理。
  2. 每月測試恢復流程(確保備份可用,避免備份損壞未發現)。
  3. 大規模數據優先使用增量備份,減少備份時間與存儲佔用。

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)
  1. oplog 滯後監控告警
  • 監控指標:mongodb_replset_member_optime_date_seconds(主從節點 oplog 時間差)。
  • 告警閾值:主從延遲 > 10s 觸發警告,> 30s 觸發緊急告警。
  • 手動查詢滯後:rs.secondaryLag()(在主節點執行,返回從節點最大滯後時間)。
  1. 容器指標與 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
  1. 合理設計索引,避免全集合掃描,定期優化聚合查詢。
  2. 擴容 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 MONGO_INITDB_* 環境變量無效

  • 原因:僅**首次初始化(數據卷為空)**時生效,已有數據的卷不會重新執行。
  • 解決:刪除舊數據卷 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`

查看容器日誌

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