{"id":25866,"date":"2015-08-31T19:02:00","date_gmt":"2015-08-31T13:32:00","guid":{"rendered":"http:\/\/www.tothenew.com\/blog\/?p=25866"},"modified":"2017-11-22T16:01:47","modified_gmt":"2017-11-22T10:31:47","slug":"mongodb-replica-set-on-docker","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/mongodb-replica-set-on-docker\/","title":{"rendered":"MongoDB Replica Set on Docker"},"content":{"rendered":"<p style=\"text-align: justify;\">In the previous <a href=\"http:\/\/www.tothenew.com\/blog\/how-to-setup-replica-sets-in-mongo-db-aws-ec2\/\">blog<\/a>, we discussed about how to setup MongoDB replica set on AWS EC2. In this blog post, we will be discussing about\u00a0setting up MongoDB replica set of three Docker containers running on a single host. After going through this blog, you will be able to setup MongoDB replica set in a few minutes and it will be easy to maintain and configure. We will create custom Docker image with pre-installed MongoDB using base Ubuntu image and Dockerfile. Dockerfile is a text file that contains all the commands required by the user to bundle custom image and by using Docker build you can create an automated build that executes command line instruction mentioned in the Dockerfile in succession.<\/p>\n<p style=\"text-align: justify;\"><strong>Use Case:<\/strong>\u00a0We are currently using MongoDB in most of our projects, and we often get requirement from the development team to set-up new MongoDB replica sets for testing. Using this script we can now start new replica sets in minutes.<\/p>\n<p style=\"text-align: justify;\"><strong>Pre-requisites:<\/strong> Before starting this blog, it is required to have basic understanding of Docker and its basic features. If you want to go through basics of Docker click <a href=\"http:\/\/www.tothenew.com\/blog\/docker-scenario-installing-and-using-apache-web-server-in-docker-container\/\">here<\/a><\/p>\n<p style=\"text-align: justify;\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-26022\" src=\"\/blog\/wp-ttn-blog\/uploads\/2015\/08\/mongodb_replicaset_docker_setup_11.png\" alt=\"mongodb_replicaset_docker_setup_1\" width=\"685\" height=\"400\" \/><\/p>\n<p style=\"text-align: justify;\">To make deployment process easier I have written custom shell script to deploy complete replica set in few minutes. So here is the overview of complete process:<\/p>\n<ul>\n<li style=\"text-align: justify;\">Create custom Docker image that will comprise of Ubuntu base image and MongodDB version 2.0.3<\/li>\n<li style=\"text-align: justify;\">Deploy three containers using custom Docker image (created in the\u00a0previous step)<\/li>\n<li style=\"text-align: justify;\">Initiate replica set on the master container and enable slave mode on the other two containers.<\/li>\n<\/ul>\n<h6 style=\"text-align: justify;\"><span style=\"color: #ff0000;\"><strong>Note: This setup can be used in development and testing environment, it is not recommended for production environment.<\/strong><\/span><\/h6>\n<p style=\"text-align: justify;\"><strong>Create custom Docker image:-<\/strong><\/p>\n<ul>\n<ul>\n<li style=\"text-align: justify;\">Create Dockerfile\u00a0and add below mentioned content to it.<\/li>\n<\/ul>\n<\/ul>\n<p>[js]mkdir \/mongodb<br \/>\ntouch \/mongodb\/Dockerfile # add below mentioned content<br \/>\ndocker build -t neerjaj2\/mongodb \/mongodb\/. [\/js]<\/p>\n<ul>\n<ul>\n<li>To use my Docker hub image use:-<\/li>\n<\/ul>\n<\/ul>\n<p>[js]docker search neerjaj2\/mongodb<br \/>\ndocker pull neerjaj2\/mongodb[\/js]<\/p>\n<p><strong> Dockerfile:-<\/strong><\/p>\n<p>[js]FROM ubuntu:latest<br \/>\nRUN apt-key adv &#8211;keyserver hkp:\/\/keyserver.ubuntu.com:80 &#8211;recv 7F0CEB10<br \/>\nRUN echo &#8216;deb http:\/\/downloads-distro.mongodb.org\/repo\/ubuntu-upstart dist 10gen&#8217; | tee \/etc\/apt\/sources.list.d\/10gen.list<br \/>\nRUN apt-get update<br \/>\nRUN apt-get install -y mongodb-10gen=2.2.3<br \/>\nRUN mkdir -p \/data\/db<br \/>\nEXPOSE 27017<br \/>\nENTRYPOINT [&quot;usr\/bin\/mongod&quot;] [\/js]<\/p>\n<p style=\"text-align: justify;\"><strong>Script to start MongoDB containers:-<\/strong><\/p>\n<ol>\n<li style=\"text-align: justify;\">Spinning up three Docker containers with specific host names, image name and custom parameters like replica set name, pre-allocation and file size.<\/li>\n<li style=\"text-align: justify;\">Once containers are up script will extract containers IP and hostname in a new file getip.txt and it is then copied to all the containers.<\/li>\n<li style=\"text-align: justify;\">After that updateHost.sh\u00a0script (generated in the main script) will be copied to all the containers and executed. The purpose of updateHost.sh is to update \/etc\/hosts file with the latest container IP\u2019s and hostnames. (This is an alternative to &#8211;add-host in Docker command )<\/li>\n<li style=\"text-align: justify;\">At last the script will run rs.status(), rs.initiate() and rs.add() command on the first node \u00a0(mongo1.ttnd.com) and rs.slaveOk() on remaining two nodes (mongo2.ttnd.com and mongo3.ttnd.com). As a result first node is configured as primary and remaining two as secondary nodes. Find details in the screenshot below:-<\/li>\n<\/ol>\n<p>[js]#!\/bin\/bash<br \/>\n# Define Hostnames<br \/>\nh1=&quot;mongo1.ttnd.com&quot;<br \/>\nh2=&quot;mongo2.ttnd.com&quot;<br \/>\nh3=&quot;mongo3.ttnd.com&quot;<\/p>\n<p># Start containers with specific hostnames and replica set name<br \/>\ndocker run -P &#8211;name ttnd1 &#8211;hostname=&quot;$h1&quot; -d neerjaj2\/mongodb &#8211;replSet ttnd &#8211;noprealloc &#8211;smallfiles<br \/>\ndocker run -P &#8211;name ttnd2 &#8211;hostname=&quot;$h2&quot; -d neerjaj2\/mongodb &#8211;replSet ttnd &#8211;noprealloc &#8211;smallfiles<br \/>\ndocker run -P &#8211;name ttnd3 &#8211;hostname=&quot;$h3&quot; -d neerjaj2\/mongodb &#8211;replSet ttnd &#8211;noprealloc &#8211;smallfiles<\/p>\n<p># Commands to extract IP addresses of containers<br \/>\necho $(docker inspect &#8211;format &#8216;{{ .NetworkSettings.IPAddress }}&#8217; ttnd1) &quot;$h1&quot; &gt; getip.txt<br \/>\necho $(docker inspect &#8211;format &#8216;{{ .NetworkSettings.IPAddress }}&#8217; ttnd2) &quot;$h2&quot; &gt;&gt; getip.txt<br \/>\necho $(docker inspect &#8211;format &#8216;{{ .NetworkSettings.IPAddress }}&#8217; ttnd3) &quot;$h3&quot; &gt;&gt; getip.txt<\/p>\n<p># Commands to cp getip.txt to containers<br \/>\ndocker cp getip.txt ttnd1:\/etc<br \/>\ndocker cp getip.txt ttnd2:\/etc<br \/>\ndocker cp getip.txt ttnd3:\/etc<\/p>\n<p># Commands to create new file updateHost.sh (to update \/etc\/hosts file in all the three docker containers)<br \/>\necho &quot;#!\/bin\/bash<br \/>\ncat \/etc\/hosts &gt; \/etc\/hosts1<br \/>\nsed -i &#8216;\/ttnd.com\/d&#8217; \/etc\/hosts1<br \/>\ncat \/etc\/getip.txt &gt;&gt; \/etc\/hosts1<br \/>\ncat \/etc\/hosts1 &gt; \/etc\/hosts&quot; &gt; updateHost.sh<\/p>\n<p># Change permission of updateHost.sh and cp files to docker container<br \/>\nchmod +x updateHost.sh<br \/>\ndocker cp updateHost.sh ttnd1:\/etc<br \/>\ndocker cp updateHost.sh ttnd2:\/etc<br \/>\ndocker cp updateHost.sh ttnd3:\/etc<br \/>\ndocker exec -it ttnd1 chmod +x \/etc\/updateHost.sh<br \/>\ndocker exec -it ttnd2 chmod +x \/etc\/updateHost.sh<br \/>\ndocker exec -it ttnd3 chmod +x \/etc\/updateHost.sh<\/p>\n<p># Execute scripts on all the three containers<br \/>\ndocker exec -it ttnd1 \/etc\/updateHost.sh<br \/>\ndocker exec -it ttnd2 \/etc\/updateHost.sh<br \/>\ndocker exec -it ttnd3 \/etc\/updateHost.sh<br \/>\n# Start MongoDB Replica Set with Primary<br \/>\ndocker exec -it ttnd1 mongo &#8211;eval &quot;rs.status()&quot;<br \/>\ndocker exec -it ttnd1 mongo &#8211;eval &quot;db&quot;<br \/>\ndocker exec -it ttnd1 mongo &#8211;eval &quot;rs.initiate()&quot;<br \/>\nsleep 120<br \/>\ndocker exec -it ttnd1 mongo &#8211;eval &quot;rs.add(\\&quot;$h2:27017\\&quot;)&quot;<br \/>\ndocker exec -it ttnd1 mongo &#8211;eval &quot;rs.add(\\&quot;$h3:27017\\&quot;)&quot;<br \/>\ndocker exec -it ttnd2 mongo &#8211;eval &quot;rs.slaveOk()&quot;<br \/>\ndocker exec -it ttnd3 mongo &#8211;eval &quot;rs.slaveOk()&quot; [\/js]<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-25871\" src=\"\/blog\/wp-ttn-blog\/uploads\/2015\/08\/mongodb_check_replicaset_status_2.png\" alt=\"mongodb_check_replicaset_status_2\" width=\"685\" height=\"505\" \/><\/p>\n<p style=\"text-align: justify;\">After executing the script or running commands manually, you can list active containers by using command \u201c<strong>docker ps<\/strong>\u201d.<\/p>\n<p>[js]docker ps[\/js]<\/p>\n<p style=\"text-align: justify;\">Once we have complete MongoDB replica set running let us add some data on the primary node and test replication on secondary nodes. So, I have added five records using commands:-<\/p>\n<p>[js]db.people.save() # to insert data in the people collection<br \/>\ndb.people.find() # to list down all the records in the people collection[\/js]<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-25868\" src=\"\/blog\/wp-ttn-blog\/uploads\/2015\/08\/add_data_to_primary_mongodb_node_3.png\" alt=\"add_data_to_primary_mongodb_node_3\" width=\"685\" height=\"97\" \/><\/p>\n<p style=\"text-align: justify;\">Let us now switch to the secondary MongoDB container using below-mentioned commands and test, read and write request on the secondary node. In this example, I am trying to insert new user Ram2 in people collection, but I am unable to do so because it is not a master node. Secondly, we can still read complete database using &#8220;<strong>find()<\/strong>&#8221; command.<\/p>\n<p>[js]docker exec -it ttnd2 \/bin\/bash [\/js]<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-25869\" src=\"\/blog\/wp-ttn-blog\/uploads\/2015\/08\/add_data_to_secondary_mongodb_node_4.png\" alt=\"add_data_to_secondary_mongodb_node_4\" width=\"685\" height=\"101\" \/><\/p>\n<p style=\"text-align: justify;\">Great, everything is working as expected, let us now test failover. We can do this by either terminating or stopping primary MongoDB container and check the status of remaining two MongoDB containers. In the current example let us stop primary MongoDB container by using command:-<\/p>\n<p>[js]docker stop ttnd1[\/js]<\/p>\n<p style=\"text-align: justify;\">After running above command check status of MongoDB replica set by running rs.status( ) command in any of the two available nodes as shown below (ttnd2 or ttnd3).<\/p>\n<p>[js]docker exec -it ttnd2 \/bin\/bash<br \/>\nmongo<br \/>\nrs.status().members[\/js]<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-25870\" src=\"\/blog\/wp-ttn-blog\/uploads\/2015\/08\/check_mongodb_replicaset_failover_5.png\" alt=\"check_mongodb_replicaset_failover_5\" width=\"685\" height=\"525\" \/><\/p>\n<p>From the screenshot above, you can see that original primary node (mongo1.ttnd.com) is in unavailable\u00a0state and third node (mongo3.ttnd.com) has become the primary node.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous blog, we discussed about how to setup MongoDB replica set on AWS EC2. In this blog post, we will be discussing about\u00a0setting up MongoDB replica set of three Docker containers running on a single host. After going through this blog, you will be able to setup MongoDB replica set in a few [&hellip;]<\/p>\n","protected":false},"author":216,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":11},"categories":[1174],"tags":[1883,2257,2256],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/25866"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/216"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=25866"}],"version-history":[{"count":1,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/25866\/revisions"}],"predecessor-version":[{"id":52473,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/25866\/revisions\/52473"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=25866"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=25866"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=25866"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}