Docker 部署 MongoDB
快速启动
# 基本运行
docker run -d --name mongodb -p 27017:27017 mongo:7
# 带认证
docker run -d \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=your_password \
mongo:7
# 带数据持久化
docker run -d \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=your_password \
-v mongodb_data:/data/db \
-v mongodb_config:/data/configdb \
mongo:7
Docker Compose 部署
- 基础配置
- 生产配置
- 带 Web 管理界面
version: '3.8'
services:
mongodb:
image: mongo:7
container_name: mongodb
restart: always
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: your_password
MONGO_INITDB_DATABASE: mydb
TZ: Asia/Shanghai
volumes:
- mongodb_data:/data/db
- mongodb_config:/data/configdb
volumes:
mongodb_data:
mongodb_config:
version: '3.8'
services:
mongodb:
image: mongo:7
container_name: mongodb
restart: always
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD}
MONGO_INITDB_DATABASE: ${MONGO_DATABASE:-mydb}
TZ: Asia/Shanghai
volumes:
- mongodb_data:/data/db
- mongodb_config:/data/configdb
- ./mongod.conf:/etc/mongod.conf
- ./init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js
command: ["--config", "/etc/mongod.conf"]
healthcheck:
test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet
interval: 10s
timeout: 5s
retries: 5
start_period: 40s
volumes:
mongodb_data:
mongodb_config:
version: '3.8'
services:
mongodb:
image: mongo:7
container_name: mongodb
restart: always
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: your_password
volumes:
- mongodb_data:/data/db
mongo-express:
image: mongo-express:latest
container_name: mongo-express
restart: always
ports:
- "8081:8081"
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: admin
ME_CONFIG_MONGODB_ADMINPASSWORD: your_password
ME_CONFIG_MONGODB_URL: mongodb://admin:your_password@mongodb:27017/
ME_CONFIG_BASICAUTH_USERNAME: admin
ME_CONFIG_BASICAUTH_PASSWORD: admin123
depends_on:
- mongodb
volumes:
mongodb_data:
自定义配置
mongod.conf
# 网络配置
net:
port: 27017
bindIp: 0.0.0.0
# 存储配置
storage:
dbPath: /data/db
journal:
enabled: true
wiredTiger:
engineConfig:
cacheSizeGB: 1
journalCompressor: snappy
collectionConfig:
blockCompressor: snappy
indexConfig:
prefixCompression: true
# 系统日志
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
logRotate: reopen
# 进程管理
processManagement:
timeZoneInfo: /usr/share/zoneinfo
# 安全配置
security:
authorization: enabled
# 操作分析
operationProfiling:
mode: slowOp
slowOpThresholdMs: 100
# 复制集配置(如需要)
# replication:
# replSetName: rs0
初始化脚本 (init-mongo.js)
// 切换到管理数据库
db = db.getSiblingDB('admin');
// 创建应用数据库
db = db.getSiblingDB('mydb');
// 创建应用用户
db.createUser({
user: 'app_user',
pwd: 'app_password',
roles: [
{
role: 'readWrite',
db: 'mydb'
}
]
});
// 创建只读用户
db.createUser({
user: 'readonly_user',
pwd: 'readonly_password',
roles: [
{
role: 'read',
db: 'mydb'
}
]
});
// 创建集合
db.createCollection('users');
db.createCollection('orders');
db.createCollection('products');
// 创建索引
db.users.createIndex({ email: 1 }, { unique: true });
db.users.createIndex({ username: 1 }, { unique: true });
db.orders.createIndex({ userId: 1, createdAt: -1 });
db.products.createIndex({ category: 1, price: 1 });
print('MongoDB initialization completed');
常用命令
# 连接 MongoDB
docker exec -it mongodb mongosh
# 带认证连接
docker exec -it mongodb mongosh -u admin -p your_password --authenticationDatabase admin
# 连接到指定数据库
docker exec -it mongodb mongosh -u app_user -p app_password --authenticationDatabase mydb mydb
# 查看日志
docker logs mongodb
docker logs -f mongodb --tail 100
# 查看统计信息
docker exec mongodb mongosh --eval "db.serverStatus()" --quiet
# 导出数据库
docker exec mongodb mongodump --db mydb --out /backup
# 导入数据库
docker exec mongodb mongorestore /backup
备份与恢复
备份
- mongodump 备份
- 自动备份脚本
# 备份单个数据库
docker exec mongodb mongodump \
--db mydb \
--out /backup/$(date +%Y%m%d_%H%M%S)
# 备份所有数据库
docker exec mongodb mongodump \
--out /backup/all_$(date +%Y%m%d_%H%M%S)
# 带认证备份
docker exec mongodb mongodump \
--username admin \
--password your_password \
--authenticationDatabase admin \
--db mydb \
--out /backup/mydb_$(date +%Y%m%d_%H%M%S)
# 备份指定集合
docker exec mongodb mongodump \
--db mydb \
--collection users \
--out /backup/users_$(date +%Y%m%d_%H%M%S)
# 压缩备份
docker exec mongodb mongodump \
--db mydb \
--archive=/backup/mydb_$(date +%Y%m%d_%H%M%S).archive \
--gzip
#!/bin/bash
# backup-mongodb.sh
BACKUP_DIR="/backup/mongodb"
MONGO_USER="admin"
MONGO_PASSWORD="your_password"
MONGO_AUTH_DB="admin"
CONTAINER_NAME="mongodb"
RETENTION_DAYS=7
# 创建备份目录
mkdir -p $BACKUP_DIR
# 生成备份文件名
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="backup_$TIMESTAMP"
# 执行备份
docker exec $CONTAINER_NAME mongodump \
--username $MONGO_USER \
--password $MONGO_PASSWORD \
--authenticationDatabase $MONGO_AUTH_DB \
--out /backup/$BACKUP_NAME
# 复制备份到主机
docker cp $CONTAINER_NAME:/backup/$BACKUP_NAME $BACKUP_DIR/
# 压缩备份
cd $BACKUP_DIR
tar -czf ${BACKUP_NAME}.tar.gz $BACKUP_NAME
rm -rf $BACKUP_NAME
# 检查备份是否成功
if [ $? -eq 0 ]; then
echo "$(date): Backup successful - ${BACKUP_NAME}.tar.gz"
# 删除旧备份
find $BACKUP_DIR -name "backup_*.tar.gz" -mtime +$RETENTION_DAYS -delete
echo "$(date): Old backups removed (older than $RETENTION_DAYS days)"
else
echo "$(date): Backup failed!"
exit 1
fi
添加到 crontab:
# 每天凌晨 3 点自动备份
0 3 * * * /path/to/backup-mongodb.sh >> /var/log/mongodb-backup.log 2>&1
恢复
# 恢复整个数据库
docker exec mongodb mongorestore \
--username admin \
--password your_password \
--authenticationDatabase admin \
/backup/20240101_120000
# 恢复指定数据库
docker exec mongodb mongorestore \
--username admin \
--password your_password \
--authenticationDatabase admin \
--db mydb \
/backup/20240101_120000/mydb
# 从归档文件恢复
docker exec mongodb mongorestore \
--username admin \
--password your_password \
--authenticationDatabase admin \
--archive=/backup/mydb_20240101_120000.archive \
--gzip
# 恢复到不同的数据库
docker exec mongodb mongorestore \
--username admin \
--password your_password \
--authenticationDatabase admin \
--db newdb \
/backup/20240101_120000/mydb
# 恢复指定集合
docker exec mongodb mongorestore \
--username admin \
--password your_password \
--authenticationDatabase admin \
--db mydb \
--collection users \
/backup/20240101_120000/mydb/users.bson
副本集(Replica Set)
version: '3.8'
services:
mongo1:
image: mongo:7
container_name: mongo1
restart: always
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: your_password
volumes:
- mongo1_data:/data/db
- mongo1_config:/data/configdb
command: mongod --replSet rs0 --bind_ip_all
mongo2:
image: mongo:7
container_name: mongo2
restart: always
ports:
- "27018:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: your_password
volumes:
- mongo2_data:/data/db
- mongo2_config:/data/configdb
command: mongod --replSet rs0 --bind_ip_all
mongo3:
image: mongo:7
container_name: mongo3
restart: always
ports:
- "27019:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: your_password
volumes:
- mongo3_data:/data/db
- mongo3_config:/data/configdb
command: mongod --replSet rs0 --bind_ip_all
volumes:
mongo1_data:
mongo1_config:
mongo2_data:
mongo2_config:
mongo3_data:
mongo3_config:
初始化副本集
# 连接到主节点
docker exec -it mongo1 mongosh -u admin -p your_password
# 初始化副本集
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 }
]
})
# 查看副本集状态
rs.status()
# 查看副本集配置
rs.conf()
MongoDB Shell 常用操作
// ========== 数据库操作 ==========
// 显示所有数据库
show dbs
// 切换数据库
use mydb
// 显示当前数据库
db
// 删除数据库
db.dropDatabase()
// ========== 集合操作 ==========
// 显示所有集合
show collections
// 创建集合
db.createCollection("users")
// 删除集合
db.users.drop()
// ========== CRUD 操作 ==========
// 插入单个文档
db.users.insertOne({
name: "张三",
email: "zhangsan@example.com",
age: 25,
createdAt: new Date()
})
// 插入多个文档
db.users.insertMany([
{ name: "李四", email: "lisi@example.com", age: 30 },
{ name: "王五", email: "wangwu@example.com", age: 28 }
])
// 查询所有文档
db.users.find()
// 条件查询
db.users.find({ age: { $gte: 25 } })
// 查询单个文档
db.users.findOne({ email: "zhangsan@example.com" })
// 更新文档
db.users.updateOne(
{ email: "zhangsan@example.com" },
{ $set: { age: 26 } }
)
// 更新多个文档
db.users.updateMany(
{ age: { $lt: 30 } },
{ $inc: { age: 1 } }
)
// 删除文档
db.users.deleteOne({ email: "zhangsan@example.com" })
// 删除多个文档
db.users.deleteMany({ age: { $lt: 25 } })
// ========== 索引操作 ==========
// 创建索引
db.users.createIndex({ email: 1 }, { unique: true })
// 创建复合索引
db.users.createIndex({ name: 1, age: -1 })
// 创建文本索引
db.users.createIndex({ description: "text" })
// 查看索引
db.users.getIndexes()
// 删除索引
db.users.dropIndex("email_1")
// ========== 聚合查询 ==========
// 统计文档数量
db.users.countDocuments()
// 分组统计
db.users.aggregate([
{ $group: { _id: "$age", count: { $sum: 1 } } }
])
// 排序和限制
db.users.aggregate([
{ $sort: { age: -1 } },
{ $limit: 10 }
])
// ========== 性能分析 ==========
// 查看查询计划
db.users.find({ age: 25 }).explain("executionStats")
// 查看慢查询
db.currentOp({ "secs_running": { $gte: 5 } })
// 终止慢查询
db.killOp(<opid>)
// ========== 用户管理 ==========
// 创建用户
db.createUser({
user: "myuser",
pwd: "mypassword",
roles: [ { role: "readWrite", db: "mydb" } ]
})
// 查看用户
db.getUsers()
// 删除用户
db.dropUser("myuser")
// 修改用户密码
db.changeUserPassword("myuser", "newpassword")
// ========== 数据库统计 ==========
// 查看数据库统计信息
db.stats()
// 查看集合统计信息
db.users.stats()
// 查看服务器状态
db.serverStatus()
性能监控
// ========== 连接统计 ==========
// 查看当前连接
db.currentOp()
// 查看服务器状态
db.serverStatus().connections
// 查看慢查询
db.system.profile.find({ millis: { $gt: 100 } }).sort({ ts: -1 }).limit(10)
// ========== 性能分析 ==========
// 启用性能分析(级别 2:记录所有操作)
db.setProfilingLevel(2)
// 启用性能分析(级别 1:仅记录慢操作)
db.setProfilingLevel(1, { slowms: 100 })
// 查看性能分析级别
db.getProfilingStatus()
// 关闭性能分析
db.setProfilingLevel(0)
// ========== 索引分析 ==========
// 查看未使用的索引
db.users.aggregate([
{ $indexStats: {} },
{ $match: { "accesses.ops": 0 } }
])
// 查看索引使用情况
db.users.aggregate([
{ $indexStats: {} }
])
// ========== 存储统计 ==========
// 查看数据库大小
db.stats(1024 * 1024) // 以 MB 为单位
// 查看集合大小
db.users.stats(1024 * 1024)
// 查看所有集合大小
db.getCollectionNames().forEach(function(collection) {
var stats = db[collection].stats(1024 * 1024);
print(collection + ": " + stats.size + " MB");
})
性能优化
1. 索引优化
// 分析慢查询
db.system.profile.find({ millis: { $gt: 100 } })
.sort({ ts: -1 })
.limit(10)
.forEach(doc => {
print("Query: " + tojson(doc.query));
print("Time: " + doc.millis + " ms");
print("Collection: " + doc.ns);
print("---");
})
// 为慢查询创建合适的索引
db.users.createIndex({ email: 1, age: 1 })
// 使用 hint 强制使用特定索引
db.users.find({ email: "test@example.com" }).hint({ email: 1 })
2. 连接池配置
.NET 连接字符串示例:
mongodb://username:password@localhost:27017/mydb?maxPoolSize=100&minPoolSize=10
Node.js 连接选项:
const client = new MongoClient(uri, {
maxPoolSize: 100,
minPoolSize: 10,
maxIdleTimeMS: 30000,
serverSelectionTimeoutMS: 5000
});
3. 查询优化
// 使用投影减少返回字段
db.users.find(
{ age: { $gte: 25 } },
{ name: 1, email: 1, _id: 0 }
)
// 使用 limit 限制返回结果
db.users.find({ age: { $gte: 25 } }).limit(10)
// 批量操作
db.users.bulkWrite([
{ insertOne: { document: { name: "user1" } } },
{ updateOne: { filter: { _id: 1 }, update: { $set: { name: "updated" } } } },
{ deleteOne: { filter: { _id: 2 } } }
])
最佳实践
最佳实践
常见问题
1. 连接认证失败
# 确保使用正确的认证数据库
docker exec -it mongodb mongosh \
-u admin \
-p your_password \
--authenticationDatabase admin
2. 磁盘空间不足
// 压缩集合
db.runCommand({ compact: 'users' })
// 删除旧数据
db.logs.deleteMany({ createdAt: { $lt: new Date('2024-01-01') } })
// 检查数据库大小
db.stats(1024 * 1024)
3. 查询性能慢
// 使用 explain 分析查询
db.users.find({ email: "test@example.com" }).explain("executionStats")
// 检查是否使用了索引
db.users.find({ email: "test@example.com" }).explain("executionStats").executionStats.executionStages
// 创建缺失的索引
db.users.createIndex({ email: 1 })