Setting Up a MongoDB Replica Set with Docker Compose

A Step-by-Step Guide

Introduction

A MongoDB replica set is a powerful feature that enhances data availability and provides automatic failover in case of node failures. Docker Compose, on the other hand, simplifies the process of defining and managing multi-container Docker applications. By combining the two, we can set up a MongoDB replica set effortlessly. In this article, we will guide you through the process of creating a MongoDB replica set using Docker Compose.

Table of Contents

  1. Prerequisites
  2. Installing Docker and Docker Compose
  3. Creating the Docker Compose File
  4. Configuring the MongoDB Replica Set
  5. Running the MongoDB Replica Set
  6. Verifying the MongoDB Replica Set
  7. Conclusion

1. Prerequisites

Before proceeding, ensure that you have the following prerequisites:

  • Basic knowledge of MongoDB and Docker
  • Docker Engine installed on your machine
  • Docker Compose installed on your machine
  • A text editor for creating the Docker Compose file

2. Installing Docker and Docker Compose

If you haven't installed Docker and Docker Compose, follow the steps below:

  • Docker Installation: Visit the official Docker website (docker.com/get-started) and download the appropriate version of Docker for your operating system. Install it following the installation wizard's instructions.

  • Docker Compose Installation: Docker Compose is included in the Docker Desktop installation on Windows and macOS. For Linux users, follow the instructions provided on the official Docker Compose website (docs.docker.com/compose/install) to install it.

3. Creating the Docker Compose File

Now, let's create the Docker Compose file to define our MongoDB replica set configuration. Open your favorite text editor and create a file named "docker-compose.yml."

version: '3.8'

networks:
  app-network:
    driver: bridge

services:
  mongodb1:
    image: mongo:latest
    container_name: mongodb1
    restart: always
    ports:
      - "27017:27017"
    networks:
      - app-network
    volumes:
      - mongodb1-data:/data/db
    command: ["--replSet", "rs0", "--bind_ip_all", "--port", "27017"]
    healthcheck:
      test: ["CMD", "mongo", "--eval", "db.adminCommand('ping')"]
      interval: 5s
      start_period: 10s

  mongodb2:
    image: mongo:latest
    container_name: mongodb2
    restart: always
    ports:
      - "27018:27018"
    networks:
      - app-network
    volumes:
      - mongodb2-data:/data/db
    command: ["--replSet", "rs0", "--bind_ip_all", "--port", "27018"]
    healthcheck:
      test: ["CMD", "mongo", "--eval", "db.adminCommand('ping')"]
      interval: 5s
      start_period: 10s

  mongodb3:
    image: mongo:latest
    container_name: mongodb3
    restart: always
    ports:
      - "27019:27019"
    networks:
      - app-network
    volumes:
      - mongodb3-data:/data/db
    command: ["--replSet", "rs0", "--bind_ip_all", "--port", "27019"]
    healthcheck:
      test: ["CMD", "mongo", "--eval", "db.adminCommand('ping')"]
      interval: 5s
      start_period: 10s

volumes:
  mongodb1-data:
  mongodb2-data:
  mongodb3-data:

4. Configuring the MongoDB Replica Set

In our Docker Compose file, we have defined three MongoDB containers, each representing a node in the replica set. The --replSet flag sets the replica set name to "rs0," and the --bind_ip_all flag allows connections from all network interfaces.

5. Running the MongoDB Replica Set

To start the MongoDB replica set, open your terminal or command prompt, navigate to the directory containing the docker-compose.yml file, and run the following command:

docker-compose up -d

Docker Compose will download the MongoDB images and create the containers according to the configuration specified in the docker-compose.yml file. The -d flag runs the containers in detached mode, allowing you to continue using the terminal.

6. Verifying the MongoDB Replica Set

Once the containers are up and running, we can connect to the MongoDB shell using Docker's exec command. Open a new terminal or command prompt and run the following command to connect to the primary node:

docker exec -it mongodb1 mongosh

Now, inside the MongoDB shell, initiate the replica set:

rs.initiate({_id: "rs0", members: [
  {_id: 0, host: "mongodb1:27017"},
  {_id: 1, host: "mongodb2:27018"},
  {_id: 2, host: "mongodb3:27019"}
]})

After running the rs.initiate() command, you should see the replica set configuration details.

7. Testing

Create a javascript file index.js to test the connection to the replica-set

const mongoose = require('mongoose');

const dbURI = 'mongodb://mongodb1:27017,mongodb2:27018,mongodb3:27019/mydatabase?replicaSet=rs0&authSource=admin';

mongoose.connect(dbURI);

const db = mongoose.connection;

db.on('error', (error) => {
  console.error('MongoDB connection error:', error.message);
});

db.once('open', () => {
  console.log('Connected to MongoDB replica set!');
});

Execute it with

node index.js

You should see: 'Connected to MongoDB replica set!'

8. Conclusion

Congratulations! You have successfully set up a MongoDB replica set using Docker Compose. This replica set provides data redundancy and high availability, ensuring that your MongoDB deployment is fault-tolerant.

In this article, we covered the prerequisites, installed Docker and Docker Compose, created a Docker Compose file to define the MongoDB replica set configuration, and verified its setup. Now you can take advantage of the benefits of a MongoDB replica set in your applications with ease.

Remember to stop the MongoDB replica set containers using docker-compose down when you no longer need them.

Happy coding with your MongoDB replica set in Docker Compose!


Common Errors

OCI runtime exec failed: exec failed: unable to start container process: exec: "mongo": executable file not found in $PATH: unknown
OCI runtime exec failed: exec failed: unable to start container process: exec: "/scripts/rs-init.sh": permission denied: unknown
Error message

  reason: TopologyDescription {
    type: 'ReplicaSetNoPrimary',
    servers: Map(3) {
      'mongodb1:27017' => ServerDescription {
        address: 'mongodb1:27017',
        type: 'Unknown',
        hosts: [],
        passives: [],
        arbiters: [],
        tags: {},
        minWireVersion: 0,
        maxWireVersion: 0,
        roundTripTime: -1,
        lastUpdateTime: 1048570472,
        lastWriteDate: 0,
        error: MongoNetworkError: getaddrinfo ENOTFOUND mongodb1

Solution

MongoDB has introduced "mongosh" as a new interactive MongoDB shell, and it is recommended to use it instead of the deprecated "mongo" shell.

So, to connect to the MongoDB container mongodb1 using the "mongosh" shell, you should use the following command:

docker exec -it mongodb1 mongosh

Sure, there are two ways to remove unused networks in Docker:

  1. Remove one or more networks using the docker network ls command.

    This command will list all of the networks that are currently created. You can then use the ID of the network to remove it using the docker network rm command. For example, to remove the network with the ID my-network, you would run the following command:

    docker network rm my-network
    
  2. Remove all unused networks using the docker network prune command.

    This command will remove all of the networks that are not currently being used by any containers. To run this command, you do not need to know the ID of the networks. For example, to remove all unused networks, you would run the following command:

    docker network prune
    

    If you want to remove all unused networks, but you want to be prompted before the command is executed, you can use the -f or --force flag. For example, to remove all unused networks and be prompted before the command is executed, you would run the following command:

    docker network prune -f
    

Here are some examples of how to use these commands:

# List all of the networks
docker network ls

# Remove the network with the ID my-network
docker network rm my-network

# Remove all unused networks
docker network prune

# Remove all unused networks and be prompted before the command is executed
docker network prune -f

I hope this helps! Let me know if you have any other questions.