Pablo Rivera Conde

Running MongoDB with Replica Sets in Docker Compose

Lately, I’ve been involved in a project that uses MongoDB. I haven’t worked much with NoSQL databases, so it’s great to give it a shot. I’m used to working with dockerized applications, but this specific project doesn’t have this setup, instead using a locally running MongoDB on the host. It’s okay, but I’m so accustomed to Docker that I can’t help but feel uncomfortable nowadays having a database running directly on my local machine.

So, I decided to dockerize the database myself. I tried several setups online, but none of them worked out of the box. I finally got it working and now have a functional compose.yml. The special detail of this setup is that I needed to have several containers running, configured as Replica Sets.

What is a MongoDB Replica Set?

In order to improve database availability, MongoDB implements the Replica Set concept. This basically allows multiple instances of the database to run with the same data. They operate in a Leader-Follower architecture, where the Leader manages communication outside the cluster and sends information to its followers to keep their data updated.

All instances report their status via heartbeats. If the leader crashes, the remaining followers decide which one will become the new leader, and the database continues working without exposing any issues to clients.

The Code

The compose.yml file is fairly simple. It sets up three different MongoDB instances, exposing their ports, and a fourth instance that only connects to these instances to configure them as part of a Replica Set.

 1services:
 2  mongo1:
 3    container_name: mongo1
 4    image: mongo:latest
 5    command: ["--replSet", "rs0", "--bind_ip_all", "--port", "27017"]
 6    ports:
 7      - 27017:27017
 8    volumes:
 9      - mongo1_data:/data/db
10    networks:
11      - mongo_network
12    healthcheck:
13      test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet
14      interval: 10s
15      timeout: 10s
16      retries: 5
17      start_period: 40s
18
19  mongo2:
20    container_name: mongo2
21    image: mongo:latest
22    command: ["--replSet", "rs0", "--bind_ip_all", "--port", "27017"]
23    ports:
24      - 27018:27017
25    volumes:
26      - mongo2_data:/data/db
27    networks:
28      - mongo_network
29    healthcheck:
30      test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet
31      interval: 10s
32      timeout: 10s
33      retries: 5
34
35  mongo3:
36    container_name: mongo3
37    image: mongo:latest
38    command: ["--replSet", "rs0", "--bind_ip_all", "--port", "27017"]
39    ports:
40      - 27019:27017
41    volumes:
42      - mongo3_data:/data/db
43    networks:
44      - mongo_network
45    healthcheck:
46      test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet
47      interval: 10s
48      timeout: 10s
49      retries: 5
50      start_period: 40s
51
52  # This service initializes the replica set
53  mongo-init:
54    image: mongo:latest
55    restart: "no"
56    depends_on:
57      mongo1:
58        condition: service_healthy
59      mongo2:
60        condition: service_healthy
61      mongo3:
62        condition: service_healthy
63    networks:
64      - mongo_network
65    volumes:
66      - ./init-replica.sh:/init-replica.sh
67    entrypoint: ["bash", "/init-replica.sh"]
68
69networks:
70  mongo_network:
71    driver: bridge
72volumes:
73  mongo1_data:
74  mongo2_data:
75  mongo3_data:

mongo1, mongo2, and mongo3 simply start instances of MongoDB with a named volume mount for each one and expose their 27017 port (MongoDB’s default port). The mongo-init service waits for these instances to be running and then executes the following script, init-replica.sh:

 1#!/bin/bash
 2
 3echo "Waiting for MongoDB instances to start..."
 4sleep 10
 5
 6echo "Initializing replica set..."
 7mongosh --host mongo1:27017 <<EOF
 8rs.initiate(
 9  {
10    _id : 'rs0',
11    members: [
12      { _id : 0, host : "mongo1:27017", priority: 1 },
13      { _id : 1, host : "mongo2:27017", priority: 0.5 },
14      { _id : 2, host : "mongo3:27017", priority: 0.5 }
15    ]
16  }
17)
18EOF
19
20mongosh --host mongo1:27017 --eval "rs.status()"

Remember to run chmod +x init-replica.sh to give the script the necessary execution permissions.

With these two files in place, just run docker compose up -d and your MongoDB replica set is ready to use!

#mongodb #docker #setup

Reply to this post by email ↪