This documentation covers the successful setup and configuration of load balancing for Docker services using Traefik 2. It demonstrates how to serve a Django API backend and a React frontend through Traefik, with detailed explanations of configurations and implementation steps.
Backend Configuration
Backend 1 Dockerfile
# Backend 1 Dockerfile
FROM python:3.12-alpine
# Prevent Python from writing bytecode and buffer output
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# Set work directory
WORKDIR /app
# Copy project files
COPY . .
# Create virtual environment and install dependencies
RUN python3 -m venv /opt/venv1 && \
    /opt/venv1/bin/pip install --no-cache-dir --upgrade pip && \
    /opt/venv1/bin/pip install --no-cache-dir -r requirements.txt
# Create entrypoint script
RUN echo '#!/bin/sh' > /entrypoint.sh && \
    echo 'set -e' >> /entrypoint.sh && \
    echo '/opt/venv1/bin/python manage.py makemigrations --noinput' >> /entrypoint.sh && \
    echo '/opt/venv1/bin/python manage.py migrate --noinput' >> /entrypoint.sh && \
    echo '/opt/venv1/bin/python manage.py collectstatic --noinput' >> /entrypoint.sh && \
    echo 'exec "$@"' >> /entrypoint.sh && \
    chmod +x /entrypoint.sh
# Entrypoint
ENTRYPOINT ["/entrypoint.sh"]
  
  
  Django Configuration in settings.py
ALLOWED_HOSTS = ["*"]
CORS_ALLOWED_ORIGINS = [
    "http://localhost",
    "http://localhost:80",
]
CORS_ALLOW_METHODS = [
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
]
CORS_ALLOW_HEADERS = [
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
]
Frontend Configuration
Frontend Dockerfile
# Base image
FROM node:20-alpine AS builder
# Set build-time environment variable
ARG REACT_APP_API_URL
ENV REACT_APP_API_URL=${REACT_APP_API_URL:-/}
# Set working directory
WORKDIR /opt/web
# Copy package files and install dependencies
COPY package*.json ./
RUN npm install
# Copy source code
COPY . .
# Build the application
RUN npm run build
# Production stage
FROM nginx:latest
# Copy Nginx configuration template
COPY nginx.conf /etc/nginx/default.conf
# Copy built assets from builder stage
COPY --from=builder /opt/web /usr/share/nginx/html
# Expose port 80
EXPOSE 80
# Default command
CMD ["nginx", "-g", "daemon off;"]
Nginx Configuration
http {
    include       mime.types;
    default_type  application/octet-stream;
    server {
        listen 80;
        server_name localhost;
        location / {
            root /usr/share/nginx/html;
            index index.html;
            try_files $uri /index.html;
        }
        location /static/ {
            root /usr/share/nginx/html;
        }
        location /api/ {
            proxy_pass http://traefik:80;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}
Docker Compose Configuration
  
  
  docker-compose.yml
services:
  traefik:
    image: traefik:latest
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--log.level=DEBUG"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    networks:
      - portfolio-network
  frontend__24673_ui:
    build:
      context: ./frontend-elearning
      dockerfile: Dockerfile
    volumes:
      - static_volume:/usr/share/nginx/html/static
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.frontend__24673_ui.rule=PathPrefix(`/`)"
      - "traefik.http.services.frontend__24673_ui.loadbalancer.server.port=80"
    networks:
      - portfolio-network
    depends_on:
      - backend_24673_1
      - backend_24673_2
  backend_24673_1:
    build: ./backend-1
    command: /opt/venv1/bin/gunicorn -b 0.0.0.0:8000 --worker-class=gevent --worker-connections=1000 --workers=3 elearning.wsgi
    volumes:
      - static_volume:/app/static
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.backend_24673_1.rule=PathPrefix(`/api`)"
      - "traefik.http.services.backen_24673_1.loadbalancer.server.port=8000"
      - "traefik.http.middlewares.backend_24673_1-stripprefix.stripprefix.prefixes=/api"
      - "traefik.http.routers.backend_24673_1.middlewares=backend_24673_1-stripprefix"
    networks:
      - portfolio-network
  backend_24673_2:
    build: ./backend-1
    command: /opt/venv1/bin/gunicorn -b 0.0.0.0:8001 --worker-class=gevent --worker-connections=1000 --workers=3 elearning.wsgi
    volumes:
      - static_volume:/app/static
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.backend_24673_2.rule=PathPrefix(`/api`)"
      - "traefik.http.services.backend_24673_2.loadbalancer.server.port=8001"
      - "traefik.http.middlewares.backend_24673_2-stripprefix.stripprefix.prefixes=/api"
      - "traefik.http.routers.backend_24673_2.middlewares=backend_24673_2-stripprefix"
    networks:
      - portfolio-network
volumes:
  static_volume:
networks:
  portfolio-network:
    driver: bridge
Axios API Configuration
Axios Instance
import axios from 'axios';
const baseurl = process.env.REACT_APP_API_URL || '/';
const AxiosInstance = axios.create({
    baseURL: baseurl,
    timeout: 10000,
    headers: {
        "Content-Type": 'application/json',
        Accept: 'application/json',
    },
});
// Adding an Axios interceptor
AxiosInstance.interceptors.response.use(
    response => response, // Pass through successful responses
    async error => {
        const config = error.config;
        if (!config._retry) {
            config._retry = true; // Mark request as retried
            return AxiosInstance(config); // Retry the request
        }
        return Promise.reject(error); // Reject if retry also fails
    }
);
export default AxiosInstance;
This documentation provides the necessary configuration and setup steps to implement a load-balanced, containerized deployment of a Django-React application with Traefik. Each component is explained for clarity, ensuring reproducibility for similar projects.
 
 
              
 
    
Top comments (0)