Docker Getting Started – NodeJs Express App

In this post we will see simple steps to get started with setting up a nodejs app in docker.

Step1 - Basic Setup

First step is install docker, for this the official guide can be followed https://docs.docker.com/engine/install/ubuntu/

Next step is to have a running express app. For the purpose of this example let’s use the app from express official website https://expressjs.com/en/starter/hello-world.html

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => res.send('Hello World!'))

app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))

So you can follow this steps on terminal to get this app up and running.

So these steps can be followed to get a basic app running

mkdir sample_app
cd sample_app
nano index.js # copy paste the above code here
npm init # just keep pressing enter
npm install express --save
node index.js

After doing above you should have a app running open localhost:3000 on your browser to confirm.

Step2 - Dockerfile

We have installed docker and also have expressjs app running. Now let’s try to run the same app using docker.

First we need to create a Dockerfile.

Dockerfile has instruction which we provide to docker to run the app.

Create a new file called “Dockerfile” in project root folder and paste this

FROM  node:13

WORKDIR /workspace

COPY package.json /workspace
COPY index.js /workspace

RUN npm install

EXPOSE 3000


CMD [ "node" , "index.js" ]

The above code should be self explanatory. If any instruction is not clear, there is documentation available online.

Next run the command

sudo docker build -t sample_blog_image .

What we done here is just build the above docker file and “-t” is used to tag the build with name “sample_blog”.

If all went well you should see output like this

Removing intermediate container 576a205ac8f0
 ---> ea35b2c0c8ca
Step 6/7 : EXPOSE 3000
 ---> Running in 171adcd7515e
Removing intermediate container 171adcd7515e
 ---> 2bfa2fadcdc9
Step 7/7 : CMD [ "node" , "index.js" ]
 ---> Running in 9ec883e0d78d
Removing intermediate container 9ec883e0d78d
 ---> 4792f9f8377a
Successfully built 4792f9f8377a
Successfully tagged sample_blog:latest

Take a step back here and lets see what we have.

Review Steps

What we did till now. First we instruction to use node:13

Docker run on images, image are basically recompiled operating systems which are devoted to one specific task. Mostly these are based on alpine linux https://alpinelinux.org/about/ and maintained here https://hub.docker.com/

When we mentioned node:13 it refers to the official image here https://hub.docker.com/_/node

So in layman terms, docker will download this linux image with node 13 installed on it and run it on your system. Cool!

Next, we do WORKDIR /workspace

this basically creates a directly called “workspace” in the above image and sets that as the active directly to run our commands.

Next, we have COPY commands which basically copies files from our local server or system to the linux image.

Next, using the RUN operation we can run commands on the linux image i.e npm install

Next, we EXPORT port 3000. by default all ports in a docker image a closed, expose opens them up.

Next, we have instruction called “CMD”. This is a special instruction (similar to ENTRYPOINT).

So basically will keep running the container, as long as the program in CMD is running. If the program exists, docker will also exit the container. We will see this later in practice.

Step3 - Run

Till now, we have build out image using the command

sudo docker build -t sample_blog_image .

To confirm you can run

sudo docker image ls

Next to run this image.

sudo docker container run --name sample_blog_container -p 5000:3000 sample_blog_image

This will run our image “sample_blog_image” with a container name “sample_blog_container”. Also this will map the port 3000 of the image to port 5000 in our system.

If this works properly you will see an output like this

Run localhost:5000 and you will see Hello Word again.

There are few important things to notice here

If you do CTRL + C or CTRL + D to stop the docker process it won’t work.

So to stop the process, open another terminal and run the command

sudo docker rm  sample_blog_container --force

This will stop the container.

There are few more command to which are useful. If you want to run docker in background run this command with -d i.e daemon mode

sudo docker container run --name sample_blog_container -d -p 5000:3000 sample_blog_image

If you want to open terminal of the linux os i.e the nodejs image run this command

sudo docker container run -it --rm -p 5000:3000 sample_blog_image bash

basically this run a container and open bash on it

If you already have a running container in daemon and you want to login into that use the command

sudo docker exec -it sample_blog_container bash

if you run the “top” command inside the container you will see your node script already running

Developing and Debugging

Till now, we deployed a simple expressjs app on nodejs. But this is not enough, we need to keep developer the app an debugging this. As the app gets more complex, we should be easily able to update code, see logs as if we are working without docker!

Let’s see how to do it.

Quick tip. Run command sudo docker container ls or sudo docker image ls to see your existing containers

Docker has concept of volumes https://docs.docker.com/storage/volumes/

Using docker volume’s we are able to link our system’s hard disk persistent storage to dockers container storage. So any change we make in our hard disk will get instantly reflected in the docker container and visa versa.

So to update our source code inside docker container, we need to setup a volume. Let’s see how to do it.

First, lets move our index.js file inside a directory called “src” so its src/index.js

Next, we change this in our Dockerfile

COPY package.json /workspace
#COPY index.js /workspace

VOLUME [ "/workspace/src" ]

So we made /workspace/src a volume

also change the CMD to “CMD [ “node” , “src/index.js” ]”

so our final Dockerfile looks liek

FROM  node:13

WORKDIR /workspace

COPY package.json /workspace
#COPY index.js /workspace

VOLUME [ "/workspace/src" ]

RUN npm install

EXPOSE 3000


CMD [ "node" , "src/index.js" ]

Next, build your image again

sudo docker build -t sample_blog_image .

To run the container

sudo docker container run --name sample_blog_container -v $(pwd)/src:/workspace/src -d -p 5000:3000 sample_blog_image

Here we are mapping the src/ folder in our pwd to the volume, both get linked.

You can confirm the same. Change some index in src/index.js in our system. Then using the command

sudo docker exec -it sample_blog_container bash
cat src/index.js

You can verify that the file automatically gets updated.

For further ease of development, we can use tools like nodemon to automatically react to file changes.

Let’s install nodemon in our Dockerfile (P.S. Do note this can be done via package.json also)

FROM  node:13

WORKDIR /workspace

COPY package.json /workspace
#COPY index.js /workspace

VOLUME [ "/workspace/src" ]

RUN npm install

RUN npm install -g nodemon

EXPOSE 3000


CMD [ "nodemon" ,"src/index.js" ]

also in your package.json change

"main": "src/index.js",

Next,

sudo docker build -t sample_blog_image .
sudo docker container run --name sample_blog_container -v $(pwd)/src:/workspace/src -p 5000:3000 sample_blog_image

Now, if you edit index.js via a code editor you will automatically see nodemon running inside

TIP: you can have different dockerfile to production vs development

https://stackoverflow.com/questions/46440909/how-to-configure-different-dockerfile-for-development-and-production

In this post we saw basics of docker and how to run a app with it.

excellence-social-linkdin
excellence-social-facebook
excellence-social-instagram
excellence-social-skype