官方文档:
https://www.mongodb.com/zh-cn/docs/v8.0/tutorial/deploy-replica-set/
其实过程不复杂, 但是存在一些权限的问题. 而且 mongo的错误提示并不友好, 甚至还有来自官方的坑. 过程可分为 3 步:
- 生成
keyFile - 编写
docker-compose.yml并启动容器 - 查看 mongo 副本模式状态
mongodb 版本: 8.0.14
生成 keyFile
这步很关键, 因为8.x 版本开启副本模式强制依赖密钥文件. 否则你会得到下面的报错:
BadValue: security.keyFile is required when authorization is enabled with replica sets
坑爹的官方文档里当然不会和你讲这一步的必要性. 生成的命令很简单:
# 生成密钥文件(权限必须为 600 或更严格)
openssl rand -base64 756 > mongo-keyfile
chmod 600 mongo-keyfile
chown 101:101 mongo-keyfile
其中 chmod 和 chown 必须要执行, 否则启动阶段会出现
error opening file: /data/mongo-keyfile: bad file
原因有二:
- mongodb 会检查
keyFile权限是否为600, 否则会出现权限错误. 因此不能粗暴的把权限设置为777 - 要求权限为
600即-rw-------, 因此文件 owner 需要和镜像中保持一致.
那么镜像中使用的是什么用户呢? 第一反应去看看 mongod 的 dockerfile 怎么写的:
...
FROM ubuntu:noble
# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
RUN set -eux; \
groupadd --gid 999 --system mongodb; \
useradd --uid 999 --system --gid mongodb --home-dir /data/db mongodb; \
mkdir -p /data/db /data/configdb; \
chown -R mongodb:mongodb /data/db /data/configdb
...
dockerfile 链接 mongo dockerfile
原来是UID=999, GID=999, 那为什么上面的命令是101:101 呢? 是不是写错了 ?
是的, 坑爹的 dockerfile 又误导了我, 折腾了半天最后打印当前的用户的时候发现根本不是999 . 我突然释怀的笑了, 哈哈哈
编写 dockerfile & 启动容器
先看看目录结构:
tree .
.
├── docker-compose.yml
├── mongo-keyfile
└── scripts
└── init-replica.js
dockerfile
version: '3.8'
services:
# MongoDB 主节点
mongo1:
image: mongodb/mongodb-community-server:8.0.14
container_name: mongo1
restart: always
environment:
- MONGODB_INITDB_ROOT_USERNAME=admin
- MONGODB_INITDB_ROOT_PASSWORD=password
ports:
- "27017:27017"
# Mongodb UserID:GroupID
#user: "101:101" # 使用宿主机当前用户的 UID/GID
volumes:
- mongo1_data:/data/db
- ./scripts:/scripts
- ./mongo-keyfile:/data/mongo-keyfile
networks:
- mongo_cluster
# command: /bin/bash -c 'id && id mongodb && ls -ld /data/db && touch /data/db/test && ls -l /data/db && mongod --replSet rs0 --bind_ip_all --port 27017 --keyFile /data/mongo-keyfile'
command: mongod --replSet rs0 --bind_ip_all --port 27017 --keyFile /data/mongo-keyfile
# MongoDB 从节点 1
mongo2:
image: mongodb/mongodb-community-server:8.0.14
container_name: mongo2
restart: always
environment:
- MONGODB_INITDB_ROOT_USERNAME=admin
- MONGODB_INITDB_ROOT_PASSWORD=password
ports:
- "27018:27017"
volumes:
- mongo2_data:/data/db
- ./mongo-keyfile:/data/mongo-keyfile
networks:
- mongo_cluster
command: mongod --replSet rs0 --bind_ip_all --port 27017 --keyFile /data/mongo-keyfile
# MongoDB 从节点 2
mongo3:
image: mongodb/mongodb-community-server:8.0.14
container_name: mongo3
restart: always
environment:
- MONGODB_INITDB_ROOT_USERNAME=admin
- MONGODB_INITDB_ROOT_PASSWORD=password
ports:
- "27019:27017"
volumes:
- mongo3_data:/data/db
- ./mongo-keyfile:/data/mongo-keyfile
networks:
- mongo_cluster
command: mongod --replSet rs0 --bind_ip_all --port 27017 --keyFile /data/mongo-keyfile
# 初始化副本集的临时容器
mongo-init-replica:
image: mongodb/mongodb-community-server:8.0.14
container_name: mongo-init-replica
volumes:
- ./scripts:/scripts
depends_on:
- mongo1
- mongo2
- mongo3
networks:
- mongo_cluster
command: >
bash -c "
sleep 10 &&
mongosh --host mongo1:27017 -u admin -p password --authenticationDatabase admin /scripts/init-replica.js
"
networks:
mongo_cluster:
driver: bridge
volumes:
mongo1_data:
mongo2_data:
mongo3_data:
初始化脚本
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "mongo1:27017" },
{ _id: 1, host: "mongo2:27017" },
{ _id: 2, host: "mongo3:27017" }
]
});
// 等待副本集初始化完成
sleep(2000);
// 查看副本集状态
rs.status();
启动容器
docker-compose up -d
验证
- 进入主节点容器
# 进入主节点容器
docker exec -it mongo1 mongosh -u admin -p password --authenticationDatabase admin
# 在 mongo shell 中查看状态
rs.status()
- 验证主从关系:
# 在 mongo shell 中执行
rs0 [direct: primary] test> rs.isMaster()
{
topologyVersion: {
processId: ObjectId('68d53800e2f75911db84c2e0'),
counter: Long('6')
},
hosts: [ 'mongo1:27017', 'mongo2:27017', 'mongo3:27017' ],
setName: 'rs0',
setVersion: 1,
ismaster: true,
secondary: false,
primary: 'mongo1:27017',
me: 'mongo1:27017',
electionId: ObjectId('7fffffff0000000000000002'),
lastWrite: {
opTime: { ts: Timestamp({ t: 1758807369, i: 1 }), t: Long('2') },
lastWriteDate: ISODate('2025-09-25T13:36:09.000Z'),
majorityOpTime: { ts: Timestamp({ t: 1758807369, i: 1 }), t: Long('2') },
majorityWriteDate: ISODate('2025-09-25T13:36:09.000Z')
},
maxBsonObjectSize: 16777216,
maxMessageSizeBytes: 48000000,
maxWriteBatchSize: 100000,
localTime: ISODate('2025-09-25T13:36:09.953Z'),
logicalSessionTimeoutMinutes: 30,
connectionId: 67,
minWireVersion: 0,
maxWireVersion: 25,
readOnly: false,
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1758807369, i: 1 }),
signature: {
hash: Binary.createFromBase64('dw26T3C3/4wkdyQo3IDDZPDNc9E=', 0),
keyId: Long('7554004955699347462')
}
},
operationTime: Timestamp({ t: 1758807369, i: 1 }),
isWritablePrimary: true
}
1957

被折叠的 条评论
为什么被折叠?



