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