Improved Dockerfile for a Node.js application

A not so great Dockerfile

Not that long ago, when I needed to dockerize my Node.js application, I used a Dockerfile like the following one.


FROM node:4.4.5

# Copy src files
COPY . /app/

# Use /app working directory
WORKDIR /app

# Expose API port
EXPOSE 80

# Build dependencies
RUN npm install

# Run application
CMD ["npm", "start"]

Basically, I tell Docker

  • to start from the official Node.js image node:4.4.5
  • to copy all the sources of the current directory into the image’s /app directory
  • to compile and install all the dependencies
  • how to instantiate a container

Why this Dockerfile is not so great ? Let’s put this against a development workflow.
Very often, a developer needs to fix some bugs and add features in his code.
Less often he needs to add new dependencies.

With this Dockerfile, each time a small modification is done in the code, the

COPY . /app/

instruction invalidates the cache and then triggers the compilation of the dependencies (that can take several minutes). We then need to find a way to use the cache for the dependencies if the list has not changed between 2 successive build of the image.

A better Dockerfile

In order to use the cache created for the dependencies, the compilation needs to be done before the copy of the application source code. This implies an additional step in order to compile the dependencies in a temporary folder and then to move then in the application folder.

In order not to have the local node_modules folder override the one created in the image, make sure you have a .dockerignore file containing « node_modules » to this folder is not taken into account in the context sent to the Docker daemon.

.dockerignore can be as minimal as:


node_modules

A better version of the above Dockerfile is listed below.


FROM mhart/alpine-node:4.4.5

# Copy list of dependencies
COPY package.json /tmp/package.json

# Install dependencies
RUN cd /tmp && npm install

# Copy dependencies libraries
RUN mkdir /app && cp -a /tmp/node_modules /app/

# Copy source code
COPY . /app

# Change current dir
WORKDIR /app

# Expose API port
EXPOSE 80

# Run application
CMD ["npm", "start"]

Note: in this file we use the mhart/alpine-node:4.4.5 Node.js image, that is much lighter (because it’s based on Linux Alpine) than the previous one (based on Ubuntu…).

2 réflexions au sujet de « Improved Dockerfile for a Node.js application »

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *