使用 DockerCompose 搭建 MongoDB 副本集

本文介绍如何在 Linux 系统中通过 docker-compose 创建 MongoDB 副本集,若是 Windows,可以进入到 WSL 中进行部署。

生成 KeyFile

  • MongoDB 使用 KeyFile 认证,副本集中的每个 mongodb 实例使用 KeyFile 内容作为认证其他成员的共享密码mongod实例只有拥有正确的keyfile才可以加入副本集
  • KeyFile 的内容必须是 6~1024 个字符的长度,且副本集所有成员的 KeyFile 内容必须相同。
  • KeyFile 应允许所有者读取,权限可以设置为 400
  • 可以使用任意方法生成 KeyFile。例如,如下操作使用 openssl 生成复杂的随机的1024个字符串。
1
2
mkdir data && cd data
openssl rand -base64 800 > mongodb.key

详细的docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# docker-compose
# 最新版本的 docker-compose 会自动识别 version
# version: "3.9"

services:
# mongodb 服务
# 节点1
mongodb27018:
hostname: mongodb27018
container_name: mongodb27018
image: mongo:latest
expose:
- 27018
ports:
- 27018:27017
restart: always
environment:
- TZ:'Asia/Shanghai'
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=yourPassword
command: mongod --bind_ip_all --replSet rs_share --keyFile /data/mongodb.key
volumes:
- ./data/rs1/db:/data/db
- ./data/rs1/configdb:/data/configdb
- ./data/mongodb.key:/data/mongodb.key
networks:
- mongodb_network
entrypoint:
- bash
- -c
- |
chmod 400 /data/mongodb.key
chown 999:999 /data/mongodb.key
exec docker-entrypoint.sh $$@

# 副节点
mongodb27019:
hostname: mongodb27019
container_name: mongodb27019
image: mongo:latest
expose:
- 27019
ports:
- 27019:27017
restart: always
environment:
- TZ:'Asia/Shanghai'
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=yourPassword
command: mongod --bind_ip_all --replSet rs_share --keyFile /data/mongodb.key
volumes:
- ./data/rs2/db:/data/db
- ./data/rs2/configdb:/data/configdb
- ./data/mongodb.key:/data/mongodb.key
networks:
- mongodb_network
entrypoint:
- bash
- -c
- |
chmod 400 /data/mongodb.key
chown 999:999 /data/mongodb.key
exec docker-entrypoint.sh $$@
depends_on:
- mongodb27018

mongodb27020:
# Host name = Container name
hostname: mongodb27020
container_name: mongodb27020
image: mongo:latest
expose:
- 27020
ports:
- 27020:27017
restart: always
environment:
- TZ:'Asia/Shanghai'
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=yourPassword
command: mongod --bind_ip_all --replSet rs_share --keyFile /data/mongodb.key
volumes:
- ./data/rs3/db:/data/db
- ./data/rs3/configdb:/data/configdb
- ./data/mongodb.key:/data/mongodb.key
networks:
- mongodb_network
entrypoint:
- bash
- -c
- |
chmod 400 /data/mongodb.key
chown 999:999 /data/mongodb.key
exec docker-entrypoint.sh $$@
depends_on:
- mongodb27019

networks:
# 设置 mongodb_network, 默认为 bridge 模式,参考:https://zhuanlan.zhihu.com/p/212772001
mongodb_network:

创建挂载目录

1
2
3
4
# 进入到 data 目录
mkdir {rs1,rs2,rs3}
# 将 mongodb.key 复制到 rs* 目录中
cp mongodb.key ./rs1/ && cp mongodb.key ./rs2/ && cp mongodb.key ./rs3/

部署容器

进入到 docker-compose.yml 目录,终端中执行 docker compose up -d 或者 docker-compose up -d 来部署容器。

image-20230416124522790

错误处理

错误 1:error during connect: in the default daemon configuration on Windows, the docker client must be run with elevated privileges to connect

docker desktop 没有启动,先启动,再运行

错误 2: Location5579201: Unable to acquire security key[s]

keyFile 权限错误,docker compose down 后,清理挂载的所有文件,重新运行一次。

配置副本集

进入 mongodb

1
2
3
4
5
6
#进入 mongodb27018 的容器内
docker exec -it mongodb27018 bash

# 进入mongo shell
# MongoDB 之前使用 mongo,之后使用 mongosh
mongosh -u root -p yourPassword

The mongo shell is removed from MongoDB 6.0. The replacement is mongosh.

初始化副本集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 切换到 admin
use admin
# 进行授权认证
# 返回 { ok: 1 } 表示成功
db.auth("root","yourPassword")
# 定义配置文件
# 配置中的 host 必须是本机实际的 ip,不能是 127.0.0.1,否则局域网内无法访问
# 如果要通过域名访问,则必须是域名
rsconf = {
_id: "rs_share",
members: [
{
_id: 0,
host: "192.168.3.240:27018"
},
{
_id: 1,
host: "192.168.3.240:27019"
},
{
_id: 2,
host: "192.168.3.240:27020"
}
]
}

# 初始化副本集
rs.initiate(rsconf)

若是只有一个节点,则只需要执行:rs.initiate()

当出现如下提示时,说明成功了:

1
2
{ "ok" : 1 }
rs_auth:SECONDARY>

单主机模式部署 3副本集 添加节点必须使用宿主机IP+PORT,使用容器内部IP的情况下代码层面连接到 mongodb-cluster 集群,获取到的集群地址信息为 docker 容器内部 IP,若业务代码没有部署在 mongodb 主机则无法访问

修改副本集配置

若是更换了主机 IP,则需要重新修改副本集中的 host,可以采用下列方式修改:

先按 进入 mongodb 登陆到 mongodb,然后使用

1
rs.status().members.find(x=>x.stateStr === 'PRIMARY')

来查找主节点。

若当前实例不是主节点,则退出重新登陆到主节点中

修改配置

1
2
3
4
5
6
7
8
9
10
11
# 切换到 admin
use admin
# 进行授权认证
# 返回 { ok: 1 } 表示成功
db.auth("root","yourPassword")
# 获取当前的副本集配置
config = rs.conf();
# 修改配置
config.members[0].host = "newhost:27017";
# 应用新的配置
rs.reconfig(config);

你的 MongoDB 版本是 4.2 或更高版本,可以使用 rs.reconfig() 方法的 force 参数来强制应用新的配置,即使新的配置和当前的配置不兼容:

1
2
# 这个操作可能会导致数据丢失,谨慎使用
rs.reconfig(config, { force: true });

rs.reconfig() 方法会导致副本集的所有成员(包括主节点)重新启动

参考

MongoDB 3 副本集群(Docker-compose部署)(单机模式)