Docker Compose is a powerful Docker tool for developing and running multi-container Dockerized applications. Docker is an open-source platform for developing and running applications in an isolated environment known as a container. A container is a standalone executable package that contains the libraries, source code, and dependencies needed to run an application.
With Docker Compose, you create a docker-compose.yml
file to run all the containers in your project as a single application. The file will contain all the container configurations such as volumes, container names, and port mappings. It also specifies the Dockerfiles for building the Docker images.
In this tutorial, we will create a backend Express server using Node.js. We will then create a front-end application using React.js and connect it to the backend server.
We will then use Docker Compose to deploy the two applications. We will also access them on the web browser. Let's start working on our applications!
Prerequisites
This tutorial assumes you are familiar with the following:
To implement this tutorial, you will need the following already installed on your computer:
- VS Code code editor.
- Node.js framework.
- Docker Desktop.
Creating the Backend Express Server using Node.js
To create the Express server using Node.js, follow the steps illustrated below:
Step 1: Create a working directory named docker-compose-app
and open it with VS Code.
In the working directory, create a new directory/folder named node
and cd
into the node
directory. This directory will contain the libraries, source code, and dependencies needed to create the application.
Step 2: Initialize the application using the following code:
npm init --y
The command will initialize the application and generate the package.json
file. The next step is to install all the dependencies for the application as follows:
npm i -g nodemon
npm i express
After running the command in your terminal, it will install express
and nodemon
. We will use the installed express
package to create the server.
We will use nodemon
to watch and monitor the backend files. Nodemon will detect changes in the backend files and automatically restart the server. It will prevent us from restarting the backend server manually after making changes to the application.
Step 3: Next, open the package.json
file and the following npm
script for nodemon
to start working:
"dev": "nodemon -L app.js"
Step 4: In the node
directory, create a new file named server.js
. This file will have the logic for creating our backend server.
Step 5: Copy and paste the following code snippet in the server.js
file:
const express = require('express')
const cors = require('cors')
const app = express()
app.use(cors())
app.get('/', (req, res) => {
res.json([
{
"id":"1",
"title":"Album Review: When we all Fall asleep where do we go?"
},
{
"id":"2",
"title":"Book Review: How can we escape this labyrinth of suffering?"
},
{
"id":"3",
"title":"Documentary Review: How can we escape the rat race?"
}
])
})
app.listen(4000, () => {
console.log('connected on port 4000')
})
The code snippet above will create a get
route. The frontend application will get the review titles from this route.
Running the Backend Express Server
To run the Backend Express Server application, run the following npm
command in your terminal:
npm run dev
The npm
command will start and run our server on http://localhost:4000/
as shown in the image below:
The image shows the backend is running and displaying the reviews. Let's start working on our frontend React.js application.
Creating the frontend React.js application
To create the frontend React.js application, follow the steps illustrated below:
Step 1: In the docker-compose-app
working directory, run the following npx
command to create a boilerplate for a React.js application
npx create-react-app react
The npx
command above will create a new directory named react
in the docker-compose-app
working directory. Now, cd
into the react
directory.
Step 2: Navigate inside the react
directory, and open the src
directory.
Step 3: While in the src
directory, open the App.js
file and add the following code snippet:
import { useEffect, useState } from 'react'
import './App.css';
function App() {
const [reviews, setReviews] = useState([])
useEffect(() => {
fetch('http://localhost:4000/')
.then(res => res.json())
.then(data => setReviews(data))
}, [])
return (
<div className="App">
<header className="App-header">
<h1>all Reviews</h1>
{reviews && reviews.map(blog => (
<div key={blog.id}>{blog.title}</div>
))}
</header>
</div>
);
}
export default App;
The added code snippet will create a frontend react application. It will fetch
the review titles from this backend get
route. Our backend application is running on http://localhost:4000/
. The next step is to run the frontend React.js application as follows:
Running the frontend React.js application
To run the frontend React.js application, execute the following command in your terminal:
npm start
The npm
command will start and run the frontend React.js application on http://localhost:3000/
as shown in the image below:
The image shows the frontend React.js application running and fetching the review titles from the backend. Let's create the Dockerfiles for the two applications. Docker Compose will use the Dockerfiles to build and run the containers.
Create the Dockerfile for the Backend Express Server
The Dockerfile will contain all the commands for building the Docker image for the backend server application. While in the node
directory/folder, create a new file named Dockerfile
. In the created Dockerfile
add the following commands to create a Docker image.
# It uses node:18-alpine as the base image for the Node.js application
FROM node:18-alpine
# It installs the nodemon package globally for monitoring and watching the backend Express server
RUN npm install -g nodemon
# Creating the working directory named `app`
WORKDIR /app
# Copying all the tools and dependencies in the package.json file to the working directory `app`
COPY package.json .
#Installing all the tools and dependencies in the container
RUN npm install
#Copying all the application source code and files to the working directory `app`
COPY . .
#Exposing the container to run on this port 4000
EXPOSE 4000
#Command to start the Docker container for the backed server application
CMD ["npm", "run", "dev"]
The next step is to create a Dockerfile
for the frontend React.js application.
Create the Dockerfile for the frontend React.js application
In the react
directory/folder, create a new file named Dockerfile
. In the created Dockerfile
add the following commands to create a Docker image.
# It uses node:18-alpine as the base image for the frontend React.js application
FROM node:18-alpine
# Creating the working directory named `app`
WORKDIR /app
# Copying all the tools and dependencies in the package.json file to the working directory `app`
COPY package.json .
#Installing all the tools and dependencies in the container
RUN npm install
#Copying all the application source code and files to the working directory `app`
COPY . .
#Exposing the container to run on this port 3000
EXPOSE 3000
#Command to start the Docker container for the frontend React.js application
CMD ["npm", "start"]
Now that we have both Dockerfiles, the next step is to create a docker-compose.yml
file which contains all the containers' configurations.
Create a docker-compose.yml
file
This file will enable us to run and deploy the two containers using Docker Compose. We will add the containers as a service
.
The docker-compose.yml
file will have two services. Using the created file, we will spin up the two containers. It will run them as a single application.
To create the two Docker Compose services, follow the steps below:
Step 1: In the docker-compose-app
working directory, create a new file docker-compose.yml
file.
Step 2: Next, add the first service named node
using the following code snippet:
# Version of Docker-compose
version: '3.9'
services:
# Add the node-js service
node:
# Location to the node.js dockerfile
build:
context: ./node
# Name of the dockerfile
dockerfile: Dockerfile
container_name: node-container
ports:
# Host port:Container port
- '4000:4000'
volumes:
# Bind-mounts configuration
- ./node:/app
# Ignoring any changes made in the "node_modules" folder
- ./app/node_modules
The code above will create a service named node
. It also shows the location of the Node.js Dockerfile.
It shows the container name as node-container
and port mapping. The node-container
will run on port 4000
.
We also add volume for this service. This volume will map the local project folder to the working directory in the container. Any changes made in the local project folder will be updated automatically in the container. It saves time rebuilding the whole container from scratch when change the files in the local project folder.
Step 3: Next, let's add the service named react
for the React.js application container.
After the node
service, add the following code snippet:
react:
# Location to the react.js dockerfile
build:
context: ./react
# Name of the dockerfile
dockerfile: Dockerfile
container_name: react-container
ports:
# Host port:Container port
- '3000:3000'
stdin_open: true
The code above will create a service named react
. It also shows the location of the React.js Dockerfile.
It shows the container name as react-container
and port mapping. The react-container
will run on port 3000
.
If you follow the steps above correctly, the final docker-compose.yml
will be as shown below:
# Version of Docker-compose
version: '3.9'
services:
# Add the node-js service
node:
# Location to the node.js dockerfile
build:
context: ./node
# Name of the dockerfile
dockerfile: Dockerfile
container_name: node-container
ports:
# Host port:Container port
- '4000:4000'
volumes:
# Bind-mounts configuration
- ./node:/app
# Ignoring any changes made in "node_modules" folder
- ./app/node_modules
react:
# Location to the react.js dockerfile
build:
context: ./react
# Name of the dockerfile
dockerfile: Dockerfile
container_name: react-container
ports:
# Host port:Container port
- '3000:3000'
stdin_open: true
Now that we have added all our services to the file, the next step is to build and run the two containers.
Running the two Containers using Docker Compose
To build and run the two Containers using Docker Compose, execute the following command in your terminal:
docker-compose up --build
The command will run the two containers and display the following output in your terminal:
The output shows both the node-container
and react-container
are running. We can access the node-container
on http://localhost:4000/
and react-container
on http://localhost:3000/
. The images below show the deployed containers running in the web browser:
Conclusion
In this tutorial, you have learned how to deploy a multi-container React.js and Node.js Application using Docker Compose. We created a backend Express server using Node.js. We then created a front-end application using React.js. After completing these steps, we created Dockerfiles for these two applications. We also created a docker-compose.yml
file.
We used the docker-compose.yml
to build and run the two application containers. We successfully deployed the Docker containers using Docker Compose. We accessed them on the web browser. You can download the complete source code for this tutorial here. Happy Deployment!
Top comments (11)
A good article.
I feel that it would've been a great article if it had also encompassed use environment variables within this setup as it can be a bit of a gotcha.
Yeah- that's a great idea.
This is an amazing write-up. Very easy to consume
Thanks for reading.
Thank you for this informative and helpful blog post. I learned a lot from your clear and detailed explanation of how to deploy a multi-container ReactJS and NodeJS application with Docker Compose.
Thanks for reading.
Why not use nginx as a proxy when building React.js Docker?
Nice post, thank you.
this is interesting
Thanks for reading.
What if I want to connect front end and backend through docker network, How Can I use IP a adress in axios