Docker-compose for a local MongoDB cluster
November 13, 2021-3 min read
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.keysudo 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:5hostname: mongodb_1command: --replSet rs1 --keyFile /etc/mongo-replication.keyenvironment:MONGO_INITDB_ROOT_USERNAME: adminMONGO_INITDB_ROOT_PASSWORD: adminports:- 127.0.10.1:27017:27017volumes:- mongodb_data_1:/data/db- ./mongo-replication.key:/etc/mongo-replication.keymongodb_2:image: mongo:5hostname: mongodb_2command: --replSet rs1 --keyFile /etc/mongo-replication.keyenvironment:MONGO_INITDB_ROOT_USERNAME: adminMONGO_INITDB_ROOT_PASSWORD: adminports:- 127.0.10.2:27017:27017volumes:- mongodb_data_2:/data/db- ./mongo-replication.key:/etc/mongo-replication.keydepends_on:- mongodb_1mongodb_3:image: mongo:5hostname: mongodb_3command: --replSet rs1 --keyFile /etc/mongo-replication.keyenvironment:MONGO_INITDB_ROOT_USERNAME: adminMONGO_INITDB_ROOT_PASSWORD: adminports:- 127.0.10.3:27017:27017volumes:- mongodb_data_3:/data/db- ./mongo-replication.key:/etc/mongo-replication.keydepends_on:- mongodb_1volumes: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 NAMESce555abc94b9 mongo:5 "docker-entrypoint.s…" 21 seconds ago Up 19 seconds 127.0.10.2:27017->27017/tcp mongodb-mongodb_2-1ad847f72fce4 mongo:5 "docker-entrypoint.s…" 21 seconds ago Up 19 seconds 127.0.10.3:27017->27017/tcp mongodb-mongodb_3-1fbd824608451 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_1127.0.10.2 mongodb_2127.0.10.3 mongodb_3
Taking it all down
Take down containers and delete their corresponding volumes:
docker-compose down -v