Dockerizing Node.JS apps

27. Apr 2017 23:12

In this post I go through how to Dockerize a NodeJS app built with Express.js

I usually turn to Express.js if I need any type of web-server functionality from NodeJS. It's a simple setup with only middleware, routers and views. The views are only used for errors and 404. The router just contains very simple rest-endpoints.

See all of the code here:

So... how I dockerize it

The dockerfile looks like this

FROM node:boron

#Use pm2 for a real node environment with crash handling and graceful shutdown
RUN npm install pm2 -g

# Create app directory
RUN mkdir -p /var/www/appdir
WORKDIR /var/www/appdir

# Install app dependencies
COPY package.json /var/www/appdir
#install deps
RUN npm install --production

# Bundle app source
COPY . /var/www/appdir

CMD [ "pm2-docker", "process.yml", "--env", "prod" ]

First we select a suitable image to build from, based on node-version. Docker node-images can be found here

The next thing we do is to install PM2. This is a processmanager for Node apps that helps with monitoring, clustering, logging as well as restarts your app if it crashes.

Then we go ahead and create a directory in the docker-container (we are building a container from an image) and set it as the containers app directory.

We then copy the entire app from our computer and into the container and start installing our apps production-dependencies.

By exposing 3000 we make the port available to the docker-host. By doing this the host may connect any of it's ports to the docker-container. For instance if you use NGINX with upstream to port 4000, you would start the docker container and mapping ports with the -p argument:

docker run -p 4000:3000 --name dockerexpress dockerexpress

Setting up PM2

To make PM2 work nicely with Docker, we want to use a process file with some environment variables in it.

#This in Dockerfile...
CMD [ "pm2-docker", "process.yml", "--env", "prod" ]

#...would be the same as this in the terminal
pm2-docker process.yml --env prod

The process.yml looks like this:

  - script   : 'index.js'
    name     : 'Service'
    exec_mode: 'cluster'
    instances: 4
        PORT: 3000
        NODE_ENV: "development"
        PORT: 3000
        NODE_ENV: "production"

Building the docker image

When all is set up you build the docker image like this

docker build -t dockerexpress .

To start a container:

docker run -p 4000:3000 --name dockerexpress dockerexpress

What happens here is that we map the ports, sets a name for the container and selectes the image we tagges as dockerexpress. In this example i just gave them the same name. There's a lot more to docker than this, but it's a start.