How to set up MongoDB with replica set via Docker Compose?

byGinkMon, 29 Jan 2024

1. Standalone instance.

Commonly, we can set up MongoDB with a simple docker-compose.yml like following:

version: '3.8'

services:
  mongo:
    image: mongo:7.0
    container_name: mongodb-standalone
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: root
    ports:
      - 27017:27017
    volumes:
      - data:/data/db
volumes:
  data: {}

Quite easy, right?

Unfortunately, this one give us a standalone instance. So it's not possible to work with transaction. Some libraries like Prisma just keep complaining about this issue if we want to create any data on it.

2. With Replica set enable.

To be able setting up authentication with replica set, let's take a look from this official document first.

So we need to generate a keyfile at the first step. And then specify that keyfile when starting mongod server.

It's possible to create the keyfile outside then mount it into the container. But due to some weird issues on file permission. I decided to modify the docker image a bit to generate the keyfile right there.

  • Let's create a folder with this structure:
mongodb7.0
  |-- Dockerfile
  |-- docker-compose.yml
  • Generate a keyfile in the image by Dockerfile:
FROM mongo:7.0
RUN openssl rand -base64 756 > /etc/mongo-keyfile 
RUN chmod 400 /etc/mongo-keyfile 
RUN chown mongodb:mongodb /etc/mongo-keyfile 
  • Update docker-compose.yml to use custom image:
version: '3.8'

services:
  mongo:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: mongodb-replicaset
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: root
    ports:
      - 27017:27017
    command: --replSet rs0 --keyFile /etc/mongo-keyfile --bind_ip_all --port 27017
    healthcheck:
      test: echo "try { rs.status() } catch (err) { rs.initiate({_id:'rs0',members:[{_id:0,host:'127.0.0.1:27017'}]}) }" | mongosh --port 27017 -u root -p root --authenticationDatabase admin
      interval: 5s
      timeout: 15s
      start_period: 15s
      retries: 10
    volumes:
      - data:/data/db

volumes:
  data: {}

Let's explain a little bit.

  • At first, we replace image mongo:7.0 by the custom image built by our Dockerfile.
  • Then we start the container with the command that specifying replica set, keyfile as well as bind IP and port.
  • After the container is up, using a heathcheck script to keep trying login and initiate the replica set. I think 10 times is more than enough. You can increase the number to retry if it's not sufficient in some cases.
  • In this example I used the default port 27017. If you already have the port occupied, then just replace all 27017 in the compose file to a different port.

Now running up this compose and wait a bit. We'll have a MongoDB with replica set enable on local machine.

docker compose up -d

Then connect to this server by:

mongosh --port 27017 --username root --password root --authenticationDatabase admin
# Or via URL string:
mongosh "mongodb://root:root@localhost:27017/?authSource=admin"


© 2016-2024  GinkCode.com