This is a guide on how to setup MongoDb replica set that can be access from your host machine or within your network with some configuration.
First create a new network:
$ docker network create my-mongo-cluster
You can verify it by :
$ docker network lsNETWORK ID NAME DRIVER SCOPE
33ad63f81109 my-mongo-cluster bridge local
Next, create 3 different MongoDb container, and we are using MongoDb 4.0.20 in this example.
$ docker run -d --net my-mongo-cluster -p 20001:20001 --name mongodb1 mongo:4.0.20 mongod --replSet my-replica --port 20001$ docker run -d --net my-mongo-cluster -p 20002:20002 --name mongodb2 mongo:4.0.20 mongod --replSet my-replica --port 20002$ docker run -d --net my-mongo-cluster -p 20003:20003 --name mongodb3 mongo:4.0.20 mongod --replSet my-replica --port 20003
Note that we are using different port compared to default port of 27017. This is intentional because when we are connecting it from outside network, MongoDb will return the host address based on your replica configuration (which will be covered below) and we need the port to be the same as the port number that was exposed by Docker.
Once they are up and running, we need to connect to one of them and initiate the replica set. We can either execute the commands within the container, or if you have mongo shell installed on your host machine, you can run following commands from your host:
$ mongo "mongodb://localhost:20001"> config={"_id":"my-replica","members":[{"_id":0,"host":"mongodb1:20001"},{"_id":1,"host":"mongodb2:20002"},{"_id":2,"host":"mongodb3:20003"}]}> rs.initiate(config)
It is important to configure the replica with above configuration, by using <hostname>:<port>. They will need that to communicate with each other for synching purpose.
Give it some time to elect PRIMARY node, and we can execute following command to verify.
my-replica:PRIMARY> rs.status(){
"set" : "rs0",
...
"members" : [{...}]
}
Congratulation, we now have a working MongoDb replica set. Now try to connect it via replica set:
mongo "mongodb://localhost:20001/?replicaSet=my-replica"
We will most likely greeted by this:
I NETWORK [thread1] Starting new replica set monitor for my-replica/localhost:20001
I NETWORK [thread1] Successfully connected to localhost:20001 (1 connections now open to localhost:20001 with a 5 second timeout)
I NETWORK [thread1] changing hosts to my-replica/mongodb1:20001
from my-replica/localhost:20001...W NETWORK [thread1] Unable to reach primary for set my-replica
I NETWORK [thread1] Cannot reach any nodes for set my-replica. Please check network connectivity and the status of the set. This has happened for 1 checks in a row.
This is because of the way replica set is configured. To overcome this, we need to configure our host file with this:
$ sudo vi /etc/hosts127.0.0.1 mongodb1 mongodb2 mongodb3
What is happening here is we are mapping mongodb1 to 127.0.0.1 which in this case it should resolve the hostname of mongodb1.
You might ask “What if I changed my replica set configuration to localhost:20001?”. That will work if you are running single instance replica setup. But if you are running multiple MongoDb, your container will resolve localhost to 127.0.0.1 and the database will not be able to communicate with each other.
You may now try to connect again:
mongo "mongodb://localhost:20001/?replicaSet=my-replica"my-replica:PRIMARY>
Bonus
If you wanted to access it outside of your host machine and within the same network, the simplest way is to map mongodb1 in your host file to host machine’s ip.