当前我们使用docker-compose 的方式部署mongodb 副本集。当然,最佳还是使用kubernetes进行mongodb副本集的部署。
1.安装docker,docker-compose
openssl rand -base64 756 > mongodb.key
chown 999:999 mongodb.key
这是一份docker-compose.yaml示例。其中需要提前在节点上创建对应的**/data/mongo/data/mongo(i)**目录,需要与mongodb.key文件在统一目录下。
version: '3.3'
services:
mongodb1:
image: mongo:4.4.8
volumes:
- /data/mongo/data/mongo1:/data/db
- ./mongodb.key:/data/mongodb.key
user: root
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=admin
container_name: mongodb1
ports:
- 37017:27017
command: mongod --replSet mongos --keyFile /data/mongodb.key
restart: always
entrypoint:
- bash
- -c
- |
chmod 400 /data/mongodb.key
chown 999:999 /data/mongodb.key
exec docker-entrypoint.sh $$@
mongodb2:
image: mongo:4.4.8
volumes:
- /data/mongo/data/mongo2:/data/db
- ./mongodb.key:/data/mongodb.key
user: root
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=admin
container_name: mongodb2
ports:
- 37018:27017
command: mongod --replSet mongos --keyFile /data/mongodb.key
restart: always
entrypoint:
- bash
- -c
- |
chmod 400 /data/mongodb.key
chown 999:999 /data/mongodb.key
exec docker-entrypoint.sh $$@
mongodb3:
image: mongo:4.4.8
volumes:
- /data/mongo/data/mongo3:/data/db
- ./mongodb.key:/data/mongodb.key
user: root
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=admin
container_name: mongodb3
ports:
- 37019:27017
command: mongod --replSet mongos --keyFile /data/mongodb.key
restart: always
entrypoint:
- bash
- -c
- |
chmod 400 /data/mongodb.key
chown 999:999 /data/mongodb.key
exec docker-entrypoint.sh $$@
切换到docker-compose.yaml文件所在目录,执行以下启动命令:
docker-compose up -d
预期结果:
[root@test01 mongo]# docker ps | grep mongo
97af9e11c66d mongo:4.4.8 "bash -c 'chmod 400 …" About an hour ago Up About an hour 0.0.0.0:37019->27017/tcp, :::37019->27017/tcp mongodb3
63ee9801d66f mongo:4.4.8 "bash -c 'chmod 400 …" About an hour ago Up About an hour 0.0.0.0:37017->27017/tcp, :::37017->27017/tcp mongodb1
9c15ed7476ba mongo:4.4.8 "bash -c 'chmod 400 …" About an hour ago Up About an hour 0.0.0.0:37018->27017/tcp, :::37018->27017/tcp mongodb2
此时,三个mongo实例已经运行起来了,接下来我们需要将这三个mongo实例配置为一个集群。
通过命令docker exec -it mongodb1 /bin/bash
进入容器进行配置
进入集群后,执行 mongo -u root -p admin
连接集群,连接成功后如下所示:
root@63ee9801d66f:/# mongo -u root -p admin
MongoDB shell version v4.4.8
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("c69a9e0b-e52e-4224-bc81-3f2d09060434") }
MongoDB server version: 4.4.8
---
The server generated these startup warnings when booting:
2022-03-08T07:13:51.708+00:00: You are running on a NUMA machine. We suggest launching mongod like this to avoid performance problems: numactl --interleave=all mongod [other options]
2022-03-08T07:13:51.708+00:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never'
---
---
Enable MongoDB's free cloud-based monitoring service, which will then receive and display
metrics about your deployment (disk utilization, CPU, operation statistics, etc).
The monitoring data will be available on a MongoDB website with a unique URL accessible to you
and anyone you share the URL with. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you.
To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---
在没有初始化副本集的集群中,执行rs.status();
命令会得到以下结果:
> rs.status()
{
"ok" : 0,
"errmsg" : "command replSetGetStatus requires authentication",
"code" : 13,
"codeName" : "Unauthorized"
}
根据mongo服务的地址进行集群初始化:
> rs.initiate({ _id: "mongos", members: [
{ _id : 0, host : "10.81.138.205:37017" },
{ _id : 1, host : "10.81.138.205:37018" },
{ _id : 2, host : "10.81.138.205:37019" },
]});
其中 “mongos”
是在docker-compose.yaml文件中指定的副本集名称,可根据实际情况修改。
host
后面紧跟着的是刚刚部署的三台mongo的地址(hostIP + port),端口号为docker-compose.yaml中映射的端口号,可根据服务器上的端口使用情况进行调整。
预期结果:
{ "ok" : 1 }
初始化完成后执行rs.status();
此时命令行中会输出以下文本:
mongos:SECONDARY> rs.status();
{
"set" : "mongos",
"date" : ISODate("2022-03-08T06:37:31.168Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncSourceHost" : "",
"syncSourceId" : -1,
... ...
"members" : [
{
"_id" : 0,
"name" : "10.81.138.205:37017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 32,
"optime" : {
"ts" : Timestamp(1646721451, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2022-03-08T06:37:31Z"),
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "Could not find member to sync from",
"electionTime" : Timestamp(1646721450, 1),
"electionDate" : ISODate("2022-03-08T06:37:30Z"),
"configVersion" : 1,
"configTerm" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
},
... ...
到这里集群的部署就完成了。
MongoDB复制集里Primary节点是不固定的,当遇到复制集轮转升级、Primary宕机、网络分区等场景时,复制集可能会选举出一个新的Primary,而原来的Primary则会降级为Secondary,即发生主备切换。
总而言之,MongoDB复制集里Primary节点是不固定的,不固定的,不固定的,重要的事情说3遍。
当连接复制集时,如果直接指定Primary
的地址来连接,当时可能可以正确读写数据的,但一旦复制集发生主备切换,你连接的Primary会降级为Secondary,你将无法继续执行写操作,这将严重影响到你的线上服务。
所以生产环境千万不要直连Primary,千万不要直连Primary,千万不要直连Primary。
要正确连接复制集,需要先了解下MongoDB的Connection String URI,所有官方的driver都支持以Connection String的方式来连接MongoDB。
下面就是Connection String包含的主要内容
mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]
以205上的mongo副本集为例,正确的连接方式如下:
mongodb://root:[email protected]:37017,10.81.138.205:37018,10.81.138.205:37019/?replicaSet=mongos&readPreference=primary