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:
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 andmysqldb
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:
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:
Let’s list all users which includes the one we just created:
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 Facebook, Twitter, and LinkedIn for more content.