適用讀者及版本説明
適用讀者
- 新手開發者:快速搭建 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 生產環境核心差異(一目瞭然)
|
對比項
|
開發/測試環境
|
生產環境
|
|
端口映射
|
啓用 |
禁用公網映射,使用內網/VPN/反向代理
|
|
密碼管理
|
可臨時使用簡單密碼(需標註)
|
強隨機密碼+ |
|
資源限制
|
可選配置
|
必須配置( |
|
數據持久化
|
Docker named volume
|
持久化卷+多副本備份
|
|
健康檢查
|
可選啓用
|
必須啓用
|
|
自動重啓
|
啓用 |
啓用 |
單節點適合開發、測試場景,提供兩種部署方式: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
若輸出包含 Up 和 healthy(如 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:跨機房/跨宿主機部署注意事項
- 網絡配置:Docker bridge 網絡僅支持單機通信,跨宿主機需使用 Docker Swarm overlay 網絡 或 Kubernetes Service,確保節點間能訪問 27017 端口。
- Hostname/DNS 配置:副本集節點地址需使用可解析的 hostname 或固定 IP,避免容器重啓後 IP 變化導致同步失敗。
- 資源隔離:不同宿主機需配置相同的資源限制(CPU/內存),避免節點性能差異導致選舉異常。
- 容災策略:3 個節點儘量分佈在 2-3 個機房,避免單機房斷電導致整個副本集不可用。
- 防火牆配置:僅開放節點間 27017 端口通信,禁止公網訪問。
8. 生產環境核心注意事項
8.1 安全第一(重中之重)
- 嚴禁暴露 27017 端口到公網(用內網、VPN 或反向代理(如 Nginx)訪問)。
- 啓用認證(root 用户+業務用户分離,最小權限原則):
- root 用户僅用於運維操作(備份/恢復/節點管理),禁止業務系統直接使用。
- 業務用户僅授予對應業務數據庫的讀寫權限,禁止授予
root/dbOwner等高權限。
- 開啓 TLS/SSL 加密(客户端與服務器、節點間通信均加密):
- 生產環境使用 CA 簽發的有效證書,禁止使用自簽名證書。
- 證書定期更換(建議每 1 年),並備份舊證書避免切換異常。
- 密碼管理:
- 強隨機密碼(長度≥16位,包含大小寫字母、數字、特殊字符)。
- 特殊字符處理:YAML 配置中用單引號包裹密碼(如
'P@ssw0rd!123'),Shell 中用轉義符(如P\@ssw0rd\!123)。 - 定期更換密碼(建議每 90 天),更換時先更新 .env 文件,再重啓容器。
- keyfile 權限嚴格設置為 600,僅授權運維用户訪問,避免泄露;所有節點的 keyfile 內容必須一致。
- 將
.env、mongo-keyfile、mongo-tls等敏感文件添加到.gitignore,禁止提交到版本庫。
8.2 高可用保障
- 副本集至少 3 節點(1 主 2 從),跨機房部署(應對機房斷電)。
- 配置
--restart always,確保容器異常後自動重啓。 - 啓用健康檢查,及時發現服務不可用狀態。
- 避免單點故障:數據卷使用持久化存儲,備份文件多副本存儲。
- 讀寫分離:客户端連接時指定
readPreference: "secondaryPreferred",將讀請求分流到從節點,減輕主節點壓力。
8.3 備份策略
- 每日自動備份(用 crontab 定時執行
mongodump),備份文件帶時間戳,避免覆蓋。
# 添加 crontab 定時任務(每天凌晨 2 點執行壓縮備份)
crontab -e
# 寫入以下內容
0 2 * * * /bin/bash /backup/mongo-backup-script.sh >> /var/log/mongo-backup.log 2>&1
- 備份文件存多份(本地+雲存儲),保留 30 天備份歷史,過期自動清理。
- 每月測試恢復流程(確保備份可用,避免備份損壞未發現)。
- 大規模數據優先使用增量備份,減少備份時間與存儲佔用。
8.4 監控與告警(優化版:oplog 滯後監控+指標對應表)
- 部署監控工具:Prometheus + Grafana(監控 CPU、內存、磁盤 IO、連接數、oplog 滯後)。
- 簡單監控配置示例(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)
- oplog 滯後監控告警:
- 監控指標:
mongodb_replset_member_optime_date_seconds(主從節點 oplog 時間差)。 - 告警閾值:主從延遲 > 10s 觸發警告,> 30s 觸發緊急告警。
- 手動查詢滯後:
rs.secondaryLag()(在主節點執行,返回從節點最大滯後時間)。
- 容器指標與 MongoDB 指標對應關係表
|
容器指標(Docker)
|
MongoDB 內部指標
|
監控意義
|
告警閾值
|
|
CPU 使用率
|
|
節點計算壓力
|
> 80%(持續5分鐘)
|
|
內存使用率
|
|
內存佔用情況
|
> 90%(持續5分鐘)
|
|
磁盤 IO 吞吐量
|
|
存儲讀寫壓力
|
> 80% 磁盤帶寬
|
|
網絡吞吐量
|
|
節點間通信壓力
|
> 100MB/s(持續5分鐘)
|
|
容器重啓次數
|
|
節點穩定性
|
> 3 次/小時
|
8.5 資源與性能
- 給容器配置資源限制(
--memory/--cpus),避免佔用宿主機全部資源。 - 優化內核參數:
- 關閉 Transparent Huge Pages(THP):
echo never > /sys/kernel/mm/transparent_hugepage/enabled - 增大文件描述符限制:
ulimit -n 65535(永久生效需修改/etc/security/limits.conf)
- 合理設計索引,避免全集合掃描,定期優化聚合查詢。
- 擴容 oplog 大小:默認 oplog 僅佔磁盤 5%,生產環境可擴容至 10%-20%,避免從節點同步失敗。
9. 常見問題排查(補充優化)
9.1 容器啓動失敗
- 排查方法:查看日誌
docker logs -f mongo-dev,常見原因:
- 端口被佔用:
netstat -tuln | grep 27017,殺死佔用進程或換端口。 - 數據卷權限:用
named volume替代宿主目錄掛載(新手推薦),或執行chmod 777 /path/on/host(臨時測試,生產不推薦)。 - 密碼含特殊字符:用單引號包裹密碼,或通過
.env文件加載。 - keyfile 權限錯誤:確保 keyfile 權限為 600,所屬用户為 999(mongo 容器默認用户)。
- TLS 證書錯誤:確保證書文件存在且權限為 600,自簽名證書需添加
--sslAllowInvalidCertificates參數。
9.2 MONGO_INITDB_* 環境變量無效
- 原因:僅**首次初始化(數據卷為空)**時生效,已有數據的卷不會重新執行。
- 解決:刪除舊數據卷
docker volume rm 項目名_mongo-data,重新啓動容器(注意備份數據)。
9.3 初始化腳本不執行
- 原因:數據卷非空,或腳本掛載路徑錯誤,或腳本權限問題。
- 解決:
- 刪除舊數據卷
docker compose down -v。 - 檢查腳本掛載路徑是否為
/docker-entrypoint-initdb.d。 - 確保腳本後綴為
.js,權限為可讀。 - 查看容器日誌
docker logs mongo-dev,排查腳本執行異常。
9.4 副本集從節點無法同步數據
- 排查步驟:
- 查看主節點 oplog 大小:
use local; db.oplog.rs.stats().size(確保 oplog 足夠大,默認僅存 24 小時數據)。 - 檢查節點間網絡:
docker exec -it mongo1 ping mongo2(確保容器間能通信)。 - 確認 keyfile 配置:所有節點的 keyfile 內容必須一致,權限為 600。
- 查看節點日誌:
docker logs mongo2,排查認證或同步錯誤。 - 檢查副本集配置:
rs.conf(),確保節點地址正確且狀態為UP。
9.5 副本集主節點切換異常
- 常見原因:節點性能差異、網絡延遲、投票數不足。
- 排查步驟:
- 查看節點狀態:
rs.status(),確認是否有節點狀態為DOWN或RECOVERING。 - 檢查節點日誌:
docker logs mongo1(查看選舉失敗原因)。 - 確認副本集投票數:3 節點副本集需至少 2 個節點正常運行才能完成選舉。
- 恢復故障節點:重啓故障容器,或重新添加節點到副本集(
rs.add("mongo2:27017"))。
9.6 資源瓶頸導致 MongoDB 卡頓
- 排查步驟:
- 內存瓶頸:
docker stats mongo-dev查看內存使用率,若接近 100%,需擴容內存或優化查詢。 - CPU 瓶頸:查看 CPU 使用率,若持續 > 80%,需排查慢查詢(
db.currentOp())或擴容 CPU。 - IO 瓶頸:
iostat -x 1查看磁盤 IO 使用率,若 %util > 90%,需更換 SSD 或優化索引。 - 慢查詢優化:開啓慢查詢日誌(
db.setProfilingLevel(1, { slowms: 100 })),排查並優化耗時查詢。
9.7 連接超時
- 新手:檢查容器是否運行(
docker ps)、端口是否映射(docker port mongo-dev)、防火牆是否開放端口。 - 高級用户:檢查防火牆(
ufw status或iptables -L)、TLS 證書是否正確、副本集節點地址是否可訪問、內部網絡是否連通。
10. 後續學習路徑
- 新手:先熟悉單節點操作(創建集合、插入/查詢數據)→ 學習 MongoDB 基本語法(參考 MongoDB 基礎教程
https://www.mongodb.com/docs/manual/tutorial/getting-started)→ 嘗試初始化腳本自定義數據。 - 高級工程師:深入副本集原理→ 學習分片集羣部署(應對 TB 級數據)→ 優化索引與聚合查詢性能→ 掌握生產級監控與故障排查→ 實現 MongoDB 與業務系統的無縫集成。
附錄
附錄1:常用命令速查表
|
操作類型
|
命令示例
|
説明
|
|
容器啓動
|
|
後台啓動 MongoDB 容器
|
|
容器停止
|
|
停止並刪除容器(保留數據卷)
|
|
容器停止(刪除數據卷)
|
|
停止容器並刪除數據卷(謹慎使用)
|
|
查看容器狀態
|
`docker ps
|
grep mongo`
|
|
查看容器日誌
|
|
實時查看容器日誌(排查故障)
|
|
進入容器交互終端
|
|
進入 MongoDB 容器內部
|
|
連接 MongoDB(容器內)
|
|
無需本地安裝 mongosh,直接連接
|
|
查看 MongoDB 版本
|
|
快速查看 MongoDB 版本
|
|
備份數據(壓縮)
|
|
容器內執行壓縮備份
|
|
恢復數據(壓縮)
|
|
恢復 gzip 壓縮的備份數據
|
|
查看副本集狀態
|
|
查看生產級副本集狀態
|
|
查看慢查詢
|
|
排查運行超過 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