How to dockerize your Node.js Express application for AWS Fargate?

Michael Wittig – 05 Dec 2019

My first project with Node.js - an asynchronous event-driven JavaScript runtime, designed to build scalable network applications - was building an online trading platform in 2013. Since then, Node.js is one of my favorite technologies. I will show you how to dockerize your Node.js application based on Express - a fast, unopinionated, minimalist web framework - and run it on AWS Fargate in this blog bost. I like AWS Fargate because running containers in the cloud were never easier.

This blog post is an excerpt from our book Rapid Docker on AWS.

Read on to learn how to build a Docker image for a Node.js application.

Dockerize your Node.js application for AWS Fargate

Building the Docker image

The Dockerfile is based on the official Node.js Docker Image: node:10.16.2-stretch. Static files (folders img and css) are served by Express as well as the dynamic parts. The following details are required to understand the Dockerfile:

  • envsubst is used to generate the config file from environment variables
  • npm ci --only=production installs the dependencies declared in package.json (package-lock.json, to be more precise)
  • The Express application listens on port 8080
  • The Express application’s entry point is server.js and can be started with node server.js

A simple server.js file follows. Yours likely is more complicated.

server.js
const express = require('express');

const app = express();
app.use('/css', express.static('css'));
app.use('/img', express.static('img'));

app.get('/health-check', (req, res, next) => {
res.sendStatus(200);
});

app.listen(8080, '0.0.0.0');

Customization Most likely, your folder structure is different. Therefore, adapt the Copy config files and Copy Node.js files section in the following Dockerfile to your needs.

docker/Dockerfile
FROM node:10.16.2-stretch

WORKDIR /usr/src/app

ENV NODE_ENV production

# Install envsubst
RUN apt-get update && apt-get install -y gettext
COPY docker/custom-entrypoint /usr/local/bin/
RUN chmod u+x /usr/local/bin/custom-entrypoint
ENTRYPOINT ["custom-entrypoint"]
RUN mkdir /usr/src/app/config/

# Copy config files
COPY config/*.tmp /tmp/config/

# Install Node.js dependencies
COPY package*.json /usr/src/app/
RUN npm ci --only=production

# Copy Node.js files
COPY css /usr/src/app/css
COPY img /usr/src/app/img
COPY views /usr/src/app/views
COPY server.js /usr/src/app/

# Expose port 8080 and start Node.js server
EXPOSE 8080
CMD ["node", "server.js"]

The custom entrypoint is used to generate the config file from environment variables with envsubst.

docker/custom-entrypoint
#!/bin/bash
set -e

echo "generating configuration files"
FILES=/tmp/config/*
for f in $FILES
do
c=$(basename $f .tmp)
echo "... $c"
envsubst < $f > /usr/src/app/config/${c}
done

echo "starting $@"
exec "$@"

Next, you will learn how to test your containers and application locally.

Testing locally

Use Docker Compose to run your application locally. The following docker-compose.yml file configures Docker Compose and starts two containers: Node.js and a MySQL database.


Looking for a new challenge?

  • DEMICON

    Senior Lead Full Stack Developer

    DEMICON • AWS Advanced Consulting Partner • Remote (Europe)
    AWS JavaScript/TypeScript Angular React
  • tecRacer

    Cloud Consultant • AWS Migrations

    tecRacer • Premier AWS Consulting Partner • Germany, Austria, Portugal, and Switzerland
    Assessment Transformation Change Management

docker/docker-compose.yml
version: '3'
services:
nodejs:
build:
context: '..'
dockerfile: 'docker/Dockerfile'
ports:
- '8080:8080'
depends_on:
- mysql
environment:
DATABASE_HOST: mysql
DATABASE_NAME: app
DATABASE_USER: app
DATABASE_PASSWORD: secret
mysql:
image: 'mysql:5.6'
command: '--default-authentication-plugin=mysql_native_password'
ports:
- '3306:3306'
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: app
MYSQL_USER: app
MYSQL_PASSWORD: secret

The following command starts the application:

docker-compose -f docker/docker-compose.yml up --build

Magically, Docker Compose will spin up two containers: Node.js and MySQL. Point your browser to http://localhost:8080 to check that your web application is up and running. The log files of all containers will show up in your terminal, which simplifies debugging a lot.

After you have verified that your application is working correctly, cancel the running docker-compose process by pressing CTRL + C, and tear down the containers:

docker-compose -f docker/docker-compose.yml down

Deploying on AWS

You are now ready to deploy your application on AWS.

(1) Build Docker image:

docker build -t nodejs-express:latest -f docker/Dockerfile .

(2) Create ECR repository:

aws ecr create-repository --repository-name nodejs-express \
--query 'repository.repositoryUri' --output text

(3) Login to Docker registry (ECR):

$(aws ecr get-login --no-include-email)

(4) Tag Docker image:

docker tag nodejs-express:latest \
111111111111.dkr.ecr.eu-west-1.amazonaws.com/\
nodejs-express:latest

(5) Push Docker image:

docker push \
111111111111.dkr.ecr.eu-west-1.amazonaws.com/\
nodejs-express:latest

There is only one step missing: you need to spin up the cloud infrastructure.

  1. Use our Free Templates for AWS CloudFormation.
  2. Use our cfn-modules.
  3. Use the blueprint from our book Rapid Docker on AWS.

Become a cloudonaut supporter

Michael Wittig

Michael Wittig ( Email Twitter LinkedIn Mastodon )

We launched the cloudonaut blog in 2015. Since then, we have published 366 articles, 60 podcast episodes, and 58 videos. It's all free and means a lot of work in our spare time. We enjoy sharing our AWS knowledge with you.

Please support us

Have you learned something new by reading, listening, or watching our content? With your help, we can spend enough time to keep publishing great content in the future. Learn more

$
Amount must be a multriply of 5. E.g, 5, 10, 15.

Thanks to Alan Leech, Alex DeBrie, ANTHONY RAITI, Christopher Hipwell, e9e4e5f0faef, Jason Yorty, Jeff Finley, jhoadley, Johannes Grumböck, Johannes Konings, John Culkin, Jonas Mellquist, Jonathan Deamer, Juraj Martinka, Ken Snyder, Markus Ellers, Oriol Rodriguez, Ross Mohan, Ross Mohan, sam onaga, Satyendra Sharma, Simon Devlin, Thorsten Hoeger, Todd Valentine, Victor Grenu, waldensystems, and all anonymous supporters for your help! We also want to thank all supporters who purchased a cloudonaut t-shirt.