mongodb replica set using docker compose – part ii

In my previous post here I showed how to setup a mongodb replica set using docker-compose. While this worked fine for testing the database and doing some small tests. However, for this replica set to be used by applications there is an issue. The mongodb client drivers may not be able to resolve the secondary names like mongo2 or mongo3 and that makes testing read preferences difficult.

In this post, I am going to enhance the configuration of previous replica set docker compose configuration, use local DNS and setup a fully functioning replica set that can be used from any client or application and allow you to use read preference like secondary preferred.

Procedure

I am not going to cover docker installation here. You can refer to my previous post to see links for installation information.

For this setup I made a few changes. I created my docker-compose.yml in /home/ubuntu itself so as not to overwrite the file from my earlier test.

I did my tests on an EC2 server in the default VPC and I setup a private hosted zone called pvt.skbali.com so that I could setup a DNS entry for my mongodb server.


root@ip-172-30-0-44:~# host mongodb.pvt.skbali.com
mongodb.pvt.skbali.com has address 172.30.0.44

I created an A record for my host with the name mongodb.pvt.skbali.com. The above shows the lookup for it.

Next I edited and saved /home/ubuntu/docker-compose.yml as shown below


version: "3"
services:
  mongo1:
    hostname: mongo1
    container_name: mongo1
    image: mongo:4.0.10
    volumes:
      - /mongodb/data1/db:/data/db
      - /mongodb/data1/configdb:/data/configdb
    networks:
      - mongo-dev-net
    expose:
      - 30001
    ports:
      - 30001:30001
    restart: always
    entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--port", "30001", "--replSet", "devrs" ]
  mongo2:
    hostname: mongo2
    container_name: mongo2
    image: mongo:4.0.10
    volumes:
      - /mongodb/data2/db:/data/db
      - /mongodb/data2/configdb:/data/configdb
    networks:
      - mongo-dev-net
    expose:
      - 30002
    ports:
      - 30002:30002
    restart: always
    entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--port", "30002", "--replSet", "devrs" ]
  mongo3:
    hostname: mongo3
    container_name: mongo3
    image: mongo:4.0.10
    volumes:
      - /mongodb/data3/db:/data/db
      - /mongodb/data3/configdb:/data/configdb
    networks:
      - mongo-dev-net
    expose:
      - 30003
    ports:
      - 30003:30003
    restart: always
    entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--port", "30003", "--replSet", "devrs" ]

networks:
  mongo-dev-net:

I made few changes in the above compared to my earlier setup. I am only going to review those changes here.

Configuration changes

  • I changed my storage to /mongodb/data[1,2,3] so that I do not overwrite my previous database files.
  • I modified the ports to map local port 30001 to container port 30001, because I am going to run my mongodb on a non standard port. This allows me to use use one DNS name and multiple ports to reference my replica set.
  • I modified the entrypoint to run the mongodb server on a non standard port. This allows me to build my replica set with DNS aware names.
  • I also changed to image to mongo:4.0.10, but this change is irrelevant for the comparison.

Startup

Run docker-compose up -d to start up the containers.

docker start
docker-compose up

You can see from the above, docker pulling the new image and starting up my databases.

Replica Set

I do not have a mongo client on this server, so I am going to show how to connect to the database using the mongo image and docker.


docker run --rm -it mongo:4.0.10 /bin/bash

Once inside the container run

oot@3f3e0b6457e1:/# mongo --host mongodb.pvt.skbali.com --port 30001

I start a new container with the mongodb image and connect to my new database.

Note: You could run the above in one command itself. Instead of /bin/bash supply the mongo connect string.

After connecting to the database run these commands to setup the replica set and add members.

Initiate the replica set.


rs.initiate()

The next three make sure, the first member uses DNS instead of an ip address


cfg = rs.conf()
cfg.members[0].host = "mongodb.pvt.skbali.com:30001"
rs.reconfig(cfg)

Then we add in two members which will serve as the secondary.


rs.add("mongodb.pvt.skbali.com:30002")
rs.add("mongodb.pvt.skbali.com:30003")

Testing from python

I am going to list the replica set information from python using the following test code. Edit a file named mongotest.py and save the following code.


import pymongo

host="mongodb://mongodb.pvt.skbali.com:30001,mongodb.pvt.skbali.com:30002,mongodb.pvt.skbali.com:30003/?replicaSet=devrs"

client=pymongo.MongoClient(host)
client.server_info()
print(client.primary)
print(client.secondaries)
client.close()

I am assuming you already have python pip and pymongo installed. Run the code and see output to verify the replica set information.


root@ip-172-30-0-44:~# python3 mongotest.py
('mongodb.pvt.skbali.com', 30001)
{('mongodb.pvt.skbali.com', 30002), ('mongodb.pvt.skbali.com', 30003)}

In my case the replica set information was listed as shown above. Ine master on port 30001 and two secondary members on port 30002 and 30003.

Conclusion

This setup used private DNS in AWS VPC to make a replica set on a single EC2 server which can be used by clients or application residing on other servers in the same VPC where this DNS is visible.

Mongo drivers can reference the secondary members using DNS and make use of read preference settings if required.

Further Reading

Leave a Reply