Dockerize your frontend + Backend application
How to dockerize your frontend + Backend application with Dockerfile(s) and Docker Compose very easily !
Why am I here?
- I want to dockerize my application easily
- I want to understand basics of docker-compose.yml files
- I want to use NGINX because I like NGINX
Why would I like to dockerize my application
There are thousands of good reasons. I'm going to name three so as not to seem too lazy. Dockerizing your application make it easier to share the same environment between developers. Using Docker create many possibilities for monitoring your docker containers (where your application is running), using prometheus and grafana for example. Deploying dockerised application on AWS Beanstalk is fun, like in my other blog post 🙃.
Set up a simple project using Solid and Express
** Avoid this section if you already have a project, just take note of our project folders structure for easily following **
To keep this simple, we will use a basic Solid application (No React because too much React in this world), with a simple Express for the backend part.
This project can be cloned on GitHub or set up with a README.md file if you want to do it yourself.
Docker Compose and Dockerfiles
I'll be quick, Compose allows you to split our backend and our frontend into two services, both services can communicate with each other and are built from their own Dockerfile, running the docker-compose.yml file will create images for each Dockerfile used, very cool.
# Tree - essentials files
📦You're app
┣ 📂backend
┣ ┣ 📂node_modules
┃ ┣ 🐋Dockerfile
┃ ┣ 📜index.js
┃ ┣ 📜package.json
┣ 📂frontend
┣ ┣ 📂node_modules
┃ ┣ 📂src
┃ ┃ ┣ 📜App.jsx
┃ ┃ ┣ 📜index.css
┃ ┃ ┣ 📜index.jsx
┃ ┣ 🐋Dockerfile
┃ ┣ 📜index.html
┃ ┣ 📜package.json
┗ 🐳docker-compose.yml
The frontend Dockerfile is composed of two builds stage, the first one for installing the Solid application in a frontend folder and the second one for serving the built application in a NGINX web server.
FROM node:alpine
# Create the folder structure for the Solid application
RUN mkdir -p /usr/src/app
RUN mkdir -p /usr/src/app/frontend
# Set the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile
WORKDIR /usr/src/app/frontend
# Copy the package.json && package-lock.json (if it exist) to know what dependencies need to be installed
COPY package*.json ./
RUN npm install
# Copy the project from your machine to the WORKDIR
COPY . .
# Build the application, the built application appear in a new directory "dist"
RUN npm run build
# Official NGINX image for serving our frontend
FROM nginx:latest
# Copy our built application in the nginx location
COPY --from=0 /usr/src/app/frontend/dist /usr/share/nginx/html
/usr/share/nginx/html is the compiled-in default location for each server's document root, in the absence of one being specified. A colleague would yell at you for not using the /var/www/html location, and he would be absolutely right, luckily no one will yell on you today, I hope.
The backend Dockerfile is installing the Express application in a backend folder and starting it on the port 5000.
FROM node:alpine
# Create the folder structure for the Express application
RUN mkdir -p /usr/src/app
RUN mkdir -p /usr/src/app/backend
# Set the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile
WORKDIR /usr/src/app/backend
# Copy the package.json && package-lock.json (if it exist) to know what dependencies need to be installed
COPY package*.json ./
# Install the dependencies
RUN npm install
# Copy the project from your machine to the WORKDIR
COPY . .
# Start Express
RUN node index.js
The docker-compose.yml is defining and running our multi-container Docker applications :
version: '2'
services:
frontend:
build: ./frontend
ports:
- '80:80'
container_name: frontend-docker
restart: always
links:
- backend
backend:
build: ./backend
ports:
- '5000:5000'
container_name: backend-docker
restart: always
- The port 80:80 make reference to the default NGINX port used to listen all incoming connections to the web server. NGINX serve our built Solid application on this port, because port 80 is the default port the application will be visible at http://localhost.
- The service "frontend" is "linked" to the backend service.
Like depends_on, Links determine the order of service startup, the frontend service will be started after the backend one !
Finnaly, run your docker-compose.yml in the root folder :
docker-compose up -d
At the end, your Solid application should be visible at http://localhost and your Express at http://localhost:5000. You could add a third service for your database for example.