Running multi-container Nodejs application using docker-compose
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 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 which were supposed to run in conjugation with each other.
This 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.
Scenario: Running a Nodejs application in one container, and Nginx as a reverse proxy to Nodejs application in the second container using docker-compose.
Before moving to docker-compose, I had already made Dockerfiles for both Nginx and Nodejs. So, I decided to reference these Dockerfiles in docker-compose.yml.
Let’s have a look at the directory structure we will be using:
[js]root@singh ~/node # ls -R
.:
docker-compose.yml nginx nodejs
./nginx:
default Dockerfile nginx.conf startUp.sh
./nodejs:
app.js Dockerfile startUp.sh
[/js]
“nginx” directory contains Nginx’s Dockerfile and other related files which we have referenced inside their respective Dockerfile as shown below:
[js]root@singh ~/node #cat nginx/Dockerfile
FROM navjotece19/nginx-as-a-proxy:v1.0
MAINTAINER NavjotSingh <navjot.singh[at]tothenew[dot]com>
ADD default /etc/nginx/sites-enabled/default
ADD nginx.conf /etc/nginx/nginx.conf
ADD startUp.sh /root/startUp.sh
RUN chmod +x /root/startUp.sh
CMD ["/root/startUp.sh"]
[/js]
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:
[js]root@singh ~/node #cat nginx/startUp.sh
#!/bin/bash
> /var/log/nginx/access.log
> /var/log/nginx/error.log
/usr/sbin/nginx &
tail -f /var/log/nginx/access.log
[/js]
“default” file has proxy pass configuration, proxying to port 7777 to Nodejs container as shown below:
[js]root@singh ~/node #cat default
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /usr/share/nginx/html;
index index.html index.htm;
server_name localhost;
location / {
proxy_pass http://nodejs:7777;
}
}[/js]
“nginx.conf” has default Nginx configuration parameters.
Lets move to the Nodejs directory which contains Dockerfile, app.js (print hello world) and startUp.sh.
[js]root@singh ~/node #cat Dockerfile
FROM navjotece19/nodejs:v1.0
MAINTAINER AS-Support <navjot.singh[at]tothenew[DOT]com>
ADD app.js /root/code/app.js
ADD startUp.sh /startUp.sh
RUN chmod +x /startUp.sh
CMD ["/startUp.sh"]
[/js]
“navjotece19/nodejs:v1.0” image has Nodejs already installed in it. We are adding “app.js” and “startUp.sh” files in Nodejs container and passing “startUp.sh” in CMD of Dockerfile.
[js]root@singh ~/node #cat app.js
var express = require(‘express’);
var app = express();
app.get(‘/’, function (req, res) {
res.send(‘Hello World!’);
});
var server = app.listen(7777, function () {
var host = server.address().address;
var port = server.address().port;
console.log(‘Example app listening at http://%s:%s’, host, port);
});
[/js]
[js]root@singh ~/node #cat startUp.sh
FROM navjotece19/nodejs:v1.0
MAINTAINER AS-Support <navjot.singh[at]tothenew[DOT]com>
ADD app.js /root/code/app.js
ADD startUp.sh /startUp.sh
RUN chmod +x /startUp.sh
CMD ["/startUp.sh"]
[/js]
Now, let’s create “docker-compose.yml” file. We have referenced the above two Dockerfiles inside it as shown below:
[js]root@singh ~/node #cat docker-compose.yml
nginx:
build: ./nginx
ports:
– "8081:80"
container_name: nginx-reverse-proxy
links:
– nodejs:nodejs
nodejs:
build: ./nodejs
container_name: nodejs
[/js]
First part is for “nginx” service providing the following details:
- build: relative/absolute path of directory containing Dockerfile.
- ports: similar to -p option while using with docker run.
- container_name: actual container name we want to give to our container.
- links: to links two containers, we have linked Nginx with Nodejs.
Second part is for nodejs providing the Dockerfile path and container name.
We are done with the configuration, now we will execute command to bring up the two container at once.
In case, if the specified container name under links does not exit in the docker-compose.yml file, the below command will throw error:
[js]root@singh ~/node #docker-compose up -d
Building nodejs…
Step 0 : FROM navjotece19/nodejs:v1.0
—> ce0e94364f8f
Step 1 : MAINTAINER AS-Support <navjot.singh[at]tothenew[DOT]com>
—> Using cache
—> a2b9677a97ee
Step 2 : ADD app.js /root/code/app.js
—> 50432306d640
Removing intermediate container f91fe7f4fc4a
Step 3 : ADD startUp.sh /startUp.sh
—> 5be07c8c5086
Removing intermediate container efa6011e27f4
Step 4 : RUN chmod +x /startUp.sh
—> Running in 970610931cbf
—> c725e61e64ab
Removing intermediate container 970610931cbf
Step 5 : CMD /startUp.sh
—> Running in 9d6d2589910c
—> 7877b8ff8f64
Removing intermediate container 9d6d2589910c
Successfully built 7877b8ff8f64
Creating nodejs…
Building nginx…
Step 0 : FROM navjotece19/nginx-as-a-proxy:v1.0
—> d4d6dbdf6558
Step 1 : MAINTAINER NavjotSingh <navjot.singh[at]tothenew[dot]com>
—> Running in 226d64d45500
—> abfb8f4c5b73
Removing intermediate container 226d64d45500
Step 2 : ADD default /etc/nginx/sites-enabled/default
—> 25ff5c0d6d21
Removing intermediate container ce21908b4a97
Step 3 : ADD nginx.conf /etc/nginx/nginx.conf
—> acde21e43cf1
Removing intermediate container 16032bfefeeb
Step 4 : ADD startUp.sh /root/startUp.sh
—> 6590c92e387b
Removing intermediate container 7aceb4a2dd20
Step 5 : RUN chmod +x /root/startUp.sh
—> Running in 34120e29ff8d
—> ea9d469e13df
Removing intermediate container 34120e29ff8d
Step 6 : CMD /root/startUp.sh
—> Running in aa93e33232fa
—> 86b11775ed0c
Removing intermediate container aa93e33232fa
Successfully built 86b11775ed0c
Creating nginx-reverse-proxy…
[/js]
This command will take docker-compose.yml file and get executed in the detached mode.
This 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:
[js]root@singh ~/node # docker-compose up -d
Creating nodejs…
Creating nginx-reverse-proxy…
[/js]
Created Images are as below:
[js]node_nginx latest 8b3e5c99c785 11 minutes ago 241.4 MB
node_nodejs latest 9787e04bb36c 11 minutes ago 649 MB
[/js]
The prefixes “node_” seems to have come from the parent directory.
Created containers are as below:
[js]docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dd06255dd7eb node_nginx "/root/startUp.sh" 37 minutes ago Up 37 minutes 0.0.0.0:8081->80/tcp nginx-reverse-proxy
266a83f5d78c node_nodejs "/startUp.sh" 37 minutes ago Up 37 minutes 80/tcp, 7766/tcp nodejs
[/js]
After this, we can connect with Nodejs app using 8081 port as shown below:
We have got our Nodejs application up and running.
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. “docker-compose” is very handy for such cases.
am trying to follow your tutorial but am lost at
FROM navjotece19/nginx-as-a-proxy:v1.0
where are you referencing the FROM