Improving the local development setup for running MongoDB Replica Set with Docker
Tags: docker, mongodb, tutorial
Published: 2021-03-19 19:36:21

All associated source code used in this blog can be found at the following Github repository:  

{% github sntnupl/devcontainers-mongodb-replica-set-with-docker no-readme %}


In my [previous post](https://dev.to/sntnupl/how-to-setup-a-mongodb-replica-set-for-development-using-docker-1de), we created a docker based development setup for running MongoDB Replica Set.  

A flaw in that setup, was that although clients could connect to stand-alone nodes of the replica set, they could not connect to the replica set as a whole, as reported by [this issue](https://github.com/sntnupl/devcontainers-mongodb-replica-set-with-docker/issues/1) on the [github repository](https://github.com/sntnupl/devcontainers-mongodb-replica-set-with-docker).

In this blog post, we will see what can be done, to overcome this problem.  

___

## Root Cause  

As per the [MongoDB specifications](https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#clients-use-the-hostnames-listed-in-the-replica-set-config-not-the-seed-list):  
> the hostnames used in a replica set config are reachable from the client

In our previous blog, we initialized the following replica set configuration:  

```bash
MONGODB1=mongo1
MONGODB2=mongo2
MONGODB3=mongo3
:
var cfg = {
    "_id": "rs0",
    ...
    "members": [
        {
            ...
            "host": "${MONGODB1}:27017",
            ...
        },
        {
            ...
            "host": "${MONGODB2}:27017",
            ...
        },
        {
            ...
            "host": "${MONGODB3}:27017",
            ...
        }
    ]
};
```

In essence, this would require the clients to able to reach the following hosts: `mongo1:27017, mongo2:27017, mongo3:27017`.  

We can update `/etc/hosts` file to point `127.0.0.1` to `mongo1, mongo2, mongo3` hostnames. But the portnumber `27017` would still cause the problem - we can't have 3 nodes (services) running on the same port. 

Therefore, solution to the problem would be the following:
1. Update `hosts` file in client machines, to map hostnames `mongo1, mongo2, mongo3` to `127.0.0.1`  
1. Run `mongod` service on the 3 nodes of the replica set. in different port numbers

___

## Solution

Implementing the 1st step is trivial. One would need to update `/etc/hosts` file in Linux, or `C:\Windows\System32\drivers\etc\hosts` in Windows:  
```bash
127.0.0.1 localhost mongo1 mongo2 mongo3
```

Let's go through the steps to implement the second step.

**Changes to the docker compose file**  

```yml
...
mongo1:
  hostname: 'mongo1'
  container_name: 'mongo1'
  ...
  command: ["-f", "/etc/mongod.conf", "--port", "30001", "--keyFile", "/auth/file.key", "--replSet", "${MONGO_REPLICA_SET_NAME}", "--bind_ip_all"]
  expose: 
    - 30001
  ports: 
    - 30001:30001 
  ...

mongo2:
  hostname: 'mongo2'
  container_name: 'mongo2'
  ...
  command: ["-f", "/etc/mongod.conf", "--port", "30002", "--keyFile", "/auth/file.key", "--replSet", "${MONGO_REPLICA_SET_NAME}", "--bind_ip_all"]
  expose: 
    - 30002
  ports: 
    - 30002:30002 
  ...

mongo3:
  hostname: 'mongo3'
  container_name: 'mongo3'
  ...
  command: ["-f", "/etc/mongod.conf", "--port", "30003", "--keyFile", "/auth/file.key", "--replSet", "${MONGO_REPLICA_SET_NAME}", "--bind_ip_all"]
  expose: 
    - 30003
  ports: 
    - 30003:30003 
  ...

```

This will bring up `mongod` services in the 3 nodes in 3 different ports.  

Next, we modify the replica set configuration, by changing `mongosetup.sh` file:  

```bash
mongo --host ${MONGODB1}:30001 -u ${MONGO_INITDB_ROOT_USERNAME} -p ${MONGO_INITDB_ROOT_PASSWORD} <<EOF
var cfg = {
    "_id": "rs0",
    ...
    "members": [
        {
            ...
            "host": "${MONGODB1}:30001",
            ...
        },
        {
            ...
            "host": "${MONGODB2}:30002",
            ...
        },
        {
            ...
            "host": "${MONGODB3}:30003",
            ...
        }
    ]
};
```

These are essentially all the necessary changes needed to be done, to solve the problem.  

___

## Final Result  

Once we make these changes, we could connect to the replica set using `mongo` client:  
```bash
$ mongo "mongodb://localhost:30001,localhost:30002,localhost:30003/<MONGO_INITDB_DATABASE>?replicaSet=rs0" -u <MONGO_INITDB_USERNAME> --authenticationDatabase admin
```

OR

```bash
$ mongo "mongodb://mongo1:30001,mongo2:30002,mongo3:30003/<MONGO_INITDB_DATABASE>?replicaSet=rs0" -u <MONGO_INITDB_USERNAME> --authenticationDatabase admin
```

![Connect to Replica set](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ac7p7xzfmnf8phtdpzwi.jpg)

We can also view result of `db.isMaster()` command to debug details like hosts of the replicaset a client must connect to, if the node is primary, etc.  

![isMaster() output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qr02ieg661iyuxm2rfc0.jpg)