搭建 MongoDB 复制集

前言

本文将介绍使用 Docker 搭建 MongoDB 复制集(一主二从),阅读本文需要有 Docker 和 MongoDB 的基础。

准备

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
version: "3.7"

services:
mongodb-rs1:
restart: 'no'
image: mongo:latest
container_name: mongodb-rs1
ports:
- 28017:27017
command: mongod --replSet rs0 --bind_ip 0.0.0.0

mongodb-rs2:
restart: 'no'
image: mongo:latest
container_name: mongodb-rs2
ports:
- 28018:27017
command: mongod --replSet rs0 --bind_ip 0.0.0.0

mongodb-rs3:
restart: 'no'
image: mongo:latest
container_name: mongodb-rs3
ports:
- 28019:27017
command: mongod --replSet rs0 --bind_ip 0.0.0.0

mongodb-setup:
restart: 'no'
image: mongo:latest
container_name: "mongodb-setup"
depends_on:
- mongodb-rs1
- mongodb-rs2
- mongodb-rs3
volumes:
- ./scripts:/scripts
entrypoint: "/scripts/setup.sh"

mongodb-rs1 mongodb-rs2 mongodb-rs3 是三个 MongoDB 实例,mongodb-rs1 用做主节点,其余两个用做从节点。

mongodb-setup 用做配置复制集,需要等三个 MongoDB 实例全部启动后执行 setup.sh。

mongod –replSet rs0 –bind_ip 0.0.0.0

replSet:指定配置集的名称是 rs0

bind_ip:任意 IP 都能连接

setup.sh

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
#!/bin/bash
echo "Waiting for startup.."
until mongo mongodb-rs1:27017 --eval 'db.runCommand({ ping: 1 }).ok' &>/dev/null
do
printf '.'
sleep 1
done

echo "Started.."
mongo mongodb-rs1:27017 << EOF
rs.initiate({
_id: "rs0",
members: [
{
_id: 0,
host: "mongodb-rs1:27017"
},
{
_id: 1,
host: "mongodb-rs2:27017"
},
{
_id: 2,
host: "mongodb-rs3:27017"
}]
})
EOF
echo "Success.."

虽然在 docker-compose.yml 中 mongodb-setup 配置了 depends_on ,会先启动 mongodb-rs1,mongodb-rs2,mongodb-rs3,再启动 mongodb-setup。这里需要注意 mongodb-setup 服务不会等待 mongodb-rs1「完全启动」之后再启动

1
2
3
4
5
until mongo mongodb-rs1:27017 --eval 'db.runCommand({ ping: 1 }).ok' &>/dev/null
do
printf '.'
sleep 1
done

上面这一段脚本起到了自旋的作用,保证 mongodb-rs1 「完全启动」之后再往下执行。

搭建

  1. CD 到 docker-compose.yml 同一目录
  2. 创建 scripts 文件夹,并把 setup.sh 放入此文件夹中
  3. 执行 docker-compose up -d

测试

因为给每个 MongoDB 都做了端口映射。直接在宿主机上执行 mongo --port 28017进入 mongodb-rs1 复制集主节点。

执行 rs.status()查看复制集状态 看返回值中 members 中复制集成员信息。

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
"members" : [
{
"_id" : 0,
"name" : "mongodb-rs1:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 3758,
"optime" : {
"ts" : Timestamp(1649167363, 1),
"t" : NumberLong(1)
},
...
},
{
"_id" : 1,
"name" : "mongodb-rs2:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 3756,
"optime" : {
"ts" : Timestamp(1649167363, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1649167363, 1),
"t" : NumberLong(1)
},
...
},
{
"_id" : 2,
"name" : "mongodb-rs3:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 3756,
"optime" : {
"ts" : Timestamp(1649167363, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1649167363, 1),
"t" : NumberLong(1)
},
...
}
],

在主节点进行写入 db.test.insert({ a:1 })

宿主机执行mongo --port 28018进入 mongodb-rs2 从节点

mongodb-rs2 从节点执行rs.secondaryOk()

使从节点支持读取

mongodb-rs2 从节点执行db.test.find()返回

1
{ "_id" : ObjectId("624c5090773e89699a369787"), "a" : 1 }

同样也可以进入 mongodb-rs3 进行验证,同 mongodb-rs2 ,这里就不做演示了。

总结

MongoDB 作为 NoSQL 数据库,同样也是分布式数据库,配置复制集相对来说还是比较简单的。