DEV Community

Udoh Deborah
Udoh Deborah

Posted on

Running Multiple Containers Using Docker Compose

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

Enter fullscreen mode Exit fullscreen mode

install git

sudo apt install git

Enter fullscreen mode Exit fullscreen mode

Clone git repository to your instance by using

git clone https://github.com/your-username/new-repo

Enter fullscreen mode Exit fullscreen mode

4. Set up the Frontend (from terminal)

cd new-repo

Enter fullscreen mode Exit fullscreen mode
cd frontend

Enter fullscreen mode Exit fullscreen mode

Set up npm and Node.js.

sudo apt install nodejs npm

Enter fullscreen mode Exit fullscreen mode
sudo npm install -g n

Enter fullscreen mode Exit fullscreen mode
sudo n stable

Enter fullscreen mode Exit fullscreen mode

check the version

node -v

Enter fullscreen mode Exit fullscreen mode
npm -v

Enter fullscreen mode Exit fullscreen mode
npm fund

Enter fullscreen mode Exit fullscreen mode

ls (to see files created) or simply

cat package.json 

Enter fullscreen mode Exit fullscreen mode
cat vite.config.ts

Enter fullscreen mode Exit fullscreen mode
nano vite.config.ts

Enter fullscreen mode Exit fullscreen mode

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)
  },
});
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
npm install
Enter fullscreen mode Exit fullscreen mode

-- 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
Enter fullscreen mode Exit fullscreen mode
start docker
Enter fullscreen mode Exit fullscreen mode
sudo systemctl start docker
Enter fullscreen mode Exit fullscreen mode
sudo systemctl enable docker
Enter fullscreen mode Exit fullscreen mode

Create a new docker file in the frontend folder

nano dockerfile
Enter fullscreen mode Exit fullscreen mode

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"]
Enter fullscreen mode Exit fullscreen mode

Build Docker-file

sudo docker build -t react-frontend
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
nano dockerfile
Enter fullscreen mode Exit fullscreen mode

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"]
Enter fullscreen mode Exit fullscreen mode

Create docker ignore file

nano docker ignore
Enter fullscreen mode Exit fullscreen mode

then paste this

pycache
*.pyc
*.pyo
.mypy_cache
.pytest_cache
.venv
.env
.git
Enter fullscreen mode Exit fullscreen mode
  • Use docker build to create the Docker image.
sudo docker build -t
Enter fullscreen mode Exit fullscreen mode

7. Make a file called docker-compose.yml using Docker Compose:

Nano docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

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:
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • 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)