This tutorial gives you a step-by-step guide on how to run a multi-container web application using docker-compose. The program is composed of distinct services for the database (PostgreSQL), frontend (React), and backend (Python). Nginx serves as a security and efficiency reverse proxy.
**Comprehending the Elements:
**
Backend: Built using Python (uvicorn), served on port 8000.
Frontend: Built with React, served on port 5173.
Database: PostgreSQL, setup with the database name and credentials.
Traefik: Reverse proxy for traffic management and request routing to the
relevant service
Requirements
:
A cloud instance having Docker installed, such as an AWS EC2.
The instance has npm and node.js installed.
An account on Docker Hub.
A unique domain name.
Steps.
1. Launch an Instance with the following requirement
- AMI (Ubuntu)
- Instance type (T3 medium)
- Create new key pair
- Security group (allow ssh, http, https from anywhere)
- Storage size (1x 30)
- Launch Instance
2. Clone the repository
https://github.com/hngprojects/devops-stage-2
clone repository on link above to your git by forking it.
Create a new repository name e.g (new-repo)
3.Connect your instance to VSCode or Instance connect
Update your instance
sudo apt update
install git
sudo apt install git
Clone git repository to your instance by using
git clone https://github.com/your-username/new-repo
4. Set up the Frontend (from terminal)
cd new-repo
cd frontend
Set up npm and Node.js.
sudo apt install nodejs npm
sudo npm install -g n
sudo n stable
check the version
node -v
npm -v
npm fund
ls (to see files created) or simply
cat package.json
cat vite.config.ts
nano vite.config.ts
NB: each of these commands will allow you see what the files contains, and "nano" command allow you edit the files.
Paste this in the vite.config.ts file
export default defineConfig({
plugins: [react(), TanStackRouterVite()],
server: {
host: '0.0.0.0', // Listen on all interfaces
port: 5173, // Use port 5173 (can be changed if needed)
},
});
The code above Modified the vite.config.ts file so that port 5173 is accessible.
Execute npm run dev and npm install.
npm run dev
npm install
-- Configure the security group for your instance to accept incoming traffic on port 5173. Using port 5173 and your instance's public IP address, access the frontend.
5. Make the Frontend Containerized:
- In the frontend directory, create a Dockerfile. Build the React application, expose port 80, install dependencies, use the official Node.js image, and copy the application code.
- Use docker build to create the Docker image.
Install Docker
sudo apt install docker
start docker
sudo systemctl start docker
sudo systemctl enable docker
Create a new docker file in the frontend folder
nano dockerfile
then paste this
Use an official Node.js image as the base
FROM node:20
Set the working directory
WORKDIR /app
Copy package.json and install dependencies
COPY package*.json ./
RUN npm install
Copy the rest of the application files
COPY . .
Build the React app
RUN npm run build
Expose port 80 and start the application
EXPOSE 80
CMD ["npx", "serve", "-s", "build"]
Build Docker-file
sudo docker build -t react-frontend
6. Build a Backend Container:
In the backend directory, make a Dockerfile.
Install Poetry and its dependencies, use the official Python image
copy the application code, configure environment variables, and open port 8000.
Make a docker-ignore file to remove files from the image that aren't needed.
cd backend
nano dockerfile
Then paste this
Use the official Python image with the desired version
FROM python:3.10-slim
Set the working directory in the container
WORKDIR /app
Install Poetry
RUN apt-get update && \
apt-get install -y curl && \
curl -sSL https://install.python-poetry.org | python3 - && \
apt-get clean
Add Poetry to PATH
ENV PATH="/root/.local/bin:$PATH"
Copy pyproject.toml and poetry.lock to the container
COPY pyproject.toml poetry.lock* /app/
Install dependencies using Poetry
RUN poetry install --no-root --no-interaction --no-ansi
# Copy the rest of the application code to the container
COPY . /app
# Ensure the application directory is in the Python path
ENV PYTHONPATH=/app
# Run the database prestart script
RUN poetry run bash ./prestart.sh
# Expose the application port
EXPOSE 8000
# Command to run the backend server
CMD ["poetry", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Create docker ignore file
nano docker ignore
then paste this
pycache
*.pyc
*.pyo
.mypy_cache
.pytest_cache
.venv
.env
.git
- Use docker build to create the Docker image.
sudo docker build -t
7. Make a file called docker-compose.yml using Docker Compose:
Nano docker-compose.yml
then paste this
version: '3.8'
services:
traefik:
image: traefik:v2.9
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
ports:
- "80:80" # Port 80 for web traffic
- "8080:8080" # Traefik dashboard port
volumes:
- "/var/run/docker.sock:/var/run/docker.sock" # Docker socket for Traefik to detect services
networks:
- web
db:
image: postgres:latest
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: mydatabase
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- web
backend:
build:
context: ./backend
labels:
- "traefik.http.routers.backend.rule=PathPrefix(/api)" # Proxy requests with /api to backend
- "traefik.http.services.backend.loadbalancer.server.port=8000"
environment:
DATABASE_URL: "postgresql://user:password@db:5432/mydatabase"
networks:
- web
frontend:
build:
context: ./frontend
labels:
- "traefik.http.routers.frontend.rule=Host(yourdomain.com)" # Main domain goes to frontend
- "traefik.http.services.frontend.loadbalancer.server.port=80"
networks:
- web
volumes:
pgdata:
networks:
web:
This is an explanation of everything specified in the file above...
- Specify the frontend, backend, database, and Traefik services.
- For routing requests, use Traefik as a reverse proxy with labels.
- Set environment variables to configure the database service's connection details.
- Configure the database URL's environment variables in the backend service.
- To define paths for producing frontend and backend images, use the build context.
- Establish networks for service-to-service communication.
8. Configure Your Domain Name:
- Make a subdomain using a free DNS provider like, (www.freedns.afraid) Set the subdomain's address to the public IP ipv4 address of your instance.
- For the frontend service, update the docker-compose.yml file with your domain name.
9. Launch the program
- To create and start all services in detached mode, run
docker-compose up -d --build
- set-up the nginx as proxy manager
Advantages of Docker Compose usage:
- Simplified Multi-Container Management
- Utilizes a single configuration file to define and operate all services.
- Scalability
- Adding or removing containers as needed is simple.
- Reproducibility
- Guarantees uniform environments for testing, production, and development.
With the help of a reverse proxy and Docker containers, this method offers a strong basis for launching web applications with improved security and speed.
Top comments (0)