- Published on
Docker-compose for a local MongoDB cluster
- Authors

- Name
- Giorgos Dimtsas
- @gedim21
In this post we'll explore how to set up MongoDB replica set using Docker and Docker Compose.
Generate the keyfile
First, we'll need a key that the replica set nodes will use to communicate with each other securly.
The key's length must be between 6 and 1024 characters and may only contain characters in the base64 set. We can generate such a key using openssl:
openssl rand -base64 768 > mongo-replication.key
Then we'll reduce the permissions on the key, else MongoDB will complain that the permissions of the key are too open.
chmod 400 mongo-replication.key
sudo chown 999:999 mongo-replication.key
Keyfiles are only suitable for development purposes. For productions environments you should use x.509 certificates.
Starting the containers
We'll start three MongoDB containers, that will compose a replica set called rs1. We'll also pass the key that we created earlier to each instance. This is the content of the docker-compose.yml file:
version: '3.7'
services:
mongodb_1:
image: mongo:5
hostname: mongodb_1
command: --replSet rs1 --keyFile /etc/mongo-replication.key
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: admin
ports:
- 127.0.10.1:27017:27017
volumes:
- mongodb_data_1:/data/db
- ./mongo-replication.key:/etc/mongo-replication.key
mongodb_2:
image: mongo:5
hostname: mongodb_2
command: --replSet rs1 --keyFile /etc/mongo-replication.key
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: admin
ports:
- 127.0.10.2:27017:27017
volumes:
- mongodb_data_2:/data/db
- ./mongo-replication.key:/etc/mongo-replication.key
depends_on:
- mongodb_1
mongodb_3:
image: mongo:5
hostname: mongodb_3
command: --replSet rs1 --keyFile /etc/mongo-replication.key
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: admin
ports:
- 127.0.10.3:27017:27017
volumes:
- mongodb_data_3:/data/db
- ./mongo-replication.key:/etc/mongo-replication.key
depends_on:
- mongodb_1
volumes:
mongodb_data_1:
mongodb_data_2:
mongodb_data_3:
Start the services using:
docker-compose up -d
The containers should be up within a few seconds:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce555abc94b9 mongo:5 "docker-entrypoint.s…" 21 seconds ago Up 19 seconds 127.0.10.2:27017->27017/tcp mongodb-mongodb_2-1
ad847f72fce4 mongo:5 "docker-entrypoint.s…" 21 seconds ago Up 19 seconds 127.0.10.3:27017->27017/tcp mongodb-mongodb_3-1
fbd824608451 mongo:5 "docker-entrypoint.s…" 21 seconds ago Up 20 seconds 127.0.10.1:27017->27017/tcp mongodb-mongodb_1-1
Initialize the replica set
With all the instances up and running, we have to initialize the replica set next.
Add the content below to a file called init-replica-set.js:
db.auth('admin', 'admin')
rs.initiate({
_id: 'rs1',
version: 1,
members: [
{ _id: 0, host: 'mongodb_1:27017', priority: 1 },
{ _id: 1, host: 'mongodb_2:27017', priority: 0 },
{ _id: 2, host: 'mongodb_3:27017', priority: 0 },
],
})
and execute it against the MongoDB cluster using:
docker run --rm --network mongodb_default mongo:5 mongosh \
--host mongodb_1:27017 --username admin --password admin \
--authenticationDatabase admin admin \
--eval "$(< init-replica-set.js)"
The response from MongoDB will be a simple { "ok" : 1 }
Use the following command to inspect the replica set status:
docker run --rm --network mongodb_default mongo:5 mongosh \
--host mongodb_1:27017 --username admin --password admin \
--authenticationDatabase admin admin \
--eval "rs.status()"
The response should be something like this:
{
"set" : "rs1",
...
"members" : [
{
"_id" : 0,
"name" : "mongodb_1:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
...
},
{
"_id" : 1,
"name" : "mongodb_2:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
...
},
{
"_id" : 2,
"name" : "mongodb_3:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
...
}
]
...
}
Create a user
The replica set is up and running; next step, create a user with the dbOwner role. This role combines the readWrite, dbAdmin and userAdmin roles, allowing the user to do pretty much anything to the database.
db.auth('admin', 'admin')
db = db.getSiblingDB('my_database')
db.createUser({
user: 'my_user',
pwd: 'my_pass',
roles: [
{
role: 'dbOwner',
db: 'my_database',
},
],
})
Add the above to a file called init-user.js and execute it against the MongoDB cluster using:
docker run --rm --network mongodb_default mongo:5 mongosh \
--host mongodb_1:27017 --username admin --password admin \
--authenticationDatabase admin admin \
--eval "$(< init-user.js)"
Connecting to the replica set
Using REPL
docker run --rm -i -t --network mongodb_default mongo:5 mongosh \
--host mongodb_1,mongodb_2,mongodb_3 --username admin --password admin \
--authenticationDatabase admin admin
Connection string
mongodb://my_user:my_pass@mongodb_1:27017,mongodb_2:27017,mongodb_3:27017/my_database?replicaSet=rs1
add the following hosts to your hosts file
127.0.10.1 mongodb_1
127.0.10.2 mongodb_2
127.0.10.3 mongodb_3
Taking it all down
Take down containers and delete their corresponding volumes:
docker-compose down -v