Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# ============================================================
# .env — Environment variables for docker-compose
# Used by all services: core, celeryworker, flower, db, broker
# ============================================================

# ------------------------------------------------------------
# Python / General
# ------------------------------------------------------------
PYTHONPATH=.
LOGS_LEVEL=DEBUG
ENVIRONMENT=local

# ------------------------------------------------------------
# Django
# ------------------------------------------------------------
DJANGO_SECRET_KEY=s8s6s5t2nu00
DJANGO_DEBUG=True
DJANGO_ADMIN_URL=admin/
DJANGO_ALLOWED_HOSTS=*
DJANGO_SETTINGS_MODULE=core.settings.local

# ------------------------------------------------------------
# PostgreSQL Database
# ------------------------------------------------------------
DB_ENGINE=django.db.backends.postgresql_psycopg2
DB_NAME=postgres
DB_USER=postgres
DB_PASSWORD=qwerty123
DB_HOST=db
DB_PORT=5432

# PostgreSQL image environment variables (used by postgres container)
POSTGRES_DB=postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=qwerty123

# ------------------------------------------------------------
# Celery
# ------------------------------------------------------------
CELERY_RESULT_BACKEND=django-db
CELERY_BROKER_URL=amqp://admin:admin@broker:5672/vhost
CELERY_WORKER_CONCURRENCY=1
CELERY_WORKER_PREFETCH_MULTIPLIER=1
CELERY_WORKER_MAX_TASKS_PER_CHILD=10

# ------------------------------------------------------------
# RabbitMQ Broker
# ------------------------------------------------------------
RABBITMQ_DEFAULT_USER=admin
RABBITMQ_DEFAULT_PASS=admin
RABBITMQ_DEFAULT_VHOST=vhost
126 changes: 91 additions & 35 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,44 +1,100 @@
FROM python:3.9.13
# ============================================================
# Dockerfile for the Django/Celery core service
# Supports: local, development, production environments
# Usage:
# Local: docker build --build-arg ENVIRONMENT=local -t core .
# Production: docker build --build-arg ENVIRONMENT=production -t core .
# ============================================================

ARG ENVIRONMENT=default
# Base image: Python 3.11 slim (LTS-aligned, amd64 compatible)
FROM python:3.11-slim

ENV PYTHONUNBUFFERED 1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=1
# ------------------------------------------------------------
# Build argument to switch between environments
# Values: local | development | production (default: local)
# ------------------------------------------------------------
ARG ENVIRONMENT=local

# ------------------------------------------------------------
# Environment variables for Python and pip behaviour
# ------------------------------------------------------------
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
ENVIRONMENT=${ENVIRONMENT}

# ------------------------------------------------------------
# Set working directory
# ------------------------------------------------------------
WORKDIR /app

COPY requirements/*.txt /tmp/requirements/

RUN set -x \
&& buildDeps=" \
build-essential \
" \
&& runDeps=" \
git \
" \
&& localDeps=" \
telnet \
" \
&& apt-get update \
&& apt-get install -y --no-install-recommends $buildDeps \
&& apt-get install -y --no-install-recommends $runDeps \
&& if [ $ENVIRONMENT = local ] || [ $ENVIRONMENT = development ]; then \
apt-get install -y --no-install-recommends $localDeps \
# Install python dev dependencies
&& pip install -r /tmp/requirements/local.txt; \
else \
# Install python production dependencies
pip install -r /tmp/requirements/production.txt; \
# other environment to local remove the build dependencies
apt-get remove -y $buildDeps; \
fi \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
# clean tmp dir
&& rm -rf /tmp/*
# ------------------------------------------------------------
# Install system dependencies
# - build-essential : needed to compile psycopg2 C extensions
# - libpq-dev : PostgreSQL client headers for psycopg2
# - git : required by some pip packages
# - telnet : useful for local debugging only
# In production, build-time deps are removed after pip install
# ------------------------------------------------------------
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
git \
$(if [ "$ENVIRONMENT" = "local" ] || [ "$ENVIRONMENT" = "development" ]; then echo "telnet"; fi) \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# ------------------------------------------------------------
# Copy only requirements files first (layer cache optimisation)
# ------------------------------------------------------------
COPY requirements/ /tmp/requirements/

# ------------------------------------------------------------
# Install Python dependencies based on the target environment
# - local/development : requirements/local.txt (includes debug toolbar)
# - production : requirements/production.txt (includes gunicorn)
# ------------------------------------------------------------
RUN if [ "$ENVIRONMENT" = "local" ] || [ "$ENVIRONMENT" = "development" ]; then \
pip install -r /tmp/requirements/local.txt; \
else \
pip install -r /tmp/requirements/production.txt; \
fi \
# Clean up temporary requirements files
&& rm -rf /tmp/requirements

# ------------------------------------------------------------
# Copy the full application source code into the container
# ------------------------------------------------------------
COPY . .

CMD [ "python","manage.py","runserver","0.0.0.0:8000" ]
# ------------------------------------------------------------
# Copy and set permissions on the Docker entrypoint script
# The entrypoint handles:
# - Waiting for PostgreSQL to be ready
# - Running makemigrations and migrate
# - Loading initial data (if needed)
# ------------------------------------------------------------
RUN chmod +x /app/docker-entrypoint.sh

# ------------------------------------------------------------
# Expose the application port
# ------------------------------------------------------------
EXPOSE 8000

# ------------------------------------------------------------
# Startup command:
# - local/development : Django dev server (hot-reload)
# - production : Gunicorn WSGI server (multi-worker)
# The entrypoint script runs first to ensure DB readiness
# ------------------------------------------------------------
CMD if [ "$ENVIRONMENT" = "local" ] || [ "$ENVIRONMENT" = "development" ]; then \
/app/docker-entrypoint.sh; \
else \
/app/docker-entrypoint.sh && \
gunicorn core.wsgi:application \
--bind 0.0.0.0:8000 \
--workers 2 \
--timeout 120 \
--log-level info; \
fi
95 changes: 95 additions & 0 deletions Dockerfile.celeryworker
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# ============================================================
# Dockerfile for the celeryworker service
# Python 3.11 + Django 4.2 + Celery 5.3.6
# Supports local and production environments via ARG ENVIRONMENT
# ============================================================

FROM python:3.11-slim

# ------------------------------------------------------------
# Build argument to switch between local and production setups
# Usage: docker build --build-arg ENVIRONMENT=production ...
# ------------------------------------------------------------
ARG ENVIRONMENT=local

# ------------------------------------------------------------
# Environment variables:
# - PYTHONUNBUFFERED: ensures stdout/stderr are flushed immediately (important for logs)
# - PIP_NO_CACHE_DIR: reduces image size by not caching pip downloads
# - PIP_DISABLE_PIP_VERSION_CHECK: suppresses pip version warnings
# - DJANGO_SETTINGS_MODULE: default settings module (overridable at runtime)
# ------------------------------------------------------------
ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
DJANGO_SETTINGS_MODULE=core.settings.local

# ------------------------------------------------------------
# Set the working directory inside the container
# ------------------------------------------------------------
WORKDIR /app

# ------------------------------------------------------------
# Install system-level dependencies:
# - build-essential: required to compile Python C extensions (e.g. psycopg2)
# - libpq-dev: PostgreSQL client library headers (required by psycopg2)
# - git: required by some pip packages that reference git repos
# - telnet: useful for local debugging of broker/db connectivity
# ------------------------------------------------------------
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
git \
telnet \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# ------------------------------------------------------------
# Copy only the requirements files first to leverage Docker layer caching.
# Dependencies are re-installed only when requirements files change.
# ------------------------------------------------------------
COPY requirements/ /tmp/requirements/

# ------------------------------------------------------------
# Install Python dependencies based on the target environment:
# - local/development: installs local.txt (includes debug toolbar, etc.)
# - production (or any other): installs production.txt (includes gunicorn)
# After installation, clean up the temporary requirements directory.
# ------------------------------------------------------------
RUN if [ "$ENVIRONMENT" = "local" ] || [ "$ENVIRONMENT" = "development" ]; then \
echo "Installing LOCAL dependencies..." \
&& pip install -r /tmp/requirements/local.txt; \
else \
echo "Installing PRODUCTION dependencies..." \
&& pip install -r /tmp/requirements/production.txt; \
fi \
&& rm -rf /tmp/requirements/

# ------------------------------------------------------------
# Copy the full application source code into the container
# ------------------------------------------------------------
COPY . .

# ------------------------------------------------------------
# Expose no HTTP port — the celery worker does not serve HTTP traffic.
# It connects outbound to the broker (RabbitMQ) and database (PostgreSQL).
# ------------------------------------------------------------

# ------------------------------------------------------------
# Default startup command: launch the Celery worker
# - -A core.celery : Celery app defined in core/celery.py
# - worker : run as a worker process
# - -l INFO : log level INFO
# - --concurrency 1 : number of concurrent worker processes
# - --max-tasks-per-child 1: recycle worker after N tasks (prevents memory leaks)
# - --prefetch-multiplier 1: fetch one task at a time per worker
# - -n celery@%h : unique worker name using hostname
# Override CMD at runtime for production tuning (e.g. higher concurrency).
# ------------------------------------------------------------
CMD ["celery", "-A", "core.celery", "worker", \
"-l", "INFO", \
"--concurrency", "1", \
"--max-tasks-per-child", "1", \
"--prefetch-multiplier", "1", \
"-n", "celery@%h"]
84 changes: 84 additions & 0 deletions Dockerfile.flower
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# ============================================================
# Dockerfile for the Flower service
# Flower is a Celery monitoring web UI (port 5555)
# Shares the same Django/Celery codebase as core & celeryworker
# ============================================================

# ------------------------------------------------------------
# Base image: Python 3.13 slim (cached locally, amd64 compatible)
# ------------------------------------------------------------
FROM python:3.13-slim

# ------------------------------------------------------------
# Build argument to switch between local and production envs
# Usage:
# Local: docker build --build-arg ENVIRONMENT=local ...
# Production: docker build --build-arg ENVIRONMENT=production ...
# ------------------------------------------------------------
ARG ENVIRONMENT=local

# ------------------------------------------------------------
# Environment variables for Python runtime behaviour
# ------------------------------------------------------------
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
ENVIRONMENT=${ENVIRONMENT}

# ------------------------------------------------------------
# Set working directory
# ------------------------------------------------------------
WORKDIR /app

# ------------------------------------------------------------
# Install OS-level dependencies
# build-essential : needed to compile psycopg2 C extensions
# git : required by some pip packages
# libpq-dev : PostgreSQL client headers for psycopg2
# ------------------------------------------------------------
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
git \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*

# ------------------------------------------------------------
# Copy only requirements files first (layer-cache friendly)
# ------------------------------------------------------------
COPY requirements/ /tmp/requirements/

# ------------------------------------------------------------
# Install Python dependencies based on ENVIRONMENT arg
# local -> requirements/local.txt (includes debug tools)
# production -> requirements/production.txt (includes gunicorn)
# default -> requirements/local.txt
# ------------------------------------------------------------
RUN if [ "$ENVIRONMENT" = "production" ]; then \
echo "Installing production dependencies..." && \
pip install -r /tmp/requirements/production.txt; \
else \
echo "Installing local/development dependencies..." && \
pip install -r /tmp/requirements/local.txt; \
fi \
# Clean up temporary requirements files
&& rm -rf /tmp/requirements

# ------------------------------------------------------------
# Copy the full application source code into the container
# ------------------------------------------------------------
COPY . .

# ------------------------------------------------------------
# Expose Flower's default web UI port
# ------------------------------------------------------------
EXPOSE 5555

# ------------------------------------------------------------
# Default startup command: launch Flower monitoring UI
# -A core.celery : Celery app reference
# --port=5555 : bind to port 5555
# --address=0.0.0.0 : accept connections from any interface
# Override CMD at runtime for different configurations
# ------------------------------------------------------------
CMD ["celery", "-A", "core.celery", "flower", "--port=5555", "--address=0.0.0.0"]
Loading