MongoDB Sharded Cluster with Replica Set

MongoDB Sharded Cluster with Replica Set in Docker

Ankit Kumar
7 min readJan 28, 2024

This blog guides you through deploying a sharded cluster using Docker — ideal for local testing, learning, and adding a dash of fun to your database exploration journey. Let’s dive in!

Cluster Components:

The components in a sharded cluster are:

  1. Shards (with replica sets)
  2. Config Server (replica set)
  3. Mongos
MongoDB Sharded Cluster with Replica Set

In total, we’ll have 11 docker containers:

  • 2 shards each of them configured as a replica set with 3 instances i.e. one primary and two secondary.
  • 1 config server configured as a replica set with 3 instances i.e. one primary and two secondary.
  • 2 mongos instances.

Brief introduction to all the components

Replica set

  • A group of 2 or more MongoDB instances that maintain identical data sets to provide high availability.
  • It has 1 primary node for write operation and 1 or more secondary node that replicate data written on primary and allow read operation.
  • If the primary node fails, one of the secondaries is automatically elected to primary, ensuring high availability and fault tolerance.

Shard

  • When sharding is enabled data is broken down and distributed (not replicated) across multiple servers known as shards.
  • This enhances the horizontal scalability, i.e. you can add more shards to the cluster when required.
  • Each shard manages a portion of the dataset, allowing for parallel processing and improved performance.

Config Server

  • It stores metadata and configuration settings for sharded clusters.
  • It keeps track of the sharding key ranges and provide information about the distribution of data across the shards to MongoDB router (mongos) to route queries efficiently to the appropriate shards.
  • Its a single point of failure and to avoid that it’s generally deployed as a replica set.

Mongos

  • It routes client requests to the appropriate shard in a sharded MongoDB cluster.
  • It acts as an interface between the application and the sharded environment, ensuring that read and write operations are seamlessly and correctly distributed among the shards.
  • Its also a single point of failure and to avoid we generally deploy 2 instances of mongos for a sharded cluster.

Prerequisites

  • Docker must be installed and running.
  • Internet connectivity for downloading container images.
  • mongosh command line tool to connect to mongo instances

Lets Deploy

Step 1: Create a docker network

docker network create mongodb-network

In case you already have a network of this name please check if you’re not using it, if not then, try deleting and recreating:

docker network ls                   # shows present networks 
docker network rm mongodb-network # delete network "mongodb-network"

Or you may create a network with another name but make sure to modify the commands mentioned ahead accordingly.

Why create a docker network?

Its not necessary but recommended as it provides better isolation and a more consistent deployment experience.

Step 2: Setup Sharded Clusters with Replica Sets

Shard 1 (mongo-shard1)

docker run -d -p 27101:27017 --name mongo-shard1-1 --network mongodb-network mongo:5 mongod --shardsvr --replSet mongo-shard1-rs --port 27017 --bind_ip localhost,mongo-shard1-1
docker run -d -p 27102:27017 --name mongo-shard1-2 --network mongodb-network mongo:5 mongod --shardsvr --replSet mongo-shard1-rs --port 27017 --bind_ip localhost,mongo-shard1-2
docker run -d -p 27103:27017 --name mongo-shard1-3 --network mongodb-network mongo:5 mongod --shardsvr --replSet mongo-shard1-rs --port 27017 --bind_ip localhost,mongo-shard1-3

Shard 2 (mongo-shard2)

docker run -d -p 27201:27017 --name mongo-shard2-1 --network mongodb-network mongo:5 mongod --shardsvr --replSet mongo-shard2-rs --port 27017 --bind_ip localhost,mongo-shard2-1
docker run -d -p 27202:27017 --name mongo-shard2-2 --network mongodb-network mongo:5 mongod --shardsvr --replSet mongo-shard2-rs --port 27017 --bind_ip localhost,mongo-shard2-2
docker run -d -p 27203:27017 --name mongo-shard2-3 --network mongodb-network mongo:5 mongod --shardsvr --replSet mongo-shard2-rs --port 27017 --bind_ip localhost,mongo-shard2-3

Check connectivity via:

docker exec -it mongo-shard1-1 mongosh --port 27017 --eval "db.runCommand({ ping: 1 })" | grep ok
docker exec -it mongo-shard1-2 mongosh --port 27017 --eval "db.runCommand({ ping: 1 })" | grep ok
docker exec -it mongo-shard1-3 mongosh --port 27017 --eval "db.runCommand({ ping: 1 })" | grep ok

docker exec -it mongo-shard2-1 mongosh --port 27017 --eval "db.runCommand({ ping: 1 })" | grep ok
docker exec -it mongo-shard2-2 mongosh --port 27017 --eval "db.runCommand({ ping: 1 })" | grep ok
docker exec -it mongo-shard2-3 mongosh --port 27017 --eval "db.runCommand({ ping: 1 })" | grep ok

You should see “ok: 1” in the output. Or you can even get the shell via:

mongosh mongodb://localhost:27101
mongosh mongodb://localhost:27102
mongosh mongodb://localhost:27103

mongosh mongodb://localhost:27201
mongosh mongodb://localhost:27202
mongosh mongodb://localhost:27203

Note: The mongo image we’re using automatically creates a docker volume for database persistence. You can get the volume via:

docker inspect mongo-shard1-1 | grep -A 20  "Mounts"

Step 3: Initialize the Replica Sets

Replica Set 1 (mongo-shard1-rs)

docker exec -it mongo-shard1-1 mongosh --eval "rs.initiate({
_id: \"mongo-shard1-rs\",
members: [
{_id: 0, host: \"mongo-shard1-1\"},
{_id: 1, host: \"mongo-shard1-2\"},
{_id: 2, host: \"mongo-shard1-3\"}
]
})"

Replica Set 2 (mongo-shard2-rs)


docker exec -it mongo-shard2-1 mongosh --eval "rs.initiate({
_id: \"mongo-shard2-rs\",
members: [
{_id: 0, host: \"mongo-shard2-1\"},
{_id: 1, host: \"mongo-shard2-2\"},
{_id: 2, host: \"mongo-shard2-3\"}
]
})"

You can check status of the replica sets via rs.status() command:

docker exec -it mongo-shard1-1 mongosh --eval "rs.status()"
docker exec -it mongo-shard2-1 mongosh --eval "rs.status()"

Step 4: Setup Config server Replica Set

Config Server (mongo-config-server)

docker run -dit --name mongo-config-server-1 --net mongodb-network -p 27001:27017 mongo:5 --configsvr --replSet mongo-config-server-rs --port 27017 --bind_ip localhost,mongo-config-server-1
docker run -dit --name mongo-config-server-2 --net mongodb-network -p 27002:27017 mongo:5 --configsvr --replSet mongo-config-server-rs --port 27017 --bind_ip localhost,mongo-config-server-2
docker run -dit --name mongo-config-server-3 --net mongodb-network -p 27003:27017 mongo:5 --configsvr --replSet mongo-config-server-rs --port 27017 --bind_ip localhost,mongo-config-server-3

Check connectivity via:

docker exec -it mongo-config-server-1 mongosh --port 27017 --eval "db.runCommand({ ping: 1 })" | grep ok
docker exec -it mongo-config-server-2 mongosh --port 27017 --eval "db.runCommand({ ping: 1 })" | grep ok
docker exec -it mongo-config-server-3 mongosh --port 27017 --eval "db.runCommand({ ping: 1 })" | grep ok

You should see “ok: 1” in the output. Or get the shell via:

mongosh mongodb://localhost:27001
mongosh mongodb://localhost:27002
mongosh mongodb://localhost:27003

Step 5: Initialize Config server Replica Set

Replica Set (mongo-config-server-rs)

docker exec -it mongo-config-server-1 mongosh --port 27017 --eval "rs.initiate({                                                                                                 
_id: \"mongo-config-server-rs\",
members: [
{_id: 0, host: \"mongo-config-server-1\"},
{_id: 1, host: \"mongo-config-server-2\"},
{_id: 2, host: \"mongo-config-server-3\"}
]
})"

Check status of the replica sets via rs.status() command:

docker exec -it mongo-config-server-1 mongosh --port 27017 --eval "rs.status()"

Step 6: Setup mongos

mongos-router-1

docker run -dit --name mongos-router-1 --net mongodb-network -p 27100:27017 mongo:5 mongos --configdb mongo-config-server-rs/mongo-config-server-1:27017,mongo-config-server-2:27017,mongo-config-server-3:27017 --port 27017 --bind_ip localhost,mongos-router-1

mongos-router-2

docker run -dit --name mongos-router-2 --net mongodb-network -p 27200:27017 mongo:5 mongos --configdb mongo-config-server-rs/mongo-config-server-1:27017,mongo-config-server-2:27017,mongo-config-server-3:27017 --port 27017 --bind_ip localhost,mongos-router-2

Check connectivity via:

docker exec -it mongos-router-1 mongosh --port 27017 --eval "db.runCommand({ ping: 1 })" | grep ok
docker exec -it mongos-router-2 mongosh --port 27017 --eval "db.runCommand({ ping: 1 })" | grep ok

You should see “ok: 1” in the output. Or get the shell via:

mongosh mongodb://localhost:27100
mongosh mongodb://localhost:27200

Step 7: Connect Shards with mongos

Connecting shards to mongos-router-1

docker exec -it mongos-router-1 mongosh --port 27017 --eval "sh.addShard(\"mongo-shard1-rs/mongo-shard1-1:27017,mongo-shard1-2:27017,mongo-shard1-3:27017\")"
docker exec -it mongos-router-1 mongosh --port 27017 --eval "sh.addShard(\"mongo-shard2-rs/mongo-shard2-1:27017,mongo-shard2-2:27017,mongo-shard2-3:27017\")"

Connecting shards to mongos-router-2

docker exec -it mongos-router-2 mongosh --port 27017 --eval "sh.addShard(\"mongo-shard1-rs/mongo-shard1-1:27017,mongo-shard1-2:27017,mongo-shard1-3:27017\")"
docker exec -it mongos-router-2 mongosh --port 27017 --eval "sh.addShard(\"mongo-shard2-rs/mongo-shard2-1:27017,mongo-shard2-2:27017,mongo-shard2-3:27017\")"

Connecting to your cluster

Connection String:

mongodb://localhost:27100,localhost:27200

You can connect via mongosh command:

mongosh mongodb://localhost:27100,localhost:27200

Since we have 2 mongos i.e. mongos-router-1 at localhost:27100 and mongos-router-2 at localhost:27200, so after connecting to the mongos shell even if one of them fails you’ll seamlessly be connected to the other mongos without any downtime.

To create or use an existing database:

use <database>

Note: Since we’re using MongoDB 5.0 we also need to run:

sh.enableSharding("<database-name>")

and to shard collection:

sh.shardCollection("<database-name>.<collection-name>", { <shard-key>: "hashed", ...})

And there you have it — a MongoDB Sharded Cluster running on your local machine!

Cleanup

For cleanup use:

Warning: Using -v will also remove volumes associated with the containers!

docker rm -vf mongos-router-1 mongos-router-2 mongo-config-server-1 mongo-config-server-2 mongo-config-server-3 mongo-shard1-1 mongo-shard1-2 mongo-shard1-3 mongo-shard2-1 mongo-shard2-2 mongo-shard2-3
docker network rm mongodb-network

There are many more configurable parameters in MongoDB, as detailed in the official documentation. And there are a ton of other things you can do in docker like:

  • Mount a config file via docker volumes instead of commands to configure the components.
  • Adjust logging and even configure dedicated volumes for logs.
  • etcetera.

I hope this guide was helpful. If so, please give it a like and consider sharing it with your fellow tech enthusiasts.

Thank you!
Until next time!

--

--

Ankit Kumar
Ankit Kumar

Responses (1)