Developing Node.js applications in Docker

In this post, we are going to look at developing a Node.js application using Docker as the development environment.

Why Dockerize my development?

You may ask, what is wrong with my current setup? Why should I “Dockerize my Node app”?

Well for starters, your development environment need not be the machine on which you are coding.

Let’s say that you are new to a project and you are getting started with your environment setup and you are installing an awesome plugin like grunt-contrib-imagemin and you find that its dependency libpng is missing on your machine. You Google and try to solve the problem yourself because a. you are the new member in the team and you want to prove yourself and b. you don’t know anyone in the team yet.

Everything is good so far, you were able to fix the libpng issue and now you run npm install  again and you notice that grunt-yellowlabtools needs phantomjs and for some reason the download fails while installation. Again for the above said reasons, you are too shy to approach someone so you spend the first day on the project installing the dependencies and finally setting up your environment and running your project successfully.

Very productive day one.

Now, imagine, one your first day, all you would need to do is

  1. Install Docker
  2. Run docker run -it -p 3000:3000 myproject/my-app:0.1.0

And voila, the app is running on your machine. And you are all set to get started. How about that?

4 reasons why?

Here are a few reasons why you need a “Dockerized” development environment:

  1. Your production environment will almost always never be same as your development environment. So you can directly work on your production environment setup on your local to avoid “surprising” deployment issues.
  2. Easy for your devops team to work and scale with containers in higher environments than your local
  3. One developer machine can run multiple (Node.js) applications in an isolated way
  4. Docker compose lets us run dependent pieces of softwarer in an micro service architecture easily

Now that you feel it is a good idea to Dockerize your development environment, lets look at how.

How to Dockerize a Node.js app?

We are going to follow below steps

  1. Setup Docker
  2. Build a simple Node.js application
  3. Build a Docker image
  4. Create a container from the Image and start developing.

Before we actually get started, let’s look at what is Docker.

What is Docker?

Docker is a computer program that performs operating-system-level virtualization also known as containerization.

To understand the above jibber-jabber, take a look at this video

Quite a simple and powerful concept.

If you would like to dig deeper in the world of containers, checkout this playlist from Vmware

Now that we understand the why, what and how; let’s get our hands dirty by building a Dockerized Node.js app.

Getting Started

First we are going to install Docker

Install Docker

For this tutorial, we are going to use Docker Community Edition (CE). To Install Docker on our machine, navigate to here & download the software for your OS.

Once Installed, you can open up a command prompt/terminal and run  docker ps and you should see something like

The above output shows that there are no images running.

Now, lets quickly test drive Docker.

Run  docker run busybox echo "hello from busybox"  and you should see that the busybox image downloaded locally and run the echo command that we have provided. The output would be as follows.

Now that we got the Docker installation done & verified, let’s move on.

Build a Node.js App

Now, we will setup a simple Node.js app. If you are planning to run this application on your local machine, make sure Node.js is setup on your machine. You can follow this post Hello Node. I am using the following versions

If you are going to run the app directly in a docker container, you can skip local installation of Node.js.

Anywhere on your machine, create a folder named  docker-node-app and open a new terminal/prompt there.

First, we are going to initialise a new Node.js project. Run

This will create a package.json  with default contents. Update it as shown below, as applicable

Do note that I have added a script named  start, which launches the app that we are going to create in a moment.

Now, we are going to build a simple app, which prints the environment variables on the machine it is running.

Inside docker-node-app folder, create a file named index.js  and update it as shown below

All we are doing is iterating the  process.env object & building a string with the key and value.

Test drive the Node.js application

Let’s test the application we have built. You can do this only if you have Node.js installed on your machine.

You can simply run

or

If you do not have nodemon on your machine, you can install it as follows

Once the server is up and running, navigate to http://localhost:3000/, we should see

Isni’t very brave of me to publish my machine’s environment variables out in public :/ 

Now that we have validated that the app is working fine, lets “containerize” it.

Build a Docker image

Now that we have our sample app running, let’s create an image. Inside docker-node-app  folder, create a file named Dockerfile and update it as shown below

On line 2 : we set the base image in which our app is going to run. Which is a Node image with version 8 installed.

On line 8: we create a directory where our source code would reside in the container

On line 11: we switch to the working directory

On line 15: we copy our current source code to the image

On line 18: we install nodemon globally.

On line 21: we install any other dependencies defined in  package.json

On line 24: we expose port 3000 so the host machine can access the app

On line 27: we start the Node.js app on boot of the container

Simple right?

Now to make sure we copy only what we need, we will create a file named  .dockerignore at the root of  docker-node-app and update it as shown below

Now that we are done with setup, we will build the docker image. From inside   docker-node-app  folder, run

docker-node-app docker build -t arvindr21/docker-node-app:0.1.0 .

Do note that  arvindr21 from the above command is my Dockerhub username. If you are planning to push this image to Dockerhub, it needs to be with your Dockerhub username.

Once the build kicks off, you should see logs as shown below

Now, if we run  docker-node-app docker images we should see

Awesome! Now our image is ready. We need to create a container from this image and voila our app  will be running from inside an image.

Create a conatiner & Run the app

This is the most important step in this process.

To run our Node.js app in a container, we are going to

  1. Download the code base on our local machine
  2. Point the volume of the container to the folder where the code is downloaded and run the image
  3. Open the local copy of code on your host machine text editor
  4. Start making changes

So, let’s move on. Since the codebase is already on our machine, we are not going to download it. If you project files are hosted on a remote server, download them to your local.

Next, we are going to create a container from the image and point the volume to docker-node-app  folder, as shown below

docker-node-app docker run -it -p 3000:3000 -v ${PWD}:/usr/src/app arvindr21/docker-node-app:0.1.0

/usr/src/app  : is the folder in the container

${PWD}  : is the folder on the host machine where the code is present. I am running the above command from the same folder, hence I am passing in the present working directory variable

3000 : is the port mapping between host machine and container.

Note: If you want to run this app as a background process pass a  -d or a deamon flag as shown below

docker-node-app docker run -itd -p 3000:3000 -v ${PWD}:/usr/src/app arvindr21/docker-node-app:0.1.0

If everything goes well, we should see

Now, navigate to http://localhost:3000/ and we should see something like

Do notice that the values now have updated to the environment variables from the container. Do notice the  HOSTNAME property, it is displaying a value of  cb0852847690. Now, from the host machine, run  docker ps and we should see something like

Do not the  HOSTNAME matches the  CONTAINER ID.

So, ya, it works.

Now to the awesome part, live reloading.

Live reload the container app

Now, we have our app running in a container and the code base on our host machine, let’s add a change to the code base on our local machine and see the changes reflect in the container app.

Open  index.js and update it as shown below

I have added a new piece of code to display the time.

Save the file on your host machine and we should see the following in the terminal/prompt

Now, back to http://localhost:3000/ and we should see

Voila! The time appear-th! Keep refreshing to see the value change.

Now, when you are done with the development, you can push the code to the remote repository and shutdown your Docker image. And once when you are ready to code, you can bring up the Docker image.

Adding code files

Okay, so we are able to make changes to an existing file, what about adding a new file. Let’s try that out.

Inside  docker-node-app folder, create a file called as  date.js and update it as shown below

All we have done is externalized the logic to get current date. Now, open  index.js and update it as shown below

And you should see a message in the prompt/terminal that the server restarted due to changes. Now if we go back to browser and refresh, we should see that the output does not change but we are loading the date from an external file.

Simple and powerful development environment that is development and deployment friendly.

You can find the code used in this post here: arvindr21/docker-node-app


Thanks for reading! Do comment.
@arvindr21