DOC_TYPE: RESEARCH_LOG

MongoDB Docker Standalone → Replica Set Migration Guide

#MongoDB#Replica Set#Docker#Database#Runbook

MongoDB Docker Standalone → Replica Set Migration Guide

This document explains how to migrate a standalone MongoDB instance running on Docker to a controlled and reliable 3-node Replica Set architecture named rs0.

The goal is not just to make MongoDB run, but to build a correct and maintainable cluster.


What Is a Replica Set?

A MongoDB Replica Set is a high availability architecture made of one Primary and one or more Secondary nodes. The Primary accepts writes. Secondary nodes replicate data from the Primary through the oplog. If the Primary fails, one Secondary can be elected as the new Primary automatically.


Why Standalone Is Not Enough

  • Single point of failure
  • Full outage if disk, OS, host, or container fails
  • Downtime is usually required during maintenance
  • No read scaling or automatic failover

Benefits

  • High availability
  • Data safety through multiple nodes
  • Easier maintenance and controlled upgrades
  • Optional read distribution with readPreference
  • Production-oriented MongoDB architecture

Architecture Overview

        ┌───────────┐
        │  mongo1   │
        │  PRIMARY  │
        └─────┬─────┘
              │ oplog
   ┌──────────┴──────────┐
┌──▼──────┐        ┌─────▼─────┐
│ mongo2  │        │  mongo3   │
│SECONDARY│        │ SECONDARY │
└─────────┘        └───────────┘

Replica Set name: rs0


Prerequisites

  • Docker and Docker Compose
  • MongoDB 6.x
  • TCP/27017 access between nodes
  • Time synchronization, preferably NTP
  • Persistent disk volumes

Step 1 - Hostname Resolution

Replica Set members should see each other by hostname.

sudo bash -lc 'cat >> /etc/hosts <<EOF
10.10.10.11 mongo1
10.10.10.12 mongo2
10.10.10.13 mongo3
EOF'

Test:

ping -c 1 mongo1
ping -c 1 mongo2
ping -c 1 mongo3

Step 2 - Keyfile for Internal Auth

The keyfile must be identical on all nodes, readable only by MongoDB, and owned by the MongoDB user.

sudo mkdir -p /opt/acme/mongodb/security
sudo openssl rand -base64 756 | sudo tee /opt/acme/mongodb/security/keyfile >/dev/null
sudo chmod 400 /opt/acme/mongodb/security/keyfile
sudo chown 999:999 /opt/acme/mongodb/security/keyfile

Copy it to secondary nodes with the same permission and ownership.


Step 3 - Convert Primary to Replica Set Mode

Required flags:

  • --replSet rs0
  • --keyFile /data/keyfile
  • --bind_ip_all
  • --auth
version: '3.4'
services:
  mongodb:
    image: mongo:6.0.27
    restart: always
    container_name: mongo-rs-mongo1
    hostname: mongo1
    volumes:
      - /opt/acme/mongodb/db/:/data/db
      - /opt/acme/mongodb/security/keyfile:/data/keyfile:ro
    ports:
      - "27017:27017"
    command: ["mongod","--replSet","rs0","--keyFile","/data/keyfile","--bind_ip_all","--auth"]

Restart:

docker compose down
docker compose up -d

Step 4 - Initialize Replica Set

docker exec -it mongo-rs-mongo1 mongosh -u mongoadmin -p mongopassword --authenticationDatabase admin
rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "mongo1:27017" }
  ]
})

Check:

rs.status()

Step 5 - Start Secondary Nodes

Secondary nodes start with empty data directories and perform initial sync.

version: '3.4'
services:
  mongodb:
    image: mongo:6.0.27
    restart: always
    container_name: mongo-rs-mongo2
    hostname: mongo2
    volumes:
      - /opt/acme/mongodb/db/:/data/db
      - /opt/acme/mongodb/security/keyfile:/data/keyfile:ro
    ports:
      - "27017:27017"
    command: ["mongod","--replSet","rs0","--keyFile","/data/keyfile","--bind_ip_all","--auth"]

Step 6 - Add Secondaries

rs.add("mongo2:27017")
rs.add("mongo3:27017")
rs.status()

Expected: one PRIMARY and two SECONDARY nodes.


Connection String

mongodb://mongoadmin:mongoadmin@mongo1:27017,mongo2:27017,mongo3:27017/admin?replicaSet=rs0&authSource=admin

Optional:

&readPreference=secondaryPreferred

Health Checks

docker exec -it mongo-rs-mongo1 mongosh -u mongoadmin -p mongopassword --authenticationDatabase admin --eval 'rs.status()'
docker exec -it mongo-rs-mongo1 mongosh -u mongoadmin -p mongopassword --authenticationDatabase admin --eval 'rs.printSecondaryReplicationInfo()'

Troubleshooting

Check hostname resolution, firewall access, same Replica Set name, identical keyfile, correct file permissions, and container-level DNS resolution.

docker exec -it mongo-rs-mongo1 bash -lc 'getent hosts mongo2 && getent hosts mongo3'

Production Checklist

  • Hostname resolution is clear
  • TCP/27017 is open between nodes
  • Disk IOPS are sufficient
  • NTP is enabled
  • Keyfile path and permissions are correct
  • Authentication and strong passwords are enabled
  • Backup strategy exists
  • Monitoring and alerting are configured
  • Application connection string contains replicaSet=rs0
  • Failover has been tested