Run Multi-Container Application using Docker Compose


Objectives

Learn how to use Docker Compose to run multiple containers at once.

Background

Follow up from the previous Docker post, we have successfully created a Docker image and add volumes for our Node.js application. However, we have to run the container manually every time we want to use it. In this post, we will learn how to use Docker Compose to run multiple containers at once.

Multi-Containers

Before we start, we need to know how to seperate our application to multiple containers. In this example, we will seperate our application into two containers: one for the Node.js application and one for the MySQL database.

Container Networking

In order to connect the Node.js application to the MySQL database, we need to create a network for the containers to communicate with each other. We can create a network using the following command: docker network create todo-app

Start a MySQL container and attach it to the network.

docker run -d \
  --network todo-app --network-alias mysql \
  -v todo-mysql-data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=secret \
  -e MYSQL_DATABASE=todos \
  mysql:8.0
          

Start your Node.js container and attach it to the network.

docker run -dp 127.0.0.1:3000:3000 \
  -w /app -v "$(pwd):/app" \
  --network todo-app \
  -e MYSQL_HOST=mysql \
  -e MYSQL_USER=root \
  -e MYSQL_PASSWORD=secret \
  -e MYSQL_DB=todos \
  node:18-alpine \
  sh -c "yarn install && yarn run dev"
          

If you look at the logs of the Node.js container, you should see a message similar to this:

$ nodemon src/index.js
  [nodemon] 2.0.20
  [nodemon] to restart at any time, enter `rs`
  [nodemon] watching path(s): *.*
  [nodemon] watching extensions: js,mjs,json
  [nodemon] starting `node src/index.js`
  Waiting for mysql:3306.
  Connected!
  Connected to mysql db at host mysql
  Listening on port 3000
          

This means that the Node.js application has successfully connected to the MySQL database.

You can add todo items by visiting http://localhost:3000 in your web browser.

To verify the connection, you can connect to the mysql database and prove that the items are being written to the database.

In the mysql shell, you should see something like this:

mysql> select * from todo_items;
+--------------------------------------+---------------------------+-----------+
| id | name | completed |
+--------------------------------------+---------------------------+-----------+
| e7e9ca55-be7e-416f-b334-7ac9225c3667 | Hi! | 0 | |
818bcdf0-f409-4199-b08a-7f5d22c1f941 | This is Sung-Jie | 0 | |
d8c47336-812f-4dae-a960-3d10bff9c950 | I'm a software engineer ? | 0 |
+--------------------------------------+---------------------------+-----------+
3 rows in set (0.00 sec)
          

Using Docker Compose

In the previous section, we have successfully created a network and connected our Node.js application to the MySQL database. However, we have to run the containers manually every time we want to use it. In this section, we will learn how to use Docker Compose to run multiple containers at once.

Install Docker Compose

If you installed Docker Desktop for Windows, Mac, or Linux you already have Docker Compose!

Create a Docker Compose file

Create a file named docker-compose.yml in your project directory and paste the following:

This file defines two services: app and mysql.

The app service uses the node:18-alpine image. It binds the container and the host machine to the exposed port, 3000. It also mounts the current directory on the host to the /app directory in the container, allowing you to modify the code without having to rebuild the image.

The mysql service uses the mysql:8.0 image. It also creates a named volume, todo-mysql-data, which will be used to persist the database data.

Notice that we need to define the volume mapping. This is because when we ran the container with docker run, the named volume was created automatically. However, that doesn’t happen when running with Compose. We need to define the volume in the top-level volumes: section and then specify the mountpoint in the service config.

Start the application

Run the following command to start the application in the background:

docker-compose up -d
          

You should see the following output:

[+] Running 3/0
 βœ” Network app_default    Created                                                                                                                                                                             0.0s 
 βœ” Container app-app-1    Created                                                                                                                                                                             0.0s 
 βœ” Container app-mysql-1  Created   
          

At this point, the application should be running. You can verify by visiting http://localhost:3000 in your web browser.

You can also see the app stack in Docker Desktop. Click on the app stack and you should see something like this:

Hooray! You have successfully deployed a Node.js application with a MySQL database using Docker Compose (Just only a single command! )πŸŽ‰

Conclusion

We have successfully deployed an multi-containers application using Docker Compose. Isn't it easy? 😎 To learn more about Docker Compose, you can visit the official documentation. If you have any questions, feel free to leave a comment below. Hope you enjoy this article and see you next time!

Resources