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
57 changes: 57 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# =============================================================================
# Environment variables for the django-example application
# Used by docker-compose.yml for all services
# =============================================================================

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

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

# -----------------------------------------------------------------------------
# PostgreSQL Database
# DB_HOST must match the docker-compose service name: 'db'
# -----------------------------------------------------------------------------
DB_ENGINE=django.db.backends.postgresql_psycopg2
DB_NAME=postgres
DB_USER=postgres
DB_PASSWORD=qwerty123
DB_HOST=db
DB_PORT=5432

# PostgreSQL image-level credentials (used by the postgres container itself)
POSTGRES_USER=postgres
POSTGRES_PASSWORD=qwerty123
POSTGRES_DB=postgres

# -----------------------------------------------------------------------------
# Celery + RabbitMQ
# CELERY_BROKER_URL must match the docker-compose service name: 'broker'
# -----------------------------------------------------------------------------
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
CELERY_RESULT_EXTENDED=False

# RabbitMQ image-level credentials (used by the rabbitmq container itself)
RABBITMQ_DEFAULT_USER=admin
RABBITMQ_DEFAULT_PASS=admin
RABBITMQ_DEFAULT_VHOST=vhost

# -----------------------------------------------------------------------------
# Cache (Redis) — currently disabled, uncomment to enable
# -----------------------------------------------------------------------------
# REDIS_URL=redis://cache:6379/0
135 changes: 103 additions & 32 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,44 +1,115 @@
FROM python:3.9.13
# =============================================================================
# Dockerfile for the Django 'core' service
# Supports both local/development and production environments
# via the ARG ENVIRONMENT build argument.
#
# Usage:
# Local: docker build --build-arg ENVIRONMENT=local -t core:local .
# Production: docker build --build-arg ENVIRONMENT=production -t core:prod .
# =============================================================================

ARG ENVIRONMENT=default
# -----------------------------------------------------------------------------
# Base image: Python 3.9.13 (pinned for reproducibility)
# -----------------------------------------------------------------------------
FROM python:3.9.13

ENV PYTHONUNBUFFERED 1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=1
# -----------------------------------------------------------------------------
# Build argument to switch between environments:
# local → installs dev dependencies + telnet, runs Django dev server
# production → installs prod dependencies only, runs Gunicorn
# -----------------------------------------------------------------------------
ARG ENVIRONMENT=local

# -----------------------------------------------------------------------------
# Environment variables:
# PYTHONUNBUFFERED → forces stdout/stderr to be unbuffered (better logging)
# PIP_NO_CACHE_DIR → disables pip cache to reduce image size
# PIP_DISABLE_PIP_VERSION_CHECK → suppresses pip upgrade warnings
# ENVIRONMENT → makes the build ARG available at runtime for CMD logic
# -----------------------------------------------------------------------------
ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
ENVIRONMENT=${ENVIRONMENT}

# -----------------------------------------------------------------------------
# Set the working directory for all subsequent instructions
# -----------------------------------------------------------------------------
WORKDIR /app

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

# -----------------------------------------------------------------------------
# Install system and Python dependencies based on the target environment.
#
# buildDeps → required to compile native Python extensions (e.g. psycopg2)
# runDeps → required at runtime (git)
# localDeps → useful for local debugging only (telnet)
#
# In production: build deps are removed after pip install to reduce image size.
# -----------------------------------------------------------------------------
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/*
&& buildDeps="build-essential" \
&& runDeps="git" \
&& localDeps="telnet" \
# Update apt package index
&& apt-get update \
# Install build-time dependencies (needed to compile psycopg2, etc.)
&& apt-get install -y --no-install-recommends $buildDeps \
# Install runtime dependencies
&& apt-get install -y --no-install-recommends $runDeps \
# Environment-specific Python dependency installation
&& if [ "$ENVIRONMENT" = "local" ] || [ "$ENVIRONMENT" = "development" ]; then \
# Install local debugging tools
apt-get install -y --no-install-recommends $localDeps \
# Install local/development Python dependencies (includes debug toolbar, etc.)
&& pip install -r /tmp/requirements/local.txt; \
else \
# Install production Python dependencies only (gunicorn, no debug tools)
pip install -r /tmp/requirements/production.txt \
# Remove build dependencies to keep the production image lean
&& apt-get remove -y $buildDeps \
&& apt-get autoremove -y; \
fi \
# Clean up apt cache to reduce image size
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
# Remove temporary requirements files
&& rm -rf /tmp/*

# -----------------------------------------------------------------------------
# Copy the full application source code into the container.
# Done after dependency installation to maximise Docker layer cache reuse.
# -----------------------------------------------------------------------------
COPY . .

CMD [ "python","manage.py","runserver","0.0.0.0:8000" ]
# -----------------------------------------------------------------------------
# Ensure the entrypoint script is executable.
# The entrypoint handles:
# 1. Waiting for PostgreSQL to be ready (via psycopg2 health check)
# 2. Running makemigrations and migrate
# 3. Loading initial data if this is the first run
# 4. Starting the Django development server
# -----------------------------------------------------------------------------
RUN chmod +x /app/docker-entrypoint.sh

# -----------------------------------------------------------------------------
# Startup command:
# local/development → runs docker-entrypoint.sh (dev server on port 8000)
# production → runs Gunicorn WSGI server directly (multi-worker)
# Note: In production, DB migrations should be handled
# separately (e.g. init container or CI/CD pipeline).
# -----------------------------------------------------------------------------
CMD if [ "$ENVIRONMENT" = "production" ]; then \
gunicorn core.wsgi:application \
--bind 0.0.0.0:8000 \
--workers 2 \
--timeout 120 \
--log-level info; \
else \
/app/docker-entrypoint.sh; \
fi
108 changes: 108 additions & 0 deletions Dockerfile.celeryworker
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# =============================================================================
# Dockerfile for the celeryworker service
# Asynchronous task worker using Celery with Django integration
# Supports both local/development and production environments via ARG ENVIRONMENT
# =============================================================================

# Base image: Python 3.9.13 (matches project's required Python version)
FROM python:3.9.13

# Build argument to switch between local and production configurations
# Values: local | development | production (default: local)
ARG ENVIRONMENT=local

# -----------------------------------------------------------------------------
# Environment variables
# PYTHONUNBUFFERED: Ensures Python output is sent straight to terminal (no buffering)
# PIP_NO_CACHE_DIR: Disables pip cache to reduce image size
# PIP_DISABLE_PIP_VERSION_CHECK: Suppresses pip version warnings during builds
# -----------------------------------------------------------------------------
ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=1

# Set the working directory inside the container
WORKDIR /app

# -----------------------------------------------------------------------------
# Copy only the requirements files first to leverage Docker layer caching.
# This way, dependencies are only re-installed when requirements files change.
# -----------------------------------------------------------------------------
COPY requirements/*.txt /tmp/requirements/

# -----------------------------------------------------------------------------
# Install system and Python dependencies based on the target environment.
#
# buildDeps: Packages needed only at build time (removed in production to reduce image size)
# runDeps: Packages needed at runtime in all environments
# localDeps: Extra packages useful only in local/development (e.g. telnet for debugging)
#
# For local/development:
# - Installs buildDeps + runDeps + localDeps
# - Installs Python deps from requirements/local.txt (_base.txt + django-debug-toolbar)
#
# For production:
# - Installs buildDeps + runDeps only
# - Installs Python deps from requirements/production.txt (_base.txt + gunicorn)
# - Removes buildDeps after install to keep the image lean
# -----------------------------------------------------------------------------
RUN set -x \
&& buildDeps=" \
build-essential \
" \
&& runDeps=" \
git \
" \
&& localDeps=" \
telnet \
" \
# Update apt package index
&& apt-get update \
# Install build-time dependencies
&& apt-get install -y --no-install-recommends $buildDeps \
# Install runtime dependencies
&& apt-get install -y --no-install-recommends $runDeps \
# Conditionally install environment-specific packages and Python deps
&& if [ "$ENVIRONMENT" = "local" ] || [ "$ENVIRONMENT" = "development" ]; then \
# Install local debugging tools
apt-get install -y --no-install-recommends $localDeps \
# Install Python dependencies for local environment (includes django-debug-toolbar)
&& pip install -r /tmp/requirements/local.txt; \
else \
# Install Python dependencies for production (includes gunicorn)
pip install -r /tmp/requirements/production.txt \
# Remove build dependencies to reduce final image size in production
&& apt-get remove -y $buildDeps; \
fi \
# Clean up apt cache to reduce image size
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
# Remove temporary requirements files
&& rm -rf /tmp/*

# -----------------------------------------------------------------------------
# Copy the full application source code into the container.
# Done after dependency installation to maximize Docker layer cache reuse.
# -----------------------------------------------------------------------------
COPY . .

# -----------------------------------------------------------------------------
# Default startup command for the Celery worker.
#
# Flags:
# -A core.celery : Django project's Celery application module
# worker : Start a Celery worker process
# -l INFO : Set log level to INFO
# --concurrency 1 : Use 1 worker process (suitable for CPU-bound tasks)
# --max-tasks-per-child 1 : Restart worker after each task (prevents memory leaks)
# --prefetch-multiplier 1 : Fetch only 1 task at a time per worker (fair dispatch)
# -n celery@%h : Worker node name using the hostname
#
# Override this CMD in docker-compose or at runtime for production tuning.
# -----------------------------------------------------------------------------
CMD ["celery", "-A", "core.celery", "worker", \
"-l", "INFO", \
"--concurrency", "1", \
"--max-tasks-per-child", "1", \
"--prefetch-multiplier", "1", \
"-n", "celery@%h"]
Loading