基于 Docker Compose 部署 MongoDB 分片集群

❓ MongoDB Cluster Components

这里示例集群一共三台机器,主机名分别为:ecs12ecs13ecs14

当前部署的 MongoDB 版本为 6.0.13,安装包名称为:mongodb-6.0.13-docker.tar.gz,其中每个节点均包含:router(mongos)configsvr 以及 shard 这 3 个角色。这里的 shard 都是单个独立的分片,不包含对应的副本集。configsvr 包含 3 个副本集。

每个节点都安装 Docker 以及 Docker Compose 插件,Docker 版本必须大于 20.10.10,Docker Compose 网络采用 host 模式部署。

其中每个角色对应的端口如下:

  • Router (mongos):27017
  • Shard:27018
  • Config Server:27019

✨ Steps

Preparing

所有节点执行安装镜像操作:

tar -xvzf mongodb-6.0.13-docker.tar.gz -C /opt
cd /opt/mongodb-6.0.13-docker
./install.sh

每个机器都执行后镜像就导入完毕了。

👉 Step 1: Start all of the containers

之后操作需要进入 Docker Compose 项目具体的安装目录,当前是 /opt/mongodb-6.0.13-docker 目录:

cd /opt/mongodb-6.0.13-docker

编辑 Docker Compose 的配置文件:docker-compose.yml,其中的默认配置如下:

version: '3'
services:

  router:
    image: mongo:6.0.13
    container_name: mongodb-router
    command: mongos --port 27017 --configdb rs-config-server/node1:27019,node2:27019,node3:27019 --bind_ip_all --keyFile=/etc/mongodb/mongodb.key
    restart: always
    network_mode: "host"
    environment:
      - TZ=Asia/Shanghai
    volumes:
      - ./scripts:/scripts
      - ./security:/etc/mongodb
      - /data/mongodb-router/db:/data/db
      - /data/mongodb-router/configdb:/data/configdb

  configsvr:
    image: mongo:6.0.13
    container_name: mongodb-configsvr
    command: mongod --port 27019 --configsvr --replSet rs-config-server --keyFile=/etc/mongodb/mongodb.key --auth
    restart: always
    network_mode: "host"
    environment:
      - TZ=Asia/Shanghai
    volumes:
      - ./scripts:/scripts 
      - ./security:/etc/mongodb
      - /data/mongodb-config/db:/data/db
      - /data/mongodb-config/configdb:/data/configdb

  shard:
    image: mongo:6.0.13
    container_name: mongodb-shard
    command: mongod --port 27018 --shardsvr --replSet rs-shard-01 --keyFile=/etc/mongodb/mongodb.key --auth
    restart: always
    network_mode: "host"
    environment:
      - TZ=Asia/Shanghai
    volumes:
      - ./scripts:/scripts
      - ./security:/etc/mongodb
      - /data/mongodb-shard/db:/data/db
      - /data/mongodb-shard/configdb:/data/configdb

其中分为三个服务,分别是 routerconfigsvr 以及 shard

router 中的 command 配置中要修改其中的主机列表 node1node2node3 为我们当前的主机,即 ecs12ecs13 以及 ecs14,端口号默认不需要修改。

修改 shard 中的 command 配置 --replSet 指定的参数按照节点递增,比如当前 ecs12 设置为 rs-shard-01,那么 ecs13 节点上就要设置为 rs-shard-02ecs14 节点上设置为 rs-shard-03,依此类推。

最后是这 3 个服务的数据目录都要根据实际的设置,要将目录放到专门的数据盘上,推荐使用 SSD 存储,只修改 : 前面的目录即可。

当前 3 个节点全部修改完成之后,所有节点依次执行命令启动:

./mongodb-server.sh start
# 启动后查看状态
./mongodb-server.sh status

如果启动没有问题可以进入下一步的配置了。

👉 Step 2: Initialize the replica sets (config servers and shards)

我们首先初始化 Config Server,在任意一个节点上即可,当前我们在 ecs12 节点上操作,首先编辑 scripts/init-configserver.js 文件,修改其中的主机名例如:

rs.initiate({_id: "rs-config-server", configsvr: true, version: 1, members: [ { _id: 0, host : 'ecs12:27019' }, { _id: 1, host : 'ecs13:27019' }, { _id: 2, host : 'ecs14:27019' } ] })

修改后保存,然后我们执行:

docker-compose -f docker-compose.yml exec configsvr sh -c "mongosh --port 27019 < /scripts/init-configserver.js"

执行成功之后,我们进入客户端确认状态:

./mongodb-client.sh config
# 进入客户端后执行
> rs.status()

即可看到 Config Server 副本集的状态。

然后我们在每个节点都编辑 scripts/init-shard.js,分别修改内容如下:

// ecs12
rs.initiate({_id: "rs-shard-01", version: 1, members: [ { _id: 0, host : "ecs12:27018" } ] })
// ecs13
rs.initiate({_id: "rs-shard-02", version: 1, members: [ { _id: 0, host : "ecs13:27018" } ] })
// ecs14
rs.initiate({_id: "rs-shard-03", version: 1, members: [ { _id: 0, host : "ecs14:27018" } ] })

修改之后保存文件,由于开启了集群认证,因此需要在每个节点单独运行:

# 所有节点都要执行
docker-compose -f docker-compose.yml exec shard sh -c "mongosh --port 27018 < /scripts/init-shard.js"

👉 Step 3: Initializing the router

初始化 mongos 只需要在一个节点执行即可,我们这里在 ecs12 上执行,首先编辑 scripts/init-router.js,修改内容为实际的节点如下:

sh.addShard("rs-shard-01/ecs12:27018")
sh.addShard("rs-shard-02/ecs13:27018")
sh.addShard("rs-shard-03/ecs14:27018")

这个配置要和上一步初始化的名称和节点完全保持一致,修改无误后保存并退出,然后运行:

docker-compose -f docker-compose.yml exec router sh -c "mongosh  --port 27017 < /scripts/init-router.js"

👉 Step 4: Create user in the MongoDB cluster

然后我们需要在集群中创建管理用户:

# 进入到 mongos
./mongodb-client.sh router

进入后执行创建管理用户的操作:

db.getSiblingDB("admin").createUser(
{
    user: "admin",
    pwd: passwordPrompt(),
    roles: [{ role: "root", db: "admin" }]
})

执行后输入密码即可完成创建,但是要注意创建完成后立即生效,必须认证后才可以进行下一步的访问:

use admin
db.auth('admin', '<password>')

认证后即可正常操作,比如查看集群状态:

sh.status()

同样我们访问 Config Server 也是使用相同的管理用户,但是这个用户仅用于管理员维护使用,由于 root 这个 role 权限太高,它包括了集群所有的管理和访问权限,所以我们需要为应用程序创建单独的用户,例如:

db.getSiblingDB("admin").createUser(
{
    user: "web",
    pwd: passwordPrompt(),
    roles: [{ role: "readWrite", db: "dev" }]
})

然后程序可以使用这个示例的 web 用户进行访问。

我们通常都是访问 mongos 角色进行数据的读写,一般不会访问 shard 服务,但是有时候我们可能需要单独的排查 shard 的状态,这个时候只能通过本机 localhost 网络接口访问,远程访问则必须认证,但是这个认证的用户和上面我们创建的管理用户是不一样的,我们也可以为 shard 创建专门的用户,这步是可选的,但是这个用户只用来管理状态,不需要读写数据,例如:

# 必须从本机连接 shard 服务
./mongodb-client.sh shard

然后创建用户:

// 每个 shard 都需要单独创建用户
db.getSiblingDB("admin").createUser(
{
    user: "manager",
    pwd: passwordPrompt(),
    roles: [ { role: "clusterAdmin", db: "admin" } ]
})

然后就可以查看 shard 的状态了:

use admin
db.auth('manager', 'password')
rs.status()

这个用户只能用来连接 shard 且必须每个 shard 从本地单独创建。

👉 Step 5: Enable sharding and setup sharding-key

到这里 MongoDB 分片集群就搭建完毕并正常运行了,我们可以创建分片的 Collection 测试一下是否正常。

任意节点机器连接 MongoDB 集群的 mongos 服务:

./mongodb-client.sh router

认证并设置 Collection 的分片策略:

use admin
db.auth('admin', '<password>')
// 例如设置 hash 分片策略,设置时会自动创建 Database 和 Collection
sh.shardCollection("test.col", { _id : "hashed" } )

插入一批测试数据:

use test

for(i = 0; i < 100; i++) {
    var doc = {_id: i};
    if(i % 2 == 0)
        doc.value = "even";
    else
        doc.value = "odd";
    db.col.insertOne(doc);
}

// 或者批量写入
var arr = [];
for(i = 0; i < 100; i++) {
    var doc = {_id: i};
    if(i % 2 == 0)
        doc.value = "even";
    else
        doc.value = "odd";
    arr.push(doc);
}
db.col.insertMany(arr);

然后可以查看 Collection 的数据分布情况:

// 可以看到总条数以及每个节点的条数情况
db.col.getShardDistribution()

删除测试的 Collection:

db.col.drop()

Reference:

  1. Deploy a Sharded Cluster
  2. Deploy Replica Set With Keyfile Authentication