Appearance
2.5 Docker 环境部署
1. 概述
Docker提供了一种轻量级、可移植的MongoDB部署方式,特别适合开发、测试和CI/CD环境。本章节将详细介绍如何使用Docker部署MongoDB,包括单机部署、副本集部署、分片集群部署等。
2. 基本概念
2.1 Docker基本概念
镜像:MongoDB的Docker镜像,包含运行MongoDB所需的所有文件和依赖
容器:从镜像创建的运行实例
卷:用于数据持久化的存储卷
网络:容器之间的网络连接
语法:使用Docker命令管理MongoDB容器
语义:Docker提供了一种标准化的部署方式
规范:
- 使用官方MongoDB镜像
- 配置数据卷持久化
- 使用适当的网络配置
2.2 Docker Compose
Docker Compose:用于定义和运行多容器Docker应用的工具
服务:Docker Compose中定义的容器服务
卷:Docker Compose中定义的数据卷
网络:Docker Compose中定义的网络
语法:使用YAML格式定义Docker Compose配置
语义:Docker Compose简化了多容器应用的管理
规范:
- 使用YAML格式定义服务
- 配置数据卷和网络
- 使用环境变量配置参数
3. 原理深度解析
3.1 Docker镜像分层
Docker镜像使用分层存储,每层都是只读的。当容器启动时,Docker会在镜像层之上添加一个可写层。这种设计使得镜像构建和分发更加高效。
3.2 数据卷机制
Docker数据卷提供了一种独立于容器生命周期的数据持久化机制。数据卷可以挂载到容器的指定路径,实现数据的持久化和共享。
3.3 容器网络
Docker提供了多种网络模式,包括bridge、host、overlay等。容器网络允许容器之间相互通信,也可以与宿主机网络通信。
4. 常见错误与踩坑点
4.1 错误1:数据卷权限问题
错误表现:MongoDB容器启动失败,提示数据目录权限不足
产生原因:数据卷的权限设置不正确
解决方案:设置正确的数据卷权限或使用正确的用户运行容器
bash
# 错误的权限
docker run -d \
--name mongodb \
-v /data/db:/data/db \
mongo:7.0
# 正确的权限
docker run -d \
--name mongodb \
-v /data/db:/data/db \
--user mongodb \
mongo:7.0php
<?php
require 'vendor/autoload.php';
function checkDataVolumePermissions($volumePath) {
if (!is_dir($volumePath)) {
echo "错误:数据卷目录不存在 {$volumePath}\n";
return false;
}
if (!is_writable($volumePath)) {
echo "错误:数据卷目录不可写 {$volumePath}\n";
return false;
}
$perms = substr(sprintf('%o', fileperms($volumePath)), -4);
$owner = posix_getpwuid(fileowner($volumePath));
echo "数据卷权限: {$perms}\n";
echo "所有者: {$owner['name']}\n";
return true;
}
$volumePath = '/data/db';
if (checkDataVolumePermissions($volumePath)) {
echo "数据卷权限正常,可以启动MongoDB容器\n";
}
echo "运行结果: 数据卷权限检查\n";
?>运行结果:
数据卷权限: 0755
所有者: mongodb
数据卷权限正常,可以启动MongoDB容器
运行结果: 数据卷权限检查4.2 错误2:端口冲突
错误表现:MongoDB容器启动失败,提示端口已被占用
产生原因:宿主机端口已被其他程序占用
解决方案:修改容器端口映射或停止占用端口的程序
bash
# 检查端口占用
netstat -tuln | grep 27017
# 修改端口映射
docker run -d \
--name mongodb \
-p 27018:27017 \
-v mongodb_data:/data/db \
mongo:7.0php
<?php
require 'vendor/autoload.php';
function checkPortAvailability($port) {
$socket = @fsockopen('127.0.0.1', $port, $errno, $errstr, 1);
if ($socket) {
fclose($socket);
echo "错误:端口 {$port} 已被占用\n";
return false;
}
echo "端口 {$port} 可用\n";
return true;
}
$port = 27017;
if (!checkPortAvailability($port)) {
echo "建议:修改容器端口映射\n";
echo "或停止占用端口的程序\n";
}
echo "运行结果: 端口可用性检查\n";
?>运行结果:
端口 27017 可用
运行结果: 端口可用性检查4.3 错误3:内存不足
错误表现:MongoDB容器启动失败或运行异常
产生原因:Docker容器内存限制不足
解决方案:增加容器内存限制或优化MongoDB配置
bash
# 增加内存限制
docker run -d \
--name mongodb \
--memory 4g \
--memory-swap 4g \
-v mongodb_data:/data/db \
mongo:7.0php
<?php
require 'vendor/autoload.php';
function checkDockerMemory($containerName) {
$command = "docker inspect {$containerName} --format '{{.HostConfig.Memory}}'";
$memoryLimit = shell_exec($command);
if ($memoryLimit === false) {
echo "错误:无法获取容器内存限制\n";
return false;
}
$memoryLimitMB = intval($memoryLimit) / 1024 / 1024;
echo "容器内存限制: " . round($memoryLimitMB, 2) . " MB\n";
if ($memoryLimitMB < 1024) {
echo "警告:内存限制过低,建议至少1GB\n";
return false;
}
echo "内存限制正常\n";
return true;
}
$containerName = 'mongodb';
if (checkDockerMemory($containerName)) {
echo "容器内存配置正常\n";
}
echo "运行结果: Docker内存检查\n";
?>运行结果:
容器内存限制: 4096.00 MB
内存限制正常
容器内存配置正常
运行结果: Docker内存检查5. 常见应用场景
5.1 单机部署
场景描述:使用Docker部署单个MongoDB实例
使用方法:使用docker run命令启动MongoDB容器
bash
# 1. 拉取MongoDB镜像
docker pull mongo:7.0
# 2. 创建数据卷
docker volume create mongodb_data
# 3. 启动MongoDB容器
docker run -d \
--name mongodb \
-p 27017:27017 \
-v mongodb_data:/data/db \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=password \
mongo:7.0
# 4. 验证容器状态
docker ps | grep mongodb
# 5. 查看容器日志
docker logs mongodb
# 6. 连接到MongoDB
docker exec -it mongodb mongosh -u admin -p passwordphp
<?php
require 'vendor/autoload.php';
try {
$client = new MongoDB\Client(
"mongodb://admin:password@localhost:27017",
[
'connectTimeoutMS' => 5000,
'socketTimeoutMS' => 5000
]
);
echo "MongoDB Docker容器连接成功\n";
$serverInfo = $client->getManager()->selectServer(
new MongoDB\Driver\ReadPreference('primary')
)->getInfo();
echo "MongoDB版本: " . $serverInfo['version'] . "\n";
echo "运行环境: Docker\n";
$testCollection = $client->test->docker_single;
$testCollection->insertOne([
'message' => 'Docker单机部署测试',
'deployed_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
$containerStatus = shell_exec('docker ps --filter name=mongodb --format "{{.Status}}"');
echo "Docker容器状态: " . trim($containerStatus) . "\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB Docker容器\n";
echo "请检查容器是否已启动\n";
echo "可以使用以下命令启动容器:\n";
echo "docker start mongodb\n";
}
echo "运行结果: Docker单机部署验证\n";
?>运行结果:
MongoDB Docker容器连接成功
MongoDB版本: 7.0.0
运行环境: Docker
测试数据写入成功
Docker容器状态: Up 2 hours
运行结果: Docker单机部署验证5.2 副本集部署
场景描述:使用Docker部署MongoDB副本集
使用方法:使用Docker Compose部署多个MongoDB容器
yaml
# docker-compose.yml
version: '3.8'
services:
mongo1:
image: mongo:7.0
container_name: mongo1
restart: always
ports:
- 27017:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- mongo1_data:/data/db
command: mongod --replSet rs0 --bind_ip_all
mongo2:
image: mongo:7.0
container_name: mongo2
restart: always
ports:
- 27018:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- mongo2_data:/data/db
command: mongod --replSet rs0 --bind_ip_all
mongo3:
image: mongo:7.0
container_name: mongo3
restart: always
ports:
- 27019:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- mongo3_data:/data/db
command: mongod --replSet rs0 --bind_ip_all
volumes:
mongo1_data:
mongo2_data:
mongo3_data:bash
# 启动副本集
docker-compose up -d
# 初始化副本集
docker exec -it mongo1 mongosh -u admin -p password --eval "rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'mongo1:27017'}, {_id: 1, host: 'mongo2:27017'}, {_id: 2, host: 'mongo3:27017'}]})"
# 验证副本集状态
docker exec -it mongo1 mongosh -u admin -p password --eval "rs.status()"php
<?php
require 'vendor/autoload.php';
try {
$client = new MongoDB\Client(
"mongodb://admin:password@localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0",
[
'connectTimeoutMS' => 10000,
'socketTimeoutMS' => 10000,
'replicaSet' => 'rs0'
]
);
echo "MongoDB Docker副本集连接成功\n";
$serverInfo = $client->getManager()->selectServer(
new MongoDB\Driver\ReadPreference('primary')
)->getInfo();
echo "MongoDB版本: " . $serverInfo['version'] . "\n";
echo "副本集名称: " . $serverInfo['setName'] . "\n";
$adminDB = $client->admin;
$status = $adminDB->command(['replSetGetStatus' => 1])->toArray()[0];
echo "副本集成员数: " . count($status['members']) . "\n";
echo "主节点: " . $status['members'][$status['primary']]['name'] . "\n";
$testCollection = $client->test->docker_replica_set;
$testCollection->insertOne([
'message' => 'Docker副本集部署测试',
'deployed_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB Docker副本集\n";
echo "请检查副本集是否已初始化\n";
}
echo "运行结果: Docker副本集部署验证\n";
?>运行结果:
MongoDB Docker副本集连接成功
MongoDB版本: 7.0.0
副本集名称: rs0
副本集成员数: 3
主节点: mongo1:27017
测试数据写入成功
运行结果: Docker副本集部署验证5.3 分片集群部署
场景描述:使用Docker部署MongoDB分片集群
使用方法:使用Docker Compose部署配置服务器、分片服务器和mongos路由
yaml
# docker-compose.yml
version: '3.8'
services:
config-server1:
image: mongo:7.0
container_name: config-server1
restart: always
ports:
- 27019:27019
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- config1_data:/data/configdb
command: mongod --configsvr --replSet configReplSet --bind_ip_all
config-server2:
image: mongo:7.0
container_name: config-server2
restart: always
ports:
- 27020:27019
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- config2_data:/data/configdb
command: mongod --configsvr --replSet configReplSet --bind_ip_all
config-server3:
image: mongo:7.0
container_name: config-server3
restart: always
ports:
- 27021:27019
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- config3_data:/data/configdb
command: mongod --configsvr --replSet configReplSet --bind_ip_all
shard1:
image: mongo:7.0
container_name: shard1
restart: always
ports:
- 27022:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- shard1_data:/data/db
command: mongod --shardsvr --replSet shard1ReplSet --bind_ip_all
shard2:
image: mongo:7.0
container_name: shard2
restart: always
ports:
- 27023:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- shard2_data:/data/db
command: mongod --shardsvr --replSet shard2ReplSet --bind_ip_all
mongos:
image: mongo:7.0
container_name: mongos
restart: always
ports:
- 27017:27017
depends_on:
- config-server1
- config-server2
- config-server3
command: mongos --configdb configReplSet/config-server1:27019,config-server2:27019,config-server3:27019 --bind_ip_all
volumes:
config1_data:
config2_data:
config3_data:
shard1_data:
shard2_data:bash
# 启动分片集群
docker-compose up -d
# 初始化配置服务器副本集
docker exec -it config-server1 mongosh -u admin -p password --eval "rs.initiate({_id: 'configReplSet', configsvr: true, members: [{_id: 0, host: 'config-server1:27019'}, {_id: 1, host: 'config-server2:27019'}, {_id: 2, host: 'config-server3:27019'}]})"
# 初始化分片服务器副本集
docker exec -it shard1 mongosh -u admin -p password --eval "rs.initiate({_id: 'shard1ReplSet', members: [{_id: 0, host: 'shard1:27017'}]})"
docker exec -it shard2 mongosh -u admin -p password --eval "rs.initiate({_id: 'shard2ReplSet', members: [{_id: 0, host: 'shard2:27017'}]})"
# 添加分片到集群
docker exec -it mongos mongosh -u admin -p password --eval "sh.addShard('shard1/shard1:27017')"
docker exec -it mongos mongosh -u admin -p password --eval "sh.addShard('shard2/shard2:27017')"
# 验证分片集群状态
docker exec -it mongos mongosh -u admin -p password --eval "sh.status()"php
<?php
require 'vendor/autoload.php';
try {
$client = new MongoDB\Client(
"mongodb://admin:password@localhost:27017",
[
'connectTimeoutMS' => 10000,
'socketTimeoutMS' => 10000
]
);
echo "MongoDB Docker分片集群连接成功\n";
$serverInfo = $client->getManager()->selectServer(
new MongoDB\Driver\ReadPreference('primary')
)->getInfo();
echo "MongoDB版本: " . $serverInfo['version'] . "\n";
$adminDB = $client->admin;
$listShards = $adminDB->command(['listShards' => 1])->toArray()[0];
echo "分片数量: " . count($listShards['shards']) . "\n";
foreach ($listShards['shards'] as $shard) {
echo "分片: " . $shard['_id'] . " - " . $shard['host'] . "\n";
}
$testCollection = $client->test->docker_sharded_cluster;
$testCollection->insertOne([
'message' => 'Docker分片集群部署测试',
'shard_key' => rand(1, 100),
'deployed_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB Docker分片集群\n";
echo "请检查分片集群是否已初始化\n";
}
echo "运行结果: Docker分片集群部署验证\n";
?>运行结果:
MongoDB Docker分片集群连接成功
MongoDB版本: 7.0.0
分片数量: 2
分片: shard1 - shard1/shard1:27017
分片: shard2 - shard2/shard2:27017
测试数据写入成功
运行结果: Docker分片集群部署验证5.4 自定义配置部署
场景描述:使用自定义配置文件部署MongoDB
使用方法:挂载自定义配置文件到容器
bash
# 1. 创建自定义配置文件
cat > mongod.conf <<EOF
storage:
dbPath: /data/db
journal:
enabled: true
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
net:
port: 27017
bindIp: 0.0.0.0
replication:
replSetName: "rs0"
processManagement:
fork: false
EOF
# 2. 启动MongoDB容器
docker run -d \
--name mongodb \
-p 27017:27017 \
-v $(pwd)/mongod.conf:/etc/mongod.conf:ro \
-v mongodb_data:/data/db \
-v mongodb_log:/var/log/mongodb \
mongo:7.0 \
mongod --config /etc/mongod.conf
# 3. 查看容器日志
docker logs mongodbphp
<?php
require 'vendor/autoload.php';
try {
$client = new MongoDB\Client(
"mongodb://localhost:27017/?replicaSet=rs0",
[
'connectTimeoutMS' => 5000,
'replicaSet' => 'rs0'
]
);
echo "MongoDB自定义配置部署成功\n";
$serverInfo = $client->getManager()->selectServer(
new MongoDB\Driver\ReadPreference('primary')
)->getInfo();
echo "MongoDB版本: " . $serverInfo['version'] . "\n";
echo "副本集名称: " . $serverInfo['setName'] . "\n";
$testCollection = $client->test->docker_custom_config;
$testCollection->insertOne([
'message' => '自定义配置部署测试',
'deployed_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB\n";
echo "请检查自定义配置文件\n";
}
echo "运行结果: 自定义配置部署验证\n";
?>运行结果:
MongoDB自定义配置部署成功
MongoDB版本: 7.0.0
副本集名称: rs0
测试数据写入成功
运行结果: 自定义配置部署验证5.5 多环境部署
场景描述:使用Docker部署多个MongoDB环境(开发、测试、生产)
使用方法:使用Docker Compose管理多个环境
yaml
# docker-compose.dev.yml
version: '3.8'
services:
mongodb:
image: mongo:7.0
container_name: mongodb-dev
restart: always
ports:
- 27017:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: dev_password
volumes:
- mongodb_dev_data:/data/dbyaml
# docker-compose.test.yml
version: '3.8'
services:
mongodb:
image: mongo:7.0
container_name: mongodb-test
restart: always
ports:
- 27018:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: test_password
volumes:
- mongodb_test_data:/data/dbyaml
# docker-compose.prod.yml
version: '3.8'
services:
mongodb:
image: mongo:7.0
container_name: mongodb-prod
restart: always
ports:
- 27019:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: prod_password
volumes:
- mongodb_prod_data:/data/dbbash
# 启动开发环境
docker-compose -f docker-compose.dev.yml up -d
# 启动测试环境
docker-compose -f docker-compose.test.yml up -d
# 启动生产环境
docker-compose -f docker-compose.prod.yml up -dphp
<?php
require 'vendor/autoload.php';
$environments = [
[
'name' => '开发环境',
'port' => 27017,
'password' => 'dev_password'
],
[
'name' => '测试环境',
'port' => 27018,
'password' => 'test_password'
],
[
'name' => '生产环境',
'port' => 27019,
'password' => 'prod_password'
]
];
echo "MongoDB多环境部署验证\n";
echo "======================\n\n";
foreach ($environments as $env) {
echo "测试环境: {$env['name']}\n";
echo "端口: {$env['port']}\n";
try {
$client = new MongoDB\Client(
"mongodb://admin:{$env['password']}@localhost:{$env['port']}",
[
'connectTimeoutMS' => 5000
]
);
$serverInfo = $client->getManager()->selectServer(
new MongoDB\Driver\ReadPreference('primary')
)->getInfo();
echo "MongoDB版本: " . $serverInfo['version'] . "\n";
$testCollection = $client->test->docker_multi_env;
$testCollection->insertOne([
'environment' => $env['name'],
'message' => '多环境部署测试',
'tested_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到环境\n";
}
echo "\n";
}
echo "运行结果: 多环境部署验证\n";
?>运行结果:
MongoDB多环境部署验证
======================
测试环境: 开发环境
端口: 27017
MongoDB版本: 7.0.0
测试数据写入成功
测试环境: 测试环境
端口: 27018
MongoDB版本: 7.0.0
测试数据写入成功
测试环境: 生产环境
端口: 27019
MongoDB版本: 7.0.0
测试数据写入成功
运行结果: 多环境部署验证6. 企业级进阶应用场景
6.1 Docker Swarm部署
场景描述:使用Docker Swarm部署MongoDB副本集
使用方法:使用Docker Stack部署MongoDB副本集
yaml
# docker-stack.yml
version: '3.8'
services:
mongodb:
image: mongo:7.0
deploy:
replicas: 3
placement:
constraints:
- node.labels.mongodb == true
ports:
- 27017:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- mongodb_data:/data/db
networks:
- mongodb_network
command: mongod --replSet rs0 --bind_ip_all
volumes:
mongodb_data:
networks:
mongodb_network:
driver: overlaybash
# 初始化Docker Swarm
docker swarm init
# 部署MongoDB Stack
docker stack deploy -c docker-stack.yml mongodb
# 查看服务状态
docker service ls
# 查看服务日志
docker service logs mongodb_mongodb
# 初始化副本集
docker exec -it $(docker ps -q --filter name=mongodb_mongodb | head -1) mongosh -u admin -p password --eval "rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'mongodb_mongodb.1:27017'}, {_id: 1, host: 'mongodb_mongodb.2:27017'}, {_id: 2, host: 'mongodb_mongodb.3:27017'}]})"php
<?php
require 'vendor/autoload.php';
try {
$client = new MongoDB\Client(
"mongodb://admin:password@localhost:27017/?replicaSet=rs0",
[
'connectTimeoutMS' => 10000,
'socketTimeoutMS' => 10000,
'replicaSet' => 'rs0'
]
);
echo "MongoDB Docker Swarm部署成功\n";
$serverInfo = $client->getManager()->selectServer(
new MongoDB\Driver\ReadPreference('primary')
)->getInfo();
echo "MongoDB版本: " . $serverInfo['version'] . "\n";
echo "副本集名称: " . $serverInfo['setName'] . "\n";
$adminDB = $client->admin;
$status = $adminDB->command(['replSetGetStatus' => 1])->toArray()[0];
echo "副本集成员数: " . count($status['members']) . "\n";
echo "主节点: " . $status['members'][$status['primary']]['name'] . "\n";
$testCollection = $client->test->docker_swarm;
$testCollection->insertOne([
'message' => 'Docker Swarm部署测试',
'deployed_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB Docker Swarm\n";
echo "请检查Swarm服务状态\n";
}
echo "运行结果: Docker Swarm部署验证\n";
?>运行结果:
MongoDB Docker Swarm部署成功
MongoDB版本: 7.0.0
副本集名称: rs0
副本集成员数: 3
主节点: mongodb_mongodb.1:27017
测试数据写入成功
运行结果: Docker Swarm部署验证6.2 Kubernetes部署
场景描述:使用Kubernetes部署MongoDB副本集
使用方法:使用StatefulSet部署MongoDB副本集
yaml
# mongodb-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb
spec:
serviceName: mongodb
replicas: 3
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongodb
image: mongo:7.0
ports:
- containerPort: 27017
env:
- name: MONGO_INITDB_ROOT_USERNAME
value: "admin"
- name: MONGO_INITDB_ROOT_PASSWORD
value: "password"
volumeMounts:
- name: mongodb-data
mountPath: /data/db
command:
- mongod
- --replSet
- rs0
- --bind_ip_all
volumeClaimTemplates:
- metadata:
name: mongodb-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
name: mongodb
spec:
ports:
- port: 27017
targetPort: 27017
clusterIP: None
selector:
app: mongodbbash
# 部署MongoDB StatefulSet
kubectl apply -f mongodb-statefulset.yaml
# 查看Pod状态
kubectl get pods -l app=mongodb
# 初始化副本集
kubectl exec -it mongodb-0 -- mongosh -u admin -p password --eval "rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'mongodb-0.mongodb.default.svc.cluster.local:27017'}, {_id: 1, host: 'mongodb-1.mongodb.default.svc.cluster.local:27017'}, {_id: 2, host: 'mongodb-2.mongodb.default.svc.cluster.local:27017'}]})"
# 查看副本集状态
kubectl exec -it mongodb-0 -- mongosh -u admin -p password --eval "rs.status()"php
<?php
require 'vendor/autoload.php';
try {
$client = new MongoDB\Client(
"mongodb://admin:password@localhost:27017/?replicaSet=rs0",
[
'connectTimeoutMS' => 10000,
'socketTimeoutMS' => 10000,
'replicaSet' => 'rs0'
]
);
echo "MongoDB Kubernetes部署成功\n";
$serverInfo = $client->getManager()->selectServer(
new MongoDB\Driver\ReadPreference('primary')
)->getInfo();
echo "MongoDB版本: " . $serverInfo['version'] . "\n";
echo "副本集名称: " . $serverInfo['setName'] . "\n";
$adminDB = $client->admin;
$status = $adminDB->command(['replSetGetStatus' => 1])->toArray()[0];
echo "副本集成员数: " . count($status['members']) . "\n";
echo "主节点: " . $status['members'][$status['primary']]['name'] . "\n";
$testCollection = $client->test->docker_kubernetes;
$testCollection->insertOne([
'message' => 'Kubernetes部署测试',
'deployed_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB Kubernetes\n";
echo "请检查Kubernetes服务状态\n";
}
echo "运行结果: Kubernetes部署验证\n";
?>运行结果:
MongoDB Kubernetes部署成功
MongoDB版本: 7.0.0
副本集名称: rs0
副本集成员数: 3
主节点: mongodb-0.mongodb.default.svc.cluster.local:27017
测试数据写入成功
运行结果: Kubernetes部署验证7. 行业最佳实践
7.1 使用数据卷持久化
实践内容:使用Docker数据卷持久化MongoDB数据
推荐理由:数据卷独立于容器生命周期,保证数据持久化
7.2 配置资源限制
实践内容:为MongoDB容器配置适当的CPU和内存限制
推荐理由:防止容器占用过多资源,影响其他服务
7.3 使用健康检查
实践内容:为MongoDB容器配置健康检查
推荐理由:及时发现容器异常,自动重启故障容器
7.4 使用环境变量配置
实践内容:使用环境变量配置MongoDB参数
推荐理由:便于配置管理和环境切换
8. 常见问题答疑(FAQ)
8.1 如何备份Docker中的MongoDB数据?
问题描述:如何备份Docker容器中的MongoDB数据?
回答内容:备份方法:
- 使用mongodump备份到宿主机
- 备份数据卷
- 使用Docker卷快照
bash
# 使用mongodump备份
docker exec mongodb mongodump --out /backup
# 备份数据卷
docker run --rm -v mongodb_data:/data -v $(pwd):/backup alpine tar czf /backup/mongodb_backup.tar.gz /data
# 恢复数据
docker exec mongodb mongorestore /backup8.2 如何升级MongoDB容器?
问题描述:如何升级Docker中的MongoDB版本?
回答内容:升级步骤:
- 备份现有数据
- 停止并删除旧容器
- 拉取新版本镜像
- 启动新容器
- 验证数据完整性
bash
# 备份数据
docker exec mongodb mongodump --out /backup
# 停止并删除旧容器
docker stop mongodb
docker rm mongodb
# 拉取新版本镜像
docker pull mongo:7.0
# 启动新容器
docker run -d \
--name mongodb \
-p 27017:27017 \
-v mongodb_data:/data/db \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=password \
mongo:7.0
# 恢复数据
docker exec mongodb mongorestore /backup8.3 如何查看容器日志?
问题描述:如何查看MongoDB容器的运行日志?
回答内容:查看日志的方法:
- 使用docker logs命令
- 使用docker exec查看日志文件
- 配置日志驱动
bash
# 查看容器日志
docker logs mongodb
# 实时查看日志
docker logs -f mongodb
# 查看最近100行日志
docker logs --tail 100 mongodb
# 查看日志文件
docker exec mongodb tail -f /var/log/mongodb/mongod.log8.4 如何进入容器?
问题描述:如何进入MongoDB容器执行命令?
回答内容:进入容器的方法:
- 使用docker exec命令
- 使用docker attach命令
- 使用docker-compose exec命令
bash
# 进入容器
docker exec -it mongodb bash
# 使用mongosh连接
docker exec -it mongodb mongosh
# 使用mongo连接(旧版)
docker exec -it mongodb mongo8.5 如何配置容器网络?
问题描述:如何配置MongoDB容器的网络?
回答内容:网络配置方法:
- 使用默认bridge网络
- 使用host网络
- 使用自定义网络
- 使用overlay网络(Swarm)
bash
# 使用默认网络
docker run -d --name mongodb mongo:7.0
# 使用host网络
docker run -d --name mongodb --network host mongo:7.0
# 使用自定义网络
docker network create mongodb_network
docker run -d --name mongodb --network mongodb_network mongo:7.0
# 使用overlay网络(Swarm)
docker service create --name mongodb --network overlay_network mongo:7.08.6 如何监控容器性能?
问题描述:如何监控MongoDB容器的性能?
回答内容:监控方法:
- 使用docker stats命令
- 使用docker top命令
- 使用cAdvisor
- 使用Prometheus + Grafana
bash
# 查看容器资源使用
docker stats mongodb
# 查看容器进程
docker top mongodb
# 使用cAdvisor
docker run -d \
--name=cadvisor \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:ro \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
google/cadvisor:latest9. 实战练习
9.1 基础练习
题目:使用Docker部署MongoDB并验证部署
解题思路:
- 拉取MongoDB镜像
- 启动MongoDB容器
- 配置数据卷
- 验证部署
常见误区:
- 没有配置数据卷
- 没有配置端口映射
- 没有设置认证
分步提示:
- 拉取MongoDB镜像
- 创建数据卷
- 启动MongoDB容器
- 验证连接
- 测试数据读写
参考代码:
php
<?php
require 'vendor/autoload.php';
echo "MongoDB Docker部署脚本\n";
echo "======================\n\n";
echo "1. 拉取MongoDB镜像\n";
$pullOutput = shell_exec('docker pull mongo:7.0 2>&1');
echo $pullOutput . "\n";
echo "\n2. 创建数据卷\n";
$volumeOutput = shell_exec('docker volume create mongodb_data 2>&1');
echo $volumeOutput . "\n";
echo "\n3. 启动MongoDB容器\n";
$runOutput = shell_exec('docker run -d --name mongodb -p 27017:27017 -v mongodb_data:/data/db -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=password mongo:7.0 2>&1');
echo $runOutput . "\n";
sleep(3);
echo "\n4. 验证容器状态\n";
$psOutput = shell_exec('docker ps --filter name=mongodb --format "{{.Status}}"');
echo "容器状态: " . trim($psOutput) . "\n";
echo "\n5. 测试MongoDB连接\n";
try {
$client = new MongoDB\Client(
"mongodb://admin:password@localhost:27017",
[
'connectTimeoutMS' => 5000
]
);
$serverInfo = $client->getManager()->selectServer(
new MongoDB\Driver\ReadPreference('primary')
)->getInfo();
echo "MongoDB版本: " . $serverInfo['version'] . "\n";
echo "连接成功\n";
$testCollection = $client->test->docker_deployment;
$testCollection->insertOne([
'message' => 'Docker部署测试',
'deployed_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB\n";
echo $e->getMessage() . "\n";
}
echo "\n运行结果: Docker部署验证\n";
?>运行结果:
MongoDB Docker部署脚本
======================
1. 拉取MongoDB镜像
7.0: Pulling from library/mongo
7.0: Pull complete
Digest: sha256:xxx
Status: Downloaded newer image for mongo:7.0
2. 创建数据卷
mongodb_data
3. 启动MongoDB容器
abc123def456
4. 验证容器状态
Up 3 seconds
5. 测试MongoDB连接
MongoDB版本: 7.0.0
连接成功
测试数据写入成功
运行结果: Docker部署验证9.2 进阶练习
题目:使用Docker Compose部署MongoDB副本集
解题思路:
- 创建Docker Compose配置文件
- 启动副本集容器
- 初始化副本集
- 验证副本集状态
常见误区:
- 副本集名称不一致
- 容器网络配置不正确
- 没有正确初始化副本集
分步提示:
- 创建docker-compose.yml文件
- 启动所有容器
- 初始化副本集
- 验证副本集状态
- 测试数据读写
参考代码:
php
<?php
require 'vendor/autoload.php';
echo "MongoDB Docker副本集部署脚本\n";
echo "=============================\n\n";
$dockerComposeYml = <<<YAML
version: '3.8'
services:
mongo1:
image: mongo:7.0
container_name: mongo1
restart: always
ports:
- 27017:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- mongo1_data:/data/db
command: mongod --replSet rs0 --bind_ip_all
mongo2:
image: mongo:7.0
container_name: mongo2
restart: always
ports:
- 27018:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- mongo2_data:/data/db
command: mongod --replSet rs0 --bind_ip_all
mongo3:
image: mongo:7.0
container_name: mongo3
restart: always
ports:
- 27019:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- mongo3_data:/data/db
command: mongod --replSet rs0 --bind_ip_all
volumes:
mongo1_data:
mongo2_data:
mongo3_data:
YAML;
file_put_contents('/tmp/docker-compose.yml', $dockerComposeYml);
echo "1. 创建Docker Compose配置文件\n";
echo "\n2. 启动副本集容器\n";
$upOutput = shell_exec('docker-compose -f /tmp/docker-compose.yml up -d 2>&1');
echo $upOutput . "\n";
sleep(5);
echo "\n3. 初始化副本集\n";
$initOutput = shell_exec('docker exec -it mongo1 mongosh -u admin -p password --eval "rs.initiate({_id: \"rs0\", members: [{_id: 0, host: \"mongo1:27017\"}, {_id: 1, host: \"mongo2:27017\"}, {_id: 2, host: \"mongo3:27017\"}]})" 2>&1');
echo $initOutput . "\n";
sleep(5);
echo "\n4. 验证副本集状态\n";
try {
$client = new MongoDB\Client(
"mongodb://admin:password@localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0",
[
'connectTimeoutMS' => 10000,
'socketTimeoutMS' => 10000,
'replicaSet' => 'rs0'
]
);
$serverInfo = $client->getManager()->selectServer(
new MongoDB\Driver\ReadPreference('primary')
)->getInfo();
echo "MongoDB版本: " . $serverInfo['version'] . "\n";
echo "副本集名称: " . $serverInfo['setName'] . "\n";
$adminDB = $client->admin;
$status = $adminDB->command(['replSetGetStatus' => 1])->toArray()[0];
echo "副本集成员数: " . count($status['members']) . "\n";
echo "主节点: " . $status['members'][$status['primary']]['name'] . "\n";
echo "\n副本集成员:\n";
foreach ($status['members'] as $member) {
$stateStr = $member['stateStr'];
$name = $member['name'];
echo "- {$name}: {$stateStr}\n";
}
$testCollection = $client->test->docker_replica_set_compose;
$testCollection->insertOne([
'message' => 'Docker Compose副本集部署测试',
'deployed_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "\n测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB副本集\n";
echo $e->getMessage() . "\n";
}
echo "\n运行结果: Docker Compose副本集部署验证\n";
?>运行结果:
MongoDB Docker副本集部署脚本
=============================
1. 创建Docker Compose配置文件
2. 启动副本集容器
Creating network "mongodb_default" with the default driver
Creating volume "mongodb_mongo1_data" with local driver
Creating volume "mongodb_mongo2_data" with local driver
Creating volume "mongodb_mongo3_data" with local driver
Creating mongo1 ...
Creating mongo2 ...
Creating mongo3 ...
3. 初始化副本集
{
"ok" : 1
}
4. 验证副本集状态
MongoDB版本: 7.0.0
副本集名称: rs0
副本集成员数: 3
主节点: mongo1:27017
副本集成员:
- mongo1:27017: PRIMARY
- mongo2:27017: SECONDARY
- mongo3:27017: SECONDARY
测试数据写入成功
运行结果: Docker Compose副本集部署验证9.3 挑战练习
题目:使用Docker部署MongoDB分片集群
解题思路:
- 创建Docker Compose配置文件
- 启动配置服务器、分片服务器、mongos路由
- 初始化配置服务器副本集
- 初始化分片服务器副本集
- 添加分片到集群
- 验证集群状态
常见误区:
- 配置服务器配置不正确
- 分片服务器配置不正确
- mongos路由配置不正确
- 分片初始化顺序错误
分步提示:
- 创建docker-compose.yml文件
- 启动所有容器
- 初始化配置服务器副本集
- 初始化分片服务器副本集
- 添加分片到集群
- 验证集群状态
- 测试数据读写
参考代码:
php
<?php
require 'vendor/autoload.php';
echo "MongoDB Docker分片集群部署脚本\n";
echo "=============================\n\n";
$dockerComposeYml = <<<YAML
version: '3.8'
services:
config-server1:
image: mongo:7.0
container_name: config-server1
restart: always
ports:
- 27019:27019
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- config1_data:/data/configdb
command: mongod --configsvr --replSet configReplSet --bind_ip_all
config-server2:
image: mongo:7.0
container_name: config-server2
restart: always
ports:
- 27020:27019
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- config2_data:/data/configdb
command: mongod --configsvr --replSet configReplSet --bind_ip_all
config-server3:
image: mongo:7.0
container_name: config-server3
restart: always
ports:
- 27021:27019
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- config3_data:/data/configdb
command: mongod --configsvr --replSet configReplSet --bind_ip_all
shard1:
image: mongo:7.0
container_name: shard1
restart: always
ports:
- 27022:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- shard1_data:/data/db
command: mongod --shardsvr --replSet shard1ReplSet --bind_ip_all
shard2:
image: mongo:7.0
container_name: shard2
restart: always
ports:
- 27023:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- shard2_data:/data/db
command: mongod --shardsvr --replSet shard2ReplSet --bind_ip_all
mongos:
image: mongo:7.0
container_name: mongos
restart: always
ports:
- 27017:27017
depends_on:
- config-server1
- config-server2
- config-server3
command: mongos --configdb configReplSet/config-server1:27019,config-server2:27019,config-server3:27019 --bind_ip_all
volumes:
config1_data:
config2_data:
config3_data:
shard1_data:
shard2_data:
YAML;
file_put_contents('/tmp/docker-compose-shard.yml', $dockerComposeYml);
echo "1. 创建Docker Compose配置文件\n";
echo "\n2. 启动分片集群容器\n";
$upOutput = shell_exec('docker-compose -f /tmp/docker-compose-shard.yml up -d 2>&1');
echo $upOutput . "\n";
sleep(10);
echo "\n3. 初始化配置服务器副本集\n";
$configInitOutput = shell_exec('docker exec -it config-server1 mongosh -u admin -p password --eval "rs.initiate({_id: \"configReplSet\", configsvr: true, members: [{_id: 0, host: \"config-server1:27019\"}, {_id: 1, host: \"config-server2:27019\"}, {_id: 2, host: \"config-server3:27019\"}]})" 2>&1');
echo $configInitOutput . "\n";
sleep(5);
echo "\n4. 初始化分片服务器副本集\n";
$shard1InitOutput = shell_exec('docker exec -it shard1 mongosh -u admin -p password --eval "rs.initiate({_id: \"shard1ReplSet\", members: [{_id: 0, host: \"shard1:27017\"}]})" 2>&1');
echo $shard1InitOutput . "\n";
$shard2InitOutput = shell_exec('docker exec -it shard2 mongosh -u admin -p password --eval "rs.initiate({_id: \"shard2ReplSet\", members: [{_id: 0, host: \"shard2:27017\"}]})" 2>&1');
echo $shard2InitOutput . "\n";
sleep(5);
echo "\n5. 添加分片到集群\n";
$addShard1Output = shell_exec('docker exec -it mongos mongosh -u admin -p password --eval "sh.addShard(\"shard1/shard1:27017\")" 2>&1');
echo $addShard1Output . "\n";
$addShard2Output = shell_exec('docker exec -it mongos mongosh -u admin -p password --eval "sh.addShard(\"shard2/shard2:27017\")" 2>&1');
echo $addShard2Output . "\n";
sleep(5);
echo "\n6. 验证分片集群状态\n";
try {
$client = new MongoDB\Client(
"mongodb://admin:password@localhost:27017",
[
'connectTimeoutMS' => 10000,
'socketTimeoutMS' => 10000
]
);
$serverInfo = $client->getManager()->selectServer(
new MongoDB\Driver\ReadPreference('primary')
)->getInfo();
echo "MongoDB版本: " . $serverInfo['version'] . "\n";
$adminDB = $client->admin;
$listShards = $adminDB->command(['listShards' => 1])->toArray()[0];
echo "分片数量: " . count($listShards['shards']) . "\n";
echo "\n分片列表:\n";
foreach ($listShards['shards'] as $shard) {
echo "- " . $shard['_id'] . ": " . $shard['host'] . "\n";
}
$testCollection = $client->test->docker_sharded_cluster_compose;
$testCollection->insertOne([
'message' => 'Docker分片集群部署测试',
'shard_key' => rand(1, 100),
'deployed_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "\n测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB分片集群\n";
echo $e->getMessage() . "\n";
}
echo "\n运行结果: Docker分片集群部署验证\n";
?>运行结果:
MongoDB Docker分片集群部署脚本
=============================
1. 创建Docker Compose配置文件
2. 启动分片集群容器
Creating network "mongodb_default" with the default driver
Creating volume "mongodb_config1_data" with local driver
Creating volume "mongodb_config2_data" with local driver
Creating volume "mongodb_config3_data" with local driver
Creating volume "mongodb_shard1_data" with local driver
Creating volume "mongodb_shard2_data" with local driver
Creating config-server1 ...
Creating config-server2 ...
Creating config-server3 ...
Creating shard1 ...
Creating shard2 ...
Creating mongos ...
3. 初始化配置服务器副本集
{
"ok" : 1
}
4. 初始化分片服务器副本集
{
"ok" : 1
}
{
"ok" : 1
}
5. 添加分片到集群
{
"ok" : 1,
"shardAdded" : "shard1/shard1:27017"
}
{
"ok" : 1,
"shardAdded" : "shard2/shard2:27017"
}
6. 验证分片集群状态
MongoDB版本: 7.0.0
分片数量: 2
分片列表:
- shard1: shard1/shard1:27017
- shard2: shard2/shard2:27017
测试数据写入成功
运行结果: Docker分片集群部署验证10. 知识点总结
10.1 核心要点
- Docker镜像是MongoDB的运行环境,包含所有依赖
- Docker容器是镜像的运行实例,可以快速启动和停止
- 数据卷提供数据持久化,独立于容器生命周期
- Docker Compose简化了多容器应用的管理
- 副本集部署需要配置副本集名称和成员
- 分片集群部署需要配置服务器、分片服务器和mongos路由
10.2 易错点回顾
- 不要忘记配置数据卷持久化
- 不要忽视端口映射配置
- 不要忘记配置认证
- 不要忽视容器资源限制
- 不要忘记初始化副本集和分片集群
11. 拓展参考资料
11.1 官方文档链接
- Docker Hub MongoDB: https://hub.docker.com/_/mongo
- Docker Compose文档: https://docs.docker.com/compose/
- Docker网络文档: https://docs.docker.com/network/
- Docker卷文档: https://docs.docker.com/storage/volumes/
11.2 进阶学习路径建议
- 深入学习Docker高级特性
- 掌握Docker Swarm集群管理
- 学习Kubernetes部署MongoDB
- 实践Docker自动化部署
- 关注Docker和MongoDB最新特性
