author

Kien Duong

May 1, 2022

Build NodeJS project with Docker

First of all, you must have an overview about Docker Compose at https://docs.docker.com/compose/

In the root project, we must create the docker-compose.yml file to define the necessary services for a NodeJS project.

Inside the package.json file, we define 3 new commands for running Docker:

    // package.json
{
  ...
  "scripts": {
    ...
    "docker:up": "docker-compose up",
    "docker:down": "docker-compose down",
    "docker:restart": "docker-compose restart",
    ...
  },
  ...
}
  

1. MySQL service

Documentation: https://hub.docker.com/_/mysql

Create a new Dockerfile for MySQL service at docker/services/mysql/ folder.

In the .env file, we also need to define some variables that will be used in the Dockerfile.

  • DOCKER_APP_NAME
  • DOCKER_MYSQL_PORT
  • DOCKER_MYSQL_PORTS
  • DOCKER_MYSQL_DB_NAME
  • DOCKER_MYSQL_ROOT_PASSWORD
  • DOCKER_MYSQL_PASSWORD
  • DOCKER_MYSQL_PORT

    // Dockerfile
FROM mysql:8
  
    // .env
# Docker
DOCKER_APP_NAME=nodejs-sample
DOCKER_MYSQL_PORT=3307
DOCKER_MYSQL_PORTS=3307:3307
DOCKER_MYSQL_DB_NAME=nodejs-sample
DOCKER_MYSQL_ROOT_PASSWORD=root
DOCKER_MYSQL_USER=root
DOCKER_MYSQL_PASSWORD=root
  
    // docker-compose.yml
...
mysql:
    build:
      context: .
      dockerfile: ./docker/services/mysql/Dockerfile
    restart: always
    container_name: ${DOCKER_APP_NAME}_mysql
    networks:
      - net
    expose:
      - ${DOCKER_MYSQL_PORT}
    ports:
      - "${DOCKER_MYSQL_PORTS}"
    volumes:
      - dbdata:/var/lib/mysql/
    environment:
      - MYSQL_DATABASE=${DOCKER_MYSQL_DB_NAME}
      - MYSQL_ROOT_PASSWORD=${DOCKER_MYSQL_ROOT_PASSWORD}
      - MYSQL_PASSWORD=${DOCKER_MYSQL_PASSWORD}
      - MYSQL_TCP_PORT=${DOCKER_MYSQL_PORT}
      - MYSQL_ROOT_HOST=%
    command: [
      '--character-set-server=utf8mb4',
      '--collation-server=utf8mb4_unicode_ci',
      '--default-authentication-plugin=mysql_native_password'
    ]
  

2. Node service

Documentation: https://hub.docker.com/_/node

Add more some variables in the .env file:

  • DOCKER_APP_PATH
  • DOCKER_NODE_PORTS

Create a new Dockerfile for Node service in the docker/services/node folder.

    // .env
DOCKER_APP_PATH=/var/www/nodejs-sample
DOCKER_NODE_PORTS=5555:5555
  
    // Dockerfile
FROM node:14.14.0-alpine

RUN apk update && apk upgrade && apk add --no-cache \
	bash \
	curl \
	gettext && \
	npm install -g nodemon && \
	npm install -g pm2 && \
	npm rebuild bcrypt --build-from-source
  
    // docker-compose.yml
node:
    restart: on-failure
    depends_on:
      - mysql
    build:
      context: .
      dockerfile: ./docker/services/node/Dockerfile
    container_name: ${DOCKER_APP_NAME}_node
    working_dir: ${DOCKER_APP_PATH}
    networks:
      - net
    ports:
      - "${DOCKER_NODE_PORTS}"
    entrypoint: sh /bin/node/command.sh
    volumes:
      - .:${DOCKER_APP_PATH}
      - ${DOCKER_APP_PATH}/node_modules
      - ./docker/services/node/command-${NODE_ENV}.sh:/bin/node/command.sh
    environment:
      - DB_HOST=${DOCKER_APP_NAME}_mysql
      - DB_USER=${DOCKER_MYSQL_USER}
      - DB_PASSWORD=${DOCKER_MYSQL_PASSWORD}
      - DB_NAME=${DOCKER_MYSQL_DB_NAME}
      - DB_PORT=${DOCKER_MYSQL_PORT}
      - NODE_ENV=${NODE_ENV}
      - PORT=${PORT}
      - TOKEN_SECRET_KEY=${TOKEN_SECRET_KEY}
  

As you can see, we’ve added some new configs for node service

  • entrypoint: sh /bin/node/command.sh It means that the system will run command.sh file in the building process

Where is command.sh from? On the next lines, you can see the config: ./docker/services/node/command-${NODE_ENV}.sh:/bin/node/command.sh

Depends on the running environment, the system will map the appropriate command file. In the docker/services/node folder, we will create two new files.

  • command-development.sh for development env.
  • command-production.sh for production env.

The difference between them is that while command-development.sh will run the application in the development environment with nodemon, command-production.sh will build & run application in the production environment with pm2-runtime.

    // command-development.sh
#!/usr/bin/env bash

yarn install && yarn dev
  
    // command-production.sh
#!/usr/bin/env bash

yarn install && yarn build && cd dist && pm2-runtime start index.js
  

The docker-compose.yml file for both mysql & node services:

    // docker-compose.yml
version: '3'

services:
  mysql:
    build:
      context: .
      dockerfile: ./docker/services/mysql/Dockerfile
    restart: always
    container_name: ${DOCKER_APP_NAME}_mysql
    networks:
      - net
    expose:
      - ${DOCKER_MYSQL_PORT}
    ports:
      - "${DOCKER_MYSQL_PORTS}"
    volumes:
      - dbdata:/var/lib/mysql/
    environment:
      - MYSQL_DATABASE=${DOCKER_MYSQL_DB_NAME}
      - MYSQL_ROOT_PASSWORD=${DOCKER_MYSQL_ROOT_PASSWORD}
      - MYSQL_PASSWORD=${DOCKER_MYSQL_PASSWORD}
      - MYSQL_TCP_PORT=${DOCKER_MYSQL_PORT}
      - MYSQL_ROOT_HOST=%
    command: [
      '--character-set-server=utf8mb4',
      '--collation-server=utf8mb4_unicode_ci',
      '--default-authentication-plugin=mysql_native_password'
    ]
  node:
    restart: on-failure
    depends_on:
      - mysql
    build:
      context: .
      dockerfile: ./docker/services/node/Dockerfile
    container_name: ${DOCKER_APP_NAME}_node
    working_dir: ${DOCKER_APP_PATH}
    networks:
      - net
    ports:
      - "${DOCKER_NODE_PORTS}"
    entrypoint: sh /bin/node/command.sh
    volumes:
      - .:${DOCKER_APP_PATH}
      - ${DOCKER_APP_PATH}/node_modules
      - ./docker/services/node/command-${NODE_ENV}.sh:/bin/node/command.sh
    environment:
      - DB_HOST=${DOCKER_APP_NAME}_mysql
      - DB_USER=${DOCKER_MYSQL_USER}
      - DB_PASSWORD=${DOCKER_MYSQL_PASSWORD}
      - DB_NAME=${DOCKER_MYSQL_DB_NAME}
      - DB_PORT=${DOCKER_MYSQL_PORT}
      - NODE_ENV=${NODE_ENV}
      - PORT=${PORT}
      - TOKEN_SECRET_KEY=${TOKEN_SECRET_KEY}

networks:
  net:
    driver: bridge

volumes:
  dbdata:
    driver: local
  

Running the defined command yarn docker:up to start the Docker. The nodejs application has been built.

nodejs docker 1

Your nodejs app has been working on the port 5555. Open a new terminal tab to see list containers by the command docker container ls

nodejs docker 2

You can see that you’ve had two containers for node & mysql services. Node service has been running at port 5555 & mysql service has been running at port 3307.

Recent Blogs