这个文章是为了解释docker-compose.yml文件,想要查看mongodb副本集部署详细信息,请浏览这篇文章: docker副本集部署mongodb
以下提供 docker-compose.yml
文件的完整注释版本(适用于 MongoDB 副本集初始化的自动配置场景):
version: '3.8' # 使用 Docker Compose 文件版本 3.8,支持最新功能和特性
services:
mongo:
# 使用的 MongoDB 镜像,可从阿里云拉取以加快国内下载速度
# image: mongo:5.0.18 # 也可以使用官方镜像(默认 Docker Hub)
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18 # 阿里云加速镜像
# image: mongo:4.4.29 # 若当前 CPU 不支持 AVX 指令集,可使用旧版本(如在老服务器上运行)
container_name: mongodb # 自定义容器名称为 mongodb
restart: always # 当容器退出时总是尝试重启,保证服务可用性
ports:
- 27018:27017 # 将宿主机 27018 端口映射到容器 27017 端口(MongoDB 默认端口)
# MongoDB 启动命令,启用副本集并指定密钥文件(用于节点认证)
command: mongod --keyFile /data/mongodb.key --replSet rs0
environment:
- MONGO_INITDB_ROOT_USERNAME=root # 初始化 root 用户名
- MONGO_INITDB_ROOT_PASSWORD=123456 # 初始化 root 密码
volumes:
- ./mongo_data:/data/db # 数据卷,将本地目录挂载到容器内部用于数据持久化
entrypoint:
- bash
- -c
- | # 使用多行 shell 命令来执行初始化逻辑
# 1️⃣ 生成副本集密钥文件(用于多个 MongoDB 节点之间的认证)
openssl rand -base64 128 > /data/mongodb.key
chmod 400 /data/mongodb.key # 设置密钥权限为只读,符合 MongoDB 要求
chown 999:999 /data/mongodb.key # 更改文件所有者为 MongoDB 默认 UID(999)
# 2️⃣ 写入副本集初始化 JavaScript 脚本(用于后续 mongo 命令执行)
echo 'const isInited = rs.status().ok === 1
if(!isInited){
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "mongo:27017" }
]
})
}' > /data/initReplicaSet.js
# 3️⃣ 后台执行 MongoDB 官方入口脚本(启动 mongod)
exec docker-entrypoint.sh "$$@" &
# 4️⃣ 循环等待 MongoDB 服务完全启动可连接
until mongo -u root -p 123456 --authenticationDatabase admin --eval "print('waited for connection')"; do
echo "Waiting for MongoDB to start..."
sleep 2
done
# 5️⃣ 使用 root 用户执行副本集初始化脚本
mongo -u root -p 123456 --authenticationDatabase admin /data/initReplicaSet.js
# 6️⃣ 等待上面后台启动的 MongoDB 进程(防止容器提前退出)
wait $$!
✅ 总结这个配置完成的事情:
步骤 | 功能 |
---|---|
1️⃣ | 生成副本集认证所需的密钥文件 |
2️⃣ | 自动生成副本集初始化脚本 |
3️⃣ | 启动 MongoDB 服务(支持副本集) |
4️⃣ | 检查 MongoDB 是否启动成功 |
5️⃣ | 执行副本集初始化(rs.initiate) |
6️⃣ | 等待 MongoDB 服务进程,确保容器不提前结束 |
下面是提供的 MongoDB 副本集初始化 JavaScript 脚本的详细解释
✅ JavaScript脚本(含详细注释)
// 检查当前 Mongo 实例是否已经初始化了副本集(返回的 rs.status().ok === 1 表示已初始化)
const isInited = rs.status().ok === 1
// 如果还未初始化副本集,则进行初始化
if (!isInited) {
rs.initiate({
_id: "rs0", // 副本集名称(必须与 --replSet 参数一致)
members: [
{
_id: 0, // 成员 ID(必须唯一)
host: "mongo:27017" // 成员主机名和端口,这里是服务名“mongo”,与 docker-compose 的服务名一致
}
]
})
}
🔍 小结重点知识:
rs.status()
:查看副本集状态,若尚未初始化会报错。rs.initiate({...})
:执行初始化命令,设定副本集 ID 和成员。mongo:27017
:此 host 需要与docker-compose.yml
中的服务名保持一致(即mongo
)。keyFile
:确保节点间的认证安全(用于构建更复杂的副本集时必不可少)。
✅ 什么是 MongoDB 副本集(Replica Set)?
副本集(Replica Set) 是 MongoDB 提供的一种 高可用机制,它通过 多个节点的数据同步,来保证数据库的容灾能力和数据一致性。
副本集至少包含:
- 一个主节点(Primary):可读可写。
- 一个或多个从节点(Secondary):只读,从主节点同步数据。
- (可选)一个仲裁节点(Arbiter):用于投票选主,但不存数据。
🔄 它的作用包括:
特性 | 说明 |
---|---|
数据高可用 | 主挂了,从会自动升级为新主。应用无需干预即可继续访问 |
自动故障转移 | 系统自动检测宕机并重新选主 |
数据冗余 | 所有节点自动同步数据,避免单点丢失 |
支持读写分离 | 某些从节点可设为只读分流 |
✅ 为什么这里要配置副本集?
在你的 docker-compose.yml
中,你启动了一个 MongoDB 实例并启用了副本集:
command: mongod --keyFile /data/mongodb.key --replSet rs0
这说明你是以 副本集模式启动 MongoDB 的,即使当前只有一个节点(也称为单节点副本集),也是必要的,原因如下:
✅ 原因一:支持事务
MongoDB 的多文档事务功能仅在 副本集或分片集群中启用。即使是单节点,也必须配置副本集来使用事务功能。
✅ 原因二:兼容未来扩展
一旦你未来需要添加多个 Mongo 节点(如主备架构),不需重构,只要加节点就行。
✅ 原因三:有些高级功能必须依赖副本集
如:
- Change Streams(变更监听)
- 写操作的确认机制(Write Concern)
- 复制集级别的状态监控
✅ 为什么要写这段 JavaScript 初始化脚本?
MongoDB 副本集启动后,默认不会自动初始化副本集配置,所以你需要执行:
rs.initiate({
_id: "rs0",
members: [{ _id: 0, host: "mongo:27017" }]
})
这段脚本的目的:
脚本功能 | 说明 |
---|---|
rs.status() | 查看副本集是否已初始化 |
rs.initiate(...) | 初始化副本集,指定 ID 和节点信息 |
host: "mongo:27017" | 这个 mongo 对应 docker-compose 中的服务名,用于容器内访问 |
_id: 0 | 成员唯一编号 |
_id: "rs0" | 副本集的唯一名称,需与启动参数 --replSet rs0 保持一致 |
host: "mongo:27017"
这里端口对应容器内端口, 详情请参考这篇文章: mongodb副本集部署脚本解释
⛔ 不写这段脚本会怎样?
如果你不执行 rs.initiate()
:
- MongoDB 虽然以副本集模式启动,但没有初始化,处于“未就绪”状态。
- 你连接 Mongo 执行写操作时会出错,如“not master and slaveOk=false”。
- 事务、Change Streams 等高级功能也无法使用。
✅ 总结
项目 | 说明 |
---|---|
什么是副本集 | MongoDB 的高可用机制,支持主从同步与容灾 |
为什么启用副本集 | 为了使用事务等功能,即使单节点也需要 |
为什么写初始化脚本 | 启用副本集后还必须执行初始化指令,否则无法写入数据 |