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)