{"id":28449,"date":"2015-10-18T17:38:25","date_gmt":"2015-10-18T12:08:25","guid":{"rendered":"http:\/\/www.tothenew.com\/blog\/?p=28449"},"modified":"2016-01-19T13:29:34","modified_gmt":"2016-01-19T07:59:34","slug":"running-multi-container-nodejs-application-using-docker-compose","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/running-multi-container-nodejs-application-using-docker-compose\/","title":{"rendered":"Running multi-container Nodejs application using docker-compose"},"content":{"rendered":"<p>This blog post is about using docker-compose, a tool provided by docker to define and run multi container application using a single command. It uses a docker-compose.yml file as default input file.<br \/>\n<img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-28450\" src=\"\/blog\/wp-ttn-blog\/uploads\/2015\/10\/Dockercompose.png\" alt=\"Dockercompose\" width=\"889\" height=\"495\" \/><\/p>\n<p>I got a use case which was to run a Nodejs application behind a Nginx acting as a reverse proxy in two different Docker containers. This can be achieved using Dockerfile but it has got its own constraints as only one image can be created using a Dockerfile. So, after the creation of two different images with Dockerfiles, we would have to create two containers separately\u00a0which were supposed to run in conjugation with each other.<br \/>\nThis did not seem to be a perfect solution for the problem scenario. After some search, I found docker-compose, read about it and concluded that it is the most apt tool to go with for the use case.<\/p>\n<p><strong>Scenario:<\/strong> Running a Nodejs application in one container, and Nginx as a reverse proxy to Nodejs application in the second container using docker-compose.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-28455\" src=\"\/blog\/wp-ttn-blog\/uploads\/2015\/10\/1-_MtS4HqN2srTcrSyet61DQ.jpeg\" alt=\"1-_MtS4HqN2srTcrSyet61DQ\" width=\"1354\" height=\"604\" \/><\/p>\n<p>Before moving to docker-compose, I had already made Dockerfiles for both Nginx and Nodejs. So, I decided to reference these Dockerfiles in <strong>docker-compose.yml<\/strong>.<\/p>\n<p>Let\u2019s have a look at the directory structure we will be using:<\/p>\n<p>[js]root@singh ~\/node # ls -R<br \/>\n.:<br \/>\ndocker-compose.yml  nginx  nodejs<\/p>\n<p>.\/nginx:<br \/>\ndefault  Dockerfile  nginx.conf  startUp.sh<\/p>\n<p>.\/nodejs:<br \/>\napp.js  Dockerfile  startUp.sh<br \/>\n[\/js]<\/p>\n<p>&#8220;nginx&#8221; directory contains Nginx\u2019s Dockerfile and other related files which we have referenced inside their respective Dockerfile as shown below:<\/p>\n<p>[js]root@singh ~\/node #cat nginx\/Dockerfile<br \/>\nFROM navjotece19\/nginx-as-a-proxy:v1.0<br \/>\nMAINTAINER NavjotSingh &lt;navjot.singh[at]tothenew[dot]com&gt;<br \/>\nADD default \/etc\/nginx\/sites-enabled\/default<br \/>\nADD nginx.conf \/etc\/nginx\/nginx.conf<br \/>\nADD startUp.sh \/root\/startUp.sh<br \/>\nRUN chmod +x \/root\/startUp.sh<br \/>\nCMD [&quot;\/root\/startUp.sh&quot;]<br \/>\n[\/js]<\/p>\n<p>We have added default, nginx.conf and startUp.sh files in Dockerfile whereas we have passed startUp.sh file as and argument to CMD for Nginx container:<\/p>\n<p>[js]root@singh ~\/node #cat nginx\/startUp.sh<br \/>\n#!\/bin\/bash<br \/>\n&gt; \/var\/log\/nginx\/access.log<br \/>\n&gt; \/var\/log\/nginx\/error.log<br \/>\n\/usr\/sbin\/nginx &amp;<br \/>\ntail -f \/var\/log\/nginx\/access.log<br \/>\n[\/js]<\/p>\n<p>&#8220;default&#8221; file has proxy pass configuration, proxying to port 7777 to Nodejs container as shown below:<\/p>\n<p>[js]root@singh ~\/node #cat default<br \/>\nserver {<br \/>\n        listen 80 default_server;<br \/>\n        listen [::]:80 default_server ipv6only=on;<\/p>\n<p>        root \/usr\/share\/nginx\/html;<br \/>\n        index index.html index.htm;<\/p>\n<p>        server_name localhost;<br \/>\n        location \/ {<br \/>\n                proxy_pass http:\/\/nodejs:7777;<br \/>\n        }<br \/>\n}[\/js]<\/p>\n<p>&#8220;nginx.conf&#8221; has default Nginx configuration parameters.<\/p>\n<p>Lets move to the Nodejs directory which contains Dockerfile, app.js (print hello world) and startUp.sh.<\/p>\n<p>[js]root@singh ~\/node #cat Dockerfile<br \/>\nFROM navjotece19\/nodejs:v1.0<br \/>\nMAINTAINER AS-Support &lt;navjot.singh[at]tothenew[DOT]com&gt;<br \/>\nADD app.js \/root\/code\/app.js<br \/>\nADD startUp.sh \/startUp.sh<br \/>\nRUN chmod +x \/startUp.sh<br \/>\nCMD [&quot;\/startUp.sh&quot;]<br \/>\n[\/js]<\/p>\n<p>&#8220;navjotece19\/nodejs:v1.0&#8221; image has Nodejs already installed in it. We are adding &#8220;app.js&#8221; and &#8220;startUp.sh&#8221; files in Nodejs container and passing &#8220;startUp.sh&#8221; in CMD of Dockerfile.<\/p>\n<p>[js]root@singh ~\/node #cat app.js<br \/>\nvar express = require(&#8216;express&#8217;);<br \/>\nvar app = express();<\/p>\n<p>app.get(&#8216;\/&#8217;, function (req, res) {<br \/>\n  res.send(&#8216;Hello World!&#8217;);<br \/>\n});<\/p>\n<p>var server = app.listen(7777, function () {<br \/>\n  var host = server.address().address;<br \/>\n  var port = server.address().port;<\/p>\n<p>  console.log(&#8216;Example app listening at http:\/\/%s:%s&#8217;, host, port);<br \/>\n});<br \/>\n[\/js]<\/p>\n<p>[js]root@singh ~\/node #cat startUp.sh<br \/>\nFROM navjotece19\/nodejs:v1.0<br \/>\nMAINTAINER AS-Support &lt;navjot.singh[at]tothenew[DOT]com&gt;<br \/>\nADD app.js \/root\/code\/app.js<br \/>\nADD startUp.sh \/startUp.sh<br \/>\nRUN chmod +x \/startUp.sh<br \/>\nCMD [&quot;\/startUp.sh&quot;]<br \/>\n[\/js]<\/p>\n<p>Now, let&#8217;s create &#8220;docker-compose.yml&#8221; file. We have referenced the above two Dockerfiles inside it as shown below:<\/p>\n<p>[js]root@singh ~\/node #cat docker-compose.yml<br \/>\nnginx:<br \/>\n build: .\/nginx<br \/>\n ports:<br \/>\n  &#8211; &quot;8081:80&quot;<br \/>\n container_name: nginx-reverse-proxy<br \/>\n links:<br \/>\n  &#8211; nodejs:nodejs<br \/>\nnodejs:<br \/>\n build: .\/nodejs<br \/>\n container_name: nodejs<br \/>\n[\/js]<\/p>\n<p>First part is for &#8220;nginx&#8221; service providing the following details:<\/p>\n<ul>\n<li>build: relative\/absolute path of directory containing Dockerfile.<\/li>\n<li>ports: similar to -p option while using with docker run.<\/li>\n<li>container_name: actual container name we want to give to our container.<\/li>\n<li>links: to links two containers, we have linked Nginx with Nodejs.<\/li>\n<\/ul>\n<p>Second part is for nodejs providing the Dockerfile path and container name.<br \/>\nWe are done with the configuration, now we will execute command to bring up the two container at once.<\/p>\n<p>In case, if the specified container name under links does not exit in the docker-compose.yml file, the below command will throw error:<\/p>\n<p>[js]root@singh ~\/node #docker-compose up -d<br \/>\nBuilding nodejs&#8230;<br \/>\nStep 0 : FROM navjotece19\/nodejs:v1.0<br \/>\n &#8212;&gt; ce0e94364f8f<br \/>\nStep 1 : MAINTAINER AS-Support &lt;navjot.singh[at]tothenew[DOT]com&gt;<br \/>\n &#8212;&gt; Using cache<br \/>\n &#8212;&gt; a2b9677a97ee<br \/>\nStep 2 : ADD app.js \/root\/code\/app.js<br \/>\n &#8212;&gt; 50432306d640<br \/>\nRemoving intermediate container f91fe7f4fc4a<br \/>\nStep 3 : ADD startUp.sh \/startUp.sh<br \/>\n &#8212;&gt; 5be07c8c5086<br \/>\nRemoving intermediate container efa6011e27f4<br \/>\nStep 4 : RUN chmod +x \/startUp.sh<br \/>\n &#8212;&gt; Running in 970610931cbf<br \/>\n &#8212;&gt; c725e61e64ab<br \/>\nRemoving intermediate container 970610931cbf<br \/>\nStep 5 : CMD \/startUp.sh<br \/>\n &#8212;&gt; Running in 9d6d2589910c<br \/>\n &#8212;&gt; 7877b8ff8f64<br \/>\nRemoving intermediate container 9d6d2589910c<br \/>\nSuccessfully built 7877b8ff8f64<br \/>\nCreating nodejs&#8230;<br \/>\nBuilding nginx&#8230;<br \/>\nStep 0 : FROM navjotece19\/nginx-as-a-proxy:v1.0<br \/>\n &#8212;&gt; d4d6dbdf6558<br \/>\nStep 1 : MAINTAINER NavjotSingh &lt;navjot.singh[at]tothenew[dot]com&gt;<br \/>\n &#8212;&gt; Running in 226d64d45500<br \/>\n &#8212;&gt; abfb8f4c5b73<br \/>\nRemoving intermediate container 226d64d45500<br \/>\nStep 2 : ADD default \/etc\/nginx\/sites-enabled\/default<br \/>\n &#8212;&gt; 25ff5c0d6d21<br \/>\nRemoving intermediate container ce21908b4a97<br \/>\nStep 3 : ADD nginx.conf \/etc\/nginx\/nginx.conf<br \/>\n &#8212;&gt; acde21e43cf1<br \/>\nRemoving intermediate container 16032bfefeeb<br \/>\nStep 4 : ADD startUp.sh \/root\/startUp.sh<br \/>\n &#8212;&gt; 6590c92e387b<br \/>\nRemoving intermediate container 7aceb4a2dd20<br \/>\nStep 5 : RUN chmod +x \/root\/startUp.sh<br \/>\n &#8212;&gt; Running in 34120e29ff8d<br \/>\n &#8212;&gt; ea9d469e13df<br \/>\nRemoving intermediate container 34120e29ff8d<br \/>\nStep 6 : CMD \/root\/startUp.sh<br \/>\n &#8212;&gt; Running in aa93e33232fa<br \/>\n &#8212;&gt; 86b11775ed0c<br \/>\nRemoving intermediate container aa93e33232fa<br \/>\nSuccessfully built 86b11775ed0c<br \/>\nCreating nginx-reverse-proxy&#8230;<br \/>\n[\/js]<\/p>\n<p>This command will take <strong>docker-compose.yml<\/strong> file and get executed in the detached mode.<br \/>\nThis command will create two images for each Nginx and Nodejs when executed for the first time and bring up two containers and we get our application running. Next time if we run it again, this will simply create containers as shown below:<\/p>\n<p>[js]root@singh ~\/node # docker-compose up -d<br \/>\nCreating nodejs&#8230;<br \/>\nCreating nginx-reverse-proxy&#8230;<br \/>\n[\/js]<\/p>\n<p>Created Images are as below:<\/p>\n<p>[js]node_nginx                     latest              8b3e5c99c785        11 minutes ago      241.4 MB<br \/>\nnode_nodejs                    latest              9787e04bb36c        11 minutes ago      649 MB<br \/>\n[\/js]<\/p>\n<p>The prefixes \u201cnode_\u201d seems to have come from the parent directory.<\/p>\n<p>Created containers are as below:<\/p>\n<p>[js]docker ps<br \/>\nCONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                  NAMES<br \/>\ndd06255dd7eb        node_nginx          &quot;\/root\/startUp.sh&quot;   37 minutes ago      Up 37 minutes       0.0.0.0:8081-&gt;80\/tcp   nginx-reverse-proxy<br \/>\n266a83f5d78c        node_nodejs         &quot;\/startUp.sh&quot;        37 minutes ago      Up 37 minutes       80\/tcp, 7766\/tcp       nodejs<br \/>\n[\/js]<\/p>\n<p>&nbsp;<\/p>\n<p>After this, we can connect with Nodejs app using 8081 port as shown below:<br \/>\n<img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-28459\" src=\"\/blog\/wp-ttn-blog\/uploads\/2015\/10\/nodejs-helloworld.png\" alt=\"nodejs-helloworld\" width=\"606\" height=\"260\" \/><\/p>\n<p>We have got our Nodejs application up and running.<\/p>\n<p>This is one use case I have implemented using docker-composer. In most of the web applications, we usually have multiple modules running on different nodes. &#8220;<strong>docker-compose<\/strong>&#8221; is very handy for such cases.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This blog post is about using docker-compose, a tool provided by docker to define and run multi container application using a single command. It uses a docker-compose.yml file as default input file. I got a use case which was to run a Nodejs application behind a Nginx acting as a reverse proxy in two different [&hellip;]<\/p>\n","protected":false},"author":154,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":5},"categories":[1174,2348,1185],"tags":[1891,1892,1883,2594,2590,2558,2620,2621,2615,2613,2614,1336,1177,2593,2592,2591,2618,2619,2616,2617],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/28449"}],"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\/154"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=28449"}],"version-history":[{"count":0,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/28449\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=28449"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=28449"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=28449"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}