Introduction

Docker has transformed the landscape of application deployment by empowering developers to encapsulate applications along with their dependencies into portable containers. In this article, we’ll explore how to dockerize a NodeJS application with MySQL, leveraging the power of Docker and Docker Compose. Containerizing your Node.js application offers seamless deployment, enhanced portability, scalability, and version control benefits.

The YouTube Channels in both English (En) and French (Fr) are now accessible, feel free to subscribe by clicking here.

What is Docker Compose?

Docker Compose stands as an indispensable tool. This extension of Docker offers the ability to define and manage multi-container applications using simple configuration files written in YAML. Instead of manually managing each container individually, Docker Compose allows the declaration of services, networks, and volumes within a single file, significantly simplifying the deployment process.

Why use Docker Compose?

Docker Compose presents several significant advantages in the deployment and management of multi-container applications. Here are some of these benefits:

  • Simplicity of Configuration: Docker Compose uses simple YAML configuration files to define the structure of applications. This approach makes the configuration and management of services, networks, and volumes easier.
  • Facilitated Orchestration: With Docker Compose, it becomes easy to declare and coordinate multiple services and containers within a single application. This simplifies the orchestration of interconnected components.
  • Rapid Deployment: Using a single configuration file, Docker Compose provides an efficient method to quickly deploy applications with all their necessary components. This speeds up the development and testing process.
  • Environment Isolation: Docker Compose configuration files can be tailored for different environments such as development, production, or testing. This allows effective isolation of settings and configurations specific to each phase of an application’s lifecycle.

To follow this guide, ensure you have the following on your machine:

  • Docker installed and running on your machine, this guide can help.
  • NodeJS, any of the recent versions will do.
  • NPM normally comes with the installation of NodeJS.

Create a NodeJS Application

Before proceeding, let’s create a basic NodeJS App with the latest LTS release at the time of writing, which is version v18.x.x.

This article is about Docker Compose, so we suggest you follow along using our sample project available on GitHub.

You can quickly determine the following dependencies that come packaged in the project:

  • Express: The web framework to easily build RESTful APIs.
  • Sequelize: The Object Relational Mapping (ORM) performs database queries easily.
  • MySQL2: The MySQL driver used by Sequelize to interact with a MySQL database.

The db.config.js file holds the database configurations the project used via the Sequelize package, here’s what it looks like:

/**
 * Database configuration.
 */
module.exports = {
    DIALECT: 'mysql',
    HOST: process.env.DB_HOST,
    PORT: process.env.DB_PORT,
    DB: process.env.DB_NAME,
    USERNAME: process.env.DB_USERNAME,
    PASSWORD: process.env.DB_PASSWORD,
};

For our demo, the port in use is 3000 and we have implemented the CRUD operations for a basic User model as well as a Ping endpoint, we won’t go deeper on that since it’s out of scope and you can follow the next sections of this guide with an existing NodeJS project too.

Create Docker Image for NodeJS Application

The Dockerfile should be provided to build an image of the NodeJS Application, it contains the following lines:

# Use a base image with NodeJS 18
FROM node:18

# Install all the dependencies in the container using the package.json file
COPY package.json .
RUN npm install

# Copy the remaining project files to the container
COPY . .

# Expose the application port
EXPOSE 3000

# Run the App
CMD npm start

It’s straightforward, the Dockerfile uses an image based on NodeJS 18, installs the dependencies into the container, copies the project files, exposes the port the App is running on, and then provides the CMD (npm start) which is the command to run when the container starts.

By building your image with the command docker build ., a successful output should be similar to the next image:

Dockerfile for NodeJS Application
Build NodeJS Docker image

As of now, we have the NodeJS App image and we’ll use the official MySQL Docker image available in the Docker Hub. We can manually spin up both components and link them together by using the database credentials to run the App, but to make the process easier we’ll link their deployments together by using Docker Compose in the next section.

Docker Compose NodeJS and MySQL

Docker Compose simplifies the orchestration of multi-container applications. To get started, create a file named docker-compose.yml in your project directory and incorporate the provided configuration:

version: '3.7'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 3000:3000
    depends_on:
      mysqldb:
        condition: service_healthy
    environment:
      - DB_HOST=mysqldb
      - DB_PORT=3306
      - DB_NAME=${MYSQL_DATABASE}
      - DB_USERNAME=root
      - DB_PASSWORD=${MYSQL_PASSWORD}
    networks:
      - nodejs-mysql-network
  mysqldb:
    image: mysql:8.0.33
    ports:
      - 3306:3306
    environment:
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - nodejs-mysql-network
    healthcheck:
      test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
      retries: 10
      interval: 3s
      timeout: 30s
volumes:
  mysql-data:
networks:
  nodejs-mysql-network:
    name: nodejs-mysql-network

Here’s what happens when Docker Compose processes these configurations:

  • This Docker Compose configuration defines two services: app for the NodeJS Application and mysqldb for the MySQL database.
  • The app service builds the image based on the Dockerfile in the project’s root directory.
  • The mysqldb service uses the official MySQL image and sets the environment variables for the database configuration.
  • The depends_on attribute ensures that the NodeJS application starts after the MySQL database to guarantee dependency ordering.
  • Finally, the healthcheck makes sure the MySQL service is ready to accept connections before running the App.

For the App to connect itself to the MySQL database, as an enhanced security measure, we provided the database credentials as environment variables to the MySQL services’ environment attributes so these are hidden from the project source code:

  • MYSQL_DATABASE: The database name.
  • MYSQL_PASSWORD: The database root’s password, we use the root user account for simplicity only.

The environment attributes present in the app service are provided as environment variables to the App container at run time, we are talking about:

  • DB_HOST: Since both services are in the same network, the database instance is addressable via the mysqldb service name.
  • DB_PORT: The database port.
  • DB_NAME: the database name.
  • DB_USERNAME: The username to access the DB with.
  • DB_PASSWORD: The password to access the DB with.

NodeJS automatically picks them up and makes these database details available in the process.env object used by the db.config.js file that we clarified on the top.

Run the Dockerized NodeJS Application With MySQL

To run the App via Docker Compose, open a terminal, jump to the project’s root directory, and execute the following command in which we provide the environment variables directly:

MYSQL_DATABASE=mydatabase MYSQL_PASSWORD=rootpassword docker compose up

In case you would like to provide the environment variables from a hidden .env file, feel free to create it from the .env.sample file and put it close to the docker-compose.yml file within the project. In case these files are in different locations, you must use the env_file field in the mysqldb service to specify the folder to access the .env file.

This being done, the command to run will change a bit to the following:

docker compose up

Docker Compose will build the NodeJS App and MySQL images, create the containers, create the network, and start them all. You’ll see logs from both the application and the database. To stop the containers, press Ctrl+C.

Using Docker Desktop enables you to view a nice summary of your Docker state in which we can see our running containers as illustrated below:

Docker Compose NodeJS MySQL Running
Running containers on Docker Desktop

The complete source code of the project is available on GitHub.

Open POSTMAN and create a POST request to the URL localhost:3000/users with a random user object to be persisted in the DB:

Docker Compose NodeJS MySQL: Create User API
Test API: create a user

Let’s list all users which includes the one we just created:

Docker Compose NodeJS MySQL: List Users API
Test API: list all users

Stop Docker Compose Services

To stop all the running containers, run:

docker compose down

Here’s the exact command to stop and remove everything created by Docker Compose, talking about the containers, images, and networks:

docker compose down --rmi all

Other Docker Compose Examples

If you are interested in related content, take a look at the following which explains how to Quickly Dockerizing NodeJS Application using docker init command:

Do you want to apply the same with a Spring Boot Application? Read this article titled Dockerize Spring Boot and MySQL with Docker Compose:

———————

We have just started our journey to build a network of professionals to grow even more our free knowledge-sharing community that’ll give you a chance to learn interesting things about topics like cloud computing, software development, and software architectures while keeping the door open to more opportunities.

Does this speak to you? If YES, feel free to Join our Discord Server to stay in touch with the community and be part of independently organized events.

———————

Conclusion

By following the steps outlined in this guide, we were able to package a NodeJS application and MySQL database into separate containers and deploy them as a cohesive application stack using Docker Compose. With Docker, you can achieve consistent application execution across different environments, easily scale your application, and simplify version control. Docker Compose streamlines the management of multi-container applications, allowing you to define, configure, and deploy complex systems effortlessly.

Thanks for reading this article. Like, recommend, and share if you enjoyed it. Follow us on FacebookTwitter, and LinkedIn for more content.

author-avatar

About Orleando Dassi

I'm a Solutions Architect with 10 years of experience who is constantly learning while impacting the community by producing technical articles/videos, building projects, and conducting tech mentoring/coaching sessions. What describes me the most is my flexibility. Follow me on Twitter and LinkedIn.