原文:https://www.yuque.com/wfzx/ninzck/dagu5akm0ztfuobw?singleDoc# 《基于Docker的MongoDB集群搭建》
在Window 10上使用 VMware 开启四个 Ubuntu 18 的虚拟主机。
MongoDB A:192.168.204.156(主节点)
MongoDB B:192.168.204.157
MongoDB C:192.168.204.158
MongoDB D:192.168.204.159
host文件位于 C:\Windows\System32\drivers\etc\hosts
192.168.204.156 mongodba
192.168.204.157 mongodbb
192.168.204.158 mongodbc
192.168.204.159 mongodbd
实验的MongoDB版本:MongoDB server version: 5.0.5
# 查询镜像
root@ubuntu:/home/liangshijie/mongodb-docker-file# docker search mongodb
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mongo MongoDB document databases provide high avai… 9439 [OK]
mongo-express Web-based MongoDB admin interface, written w… 1279 [OK]
bitnami/mongodb Bitnami MongoDB Docker Image 205 [OK]
percona/percona-server-mongodb Percona Server for MongoDB docker images 36
rapidfort/mongodb RapidFort optimized, hardened image for Mong… 15
circleci/mongo CircleCI images for MongoDB 12 [OK]
bitnami/mongodb-sharded 9
...
# 拉取第一个
docker pull mongo
官方文档:https://www.mongodb.com/compatibility/docker
# 创建基本目录
cd /home/liangshijie/mongodb-docker-file
# 要注意创建的文件夹docker进程是否有权限操作
mkdir data
mkdir log
mkdir conf
chmod 777 data
# 创建日志文件。 # 提高权限,不然权限错误
touch ./log/mongod.log
chmod 777 ./log/mongod.log
# 生成密钥文件。
# 后续要将密钥文件拷贝到从服务器,所以在降低key.file密钥文件权限前,你可能需要先将其拷贝到其它服务器。
openssl rand -base64 756 > ./conf/key.file
# 降低权限,不然权限错误
chmod 400 ./conf/key.file
# 创建配置文件。具体内容看后面
vim ./conf/mongod.conf.orig
# mongod.conf
# for documentation of all options, see:
# http://docs.mongodb.org/manual/reference/configuration-options/
# Where and how to store data.
storage:
dbPath: /var/lib/mongodb # 数据存储的目录,默认就好
journal:
enabled: true
# engine:
# wiredTiger:
# where to write logging data.
systemLog:
destination: file # 日志写入到文件
logAppend: true # 追加的方式
path: /var/log/mongodb/mongod.log # 日志文件位置,默认就好
# network interfaces
#net:
# port: 27017
# bindIp: 127.0.0.1
# how the process runs
processManagement:
timeZoneInfo: /usr/share/zoneinfo
#security:
#security:
# keyFile: /data/configdb/key.file # 集群节点之间使用我们生成的密钥进行权限验证
#replication:
# replSetName: mongoCluster # 指定集群名称
net:
bindIp: mongodba # 要绑定的地址,一般不写IP
#operationProfiling:
#replication:
#sharding:
## Enterprise-Only Options:
#auditLog:
#snmp:
温馨提示,后续要将密钥文件拷贝到服务器,所以在降低
key.file
密钥文件权限前,你可能需要先将其拷贝到其它服务器。
docker run -u root --name mongodb -d -p 27017:27017 \
-v /home/liangshijie/mongodb-docker-file/data:/var/lib/mongodb \
-v /home/liangshijie/mongodb-docker-file/conf:/data/configdb \
-v /home/liangshijie/mongodb-docker-file/log:/var/log/mongodb \
--hostname="mongodba" \
mongo --config /data/configdb/mongod.conf.orig
由于指定了日志文件的位置,所以使用容器命令
docker logs -f
是不会打印日志的,日志输出到这个位置了:./log/mongod.log。
配置文件mongod.conf.orig
的位置指定的是容器内的位置。
如果只是想快速启动一个 MongoDB 容器,可以使用这条命令:
docker run --name mongodb -d -p 27017:27017 -v /home/liangshijie/mongodb-docker-file/data:/data/db -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD=123456 mongo
# 进入容器
docker exec -it <容器ID> bash
cd /usr/bin
mongo --host mongodba
# 创建管理员用户(用于登录主节点初始化集群)
db.createUser( {
user: "root",
pwd: "123456",
roles: [ { role: "root", db: "admin" } ]
});
# 创建读写用户(可以后面再创建,用于主节点的读写操作,在从节点登录只能只读)
db.createUser({ user:'user',pwd:'123456',roles:[ { role:'readWrite', db: 'study'}]});
# 退出
exit
集群通信需要密钥。
vim ./conf/mongod.conf.orig
# 在上面的配置文件中,我已经写好了配置,只需要把下面的注释放开即可:
security:
keyFile: /data/configdb/key.file # 集群节点之间使用我们生成的密钥进行权限验证
replication:
replSetName: mongoCluster # 指定集群名称
# 可选,降低配置文件的权限
chmod 400 ./conf/mongod.conf.orig
为什么之前不放开配置?因为一早放开的话没有权限创建用户,等创建好用户再放开。
docker restart <容器ID>
# 进入容器
docker exec -it <容器ID> bash
cd /usr/bin
# 登录
mongo --host mongodba
# 认证
db.auth("root","123456")
# 初始化
rs.initiate()
# 结果如下:
{
"info2" : "no configuration specified. Using a default configuration for the set",
"me" : "mongodba:27017",
"ok" : 1
}
# 查看状态
rs.status()
# 在从节点已经就绪的情况下,我们也可以通过下面配置初始化集群。
var cfg ={"_id":"heroMongoCluster",
"protocolVersion" : 1,
"members":[
{"_id":1,"host":"mongodba:27017","priority":10},
{"_id":2,"host":"mongodbb:27017","priority":1},
{"_id":2,"host":"mongodbc:27017","priority":1},
{"_id":2,"host":"mongodbd:27017","priority":1}
]
};
rs.initiate(cfg)
从节点跳过生成密钥的步骤。
# 创建基本目录
cd /home/liangshijie/mongodb-docker-file
# 要注意创建的文件夹docker进程是否有权限操作
mkdir data
mkdir log
mkdir conf
chmod 777 data
# 创建日志文件。 # 提高权限,不然权限错误
touch ./log/mongod.log
chmod 777 ./log/mongod.log
# 创建配置文件。具体复制后面的
vim ./conf/mongod.conf.orig
# 最后降低权限(可选)
chmod 400 ./conf/mongod.conf.orig
跟主节点配置不一样的地方就是,一开始就放开 security 的注释,在这里,需要注意修改bindIp的值,完整配置如下:
# mongod.conf
# for documentation of all options, see:
# http://docs.mongodb.org/manual/reference/configuration-options/
# Where and how to store data.
storage:
dbPath: /var/lib/mongodb # 数据存储的目录,默认就好
journal:
enabled: true
# engine:
# wiredTiger:
# where to write logging data.
systemLog:
destination: file # 日志写入到文件
logAppend: true # 追加的方式
path: /var/log/mongodb/mongod.log # 日志文件位置,默认就好
# network interfaces
#net:
# port: 27017
# bindIp: 127.0.0.1
# how the process runs
processManagement:
timeZoneInfo: /usr/share/zoneinfo
#security:
security:
keyFile: /data/configdb/key.file # 集群节点之间使用我们生成的密钥进行权限验证
replication:
replSetName: mongoCluster # 指定集群名称
net:
bindIp: mongodbb # 要绑定的地址,一般不写IP
#operationProfiling:
#replication:
#sharding:
## Enterprise-Only Options:
#auditLog:
#snmp:
将主节点的 key.file 文件复制到从节点的 ./conf 目录下。(不拷贝文件也行,cat输出文件内容,复制粘贴也是可以的)
遇到拷贝不进conf的情况,请检查目录权限。 chmod 777 ./conf 开放上传之后,再 chmod 755 ./conf 收回。
注意,conf目录下的 key.file 权限是 400。 配置文件是 755
docker run --name mongodb -d -p 27017:27017 \
-v /home/liangshijie/mongodb-docker-file/data:/var/lib/mongodb \
-v /home/liangshijie/mongodb-docker-file/conf:/data/configdb \
-v /home/liangshijie/mongodb-docker-file/log:/var/log/mongodb \
--hostname="mongodbb" \
mongo --config /data/configdb/mongod.conf.orig
同理,其它几个从节点也是这样配置,注意,要改一下配置文件中 bindIp
属性,以及启动命令中--hostname
的属性。
你需要确保主、从节点容器之间能正常通信。如果你想在容器内测试能不能ping同其它主机的mongo服务,可以在容器内安装ping:
apt-get update
apt-get install iputils-ping
# 进入主节点的mongodb容器
docker exec -it <容器ID> bash
cd /usr/bin
# 登录
mongo --host mongodba
# 认证
db.auth("root","123456")
# 增加从节点
rs.add("mongodbb:27017")
# 执行结果:
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1675486280, 1),
"signature" : {
"hash" : BinData(0,"cwO0f4QXhKNfNGKZstysMTqrQ9w="),
"keyId" : NumberLong("7196151896959090692")
}
},
"operationTime" : Timestamp(1675486280, 1)
}
rs.add("mongodbc:27017")
rs.add("mongodbd:27017")
# 删除slave 节点
rs.remove("172.17.187.80:37019")
rs.conf()
{
"_id" : "mongoCluster",
"version" : 9,
"term" : 1,
"members" : [
{
"_id" : 0,
"host" : "mongodba:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"secondaryDelaySecs" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "mongodbb:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"secondaryDelaySecs" : NumberLong(0),
"votes" : 1
},
{
"_id" : 3,
"host" : "mongodbc:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"secondaryDelaySecs" : NumberLong(0),
"votes" : 1
},
{
"_id" : 4,
"host" : "mongodbd:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"secondaryDelaySecs" : NumberLong(0),
"votes" : 1
}
],
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("63ddde05097f7140da2e9c0a")
}
}
执行 rs.status()
查看状态,在 members
属性中可以看到节点列表信息。
rs.status()
{
"set" : "mongoCluster",
"date" : ISODate("2023-02-04T04:52:11.084Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"majorityVoteCount" : 2,
"writeMajorityCount" : 2,
"votingMembersCount" : 2,
"writableVotingMembersCount" : 2,
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1675486328, 1),
"t" : NumberLong(1)
},
"lastCommittedWallTime" : ISODate("2023-02-04T04:52:08.443Z"),
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1675486328, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1675486328, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1675486328, 1),
"t" : NumberLong(1)
},
"lastAppliedWallTime" : ISODate("2023-02-04T04:52:08.443Z"),
"lastDurableWallTime" : ISODate("2023-02-04T04:52:08.443Z")
},
"lastStableRecoveryTimestamp" : Timestamp(1675486292, 1),
"electionCandidateMetrics" : {
"lastElectionReason" : "electionTimeout",
"lastElectionDate" : ISODate("2023-02-04T04:24:38.141Z"),
"electionTerm" : NumberLong(1),
"lastCommittedOpTimeAtElection" : {
"ts" : Timestamp(1675484677, 1),
"t" : NumberLong(-1)
},
"lastSeenOpTimeAtElection" : {
"ts" : Timestamp(1675484677, 1),
"t" : NumberLong(-1)
},
"numVotesNeeded" : 1,
"priorityAtElection" : 1,
"electionTimeoutMillis" : NumberLong(10000),
"newTermStartDate" : ISODate("2023-02-04T04:24:38.243Z"),
"wMajorityWriteAvailabilityDate" : ISODate("2023-02-04T04:24:38.285Z")
},
"members" : [
{
"_id" : 0,
"name" : "mongodba:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1932,
"optime" : {
"ts" : Timestamp(1675486328, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2023-02-04T04:52:08Z"),
"lastAppliedWallTime" : ISODate("2023-02-04T04:52:08.443Z"),
"lastDurableWallTime" : ISODate("2023-02-04T04:52:08.443Z"),
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1675484678, 1),
"electionDate" : ISODate("2023-02-04T04:24:38Z"),
"configVersion" : 4,
"configTerm" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "172.17.187.80:37019",
"health" : 0,
"state" : 8,
"stateStr" : "(not reachable/healthy)",
"uptime" : 0,
"optime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDurable" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
"lastAppliedWallTime" : ISODate("1970-01-01T00:00:00Z"),
"lastDurableWallTime" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2023-02-04T04:52:09.266Z"),
"lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "Error connecting to 172.17.187.80:37019 :: caused by :: No route to host",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"configVersion" : -1,
"configTerm" : -1
},
{
"_id" : 2,
"name" : "mongodbb:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 50,
"optime" : {
"ts" : Timestamp(1675486328, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1675486328, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2023-02-04T04:52:08Z"),
"optimeDurableDate" : ISODate("2023-02-04T04:52:08Z"),
"lastAppliedWallTime" : ISODate("2023-02-04T04:52:08.443Z"),
"lastDurableWallTime" : ISODate("2023-02-04T04:52:08.443Z"),
"lastHeartbeat" : ISODate("2023-02-04T04:52:10.446Z"),
"lastHeartbeatRecv" : ISODate("2023-02-04T04:52:11.046Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncSourceHost" : "mongodba:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 4,
"configTerm" : 1
}
],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1675486328, 1),
"signature" : {
"hash" : BinData(0,"qdS8hsuZZ6jdGUDjvFV2bKIFxkE="),
"keyId" : NumberLong("7196151896959090692")
}
},
"operationTime" : Timestamp(1675486328, 1)
}
容器重启一般要重新进行同步
use study
# 登录从节点, 执行同步语句
db.auth("user", "123456")
# 同步。低版本的命令: rs.slaveOk()
rs.secondaryOk()
show dbs
# 进入主节点执行
docker exec -it <容器ID> bash
cd /usr/bin
mongo --host mongodba
db.auth("user","123456")
use study
db.myt.insertMany([
{xm:"李四",age:24},
{xm:"王五",age:25},
{xm:"赵六",age:26},
{xm:"李四",age:34},
{xm:"王五",age:35},
{xm:"赵六",age:36}
])
db.myt.insertMany([
{xm:"孙七",age:44},
])
# 登录从节点
use study
db.auth("user", "123456")
use study
db.myt.find()
var cfg ={"_id":"heroMongoCluster",
"protocolVersion" : 1,
"members":[
{"_id":1,"host":"172.17.187.80:37017","priority":10},
{"_id":2,"host":"172.17.187.80:37018","priority":0},
{"_id":3,"host":"172.17.187.80:37019","priority":5},
{"_id":4,"host":"172.17.187.80:37020","arbiterOnly":true}
]
};
// 重新装载配置,并重新生成集群节点。
rs.reconfig(cfg)
rs.addArb("172.17.187.80:37020")