Despliegue Django con Docker

Avanzado
Django
Django
Actualizado: 18/04/2026

Dockerfile para Django

# Dockerfile
FROM python:3.12-slim AS base

# Variables de entorno
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PIP_NO_CACHE_DIR=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=1

WORKDIR /app

# Instalar dependencias del sistema
RUN apt-get update && apt-get install -y \
    libpq-dev \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# Instalar dependencias Python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copiar código fuente
COPY . .

# Crear usuario sin privilegios
RUN addgroup --system django && adduser --system --ingroup django django
RUN chown -R django:django /app
USER django

# Recopilar archivos estáticos en build time
RUN python manage.py collectstatic --noinput

EXPOSE 8000

# Usar gunicorn en producción
CMD ["gunicorn", "mi_proyecto.wsgi:application", \
     "--bind", "0.0.0.0:8000", \
     "--workers", "3", \
     "--timeout", "30"]

Diagrama conceptual de Despliegue Django con Docker

docker-compose para desarrollo

# docker-compose.yml
version: '3.9'

services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: ${DB_NAME:-mi_app}
      POSTGRES_USER: ${DB_USER:-postgres}
      POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres}"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  web:
    build: .
    command: >
      sh -c "python manage.py migrate &&
             python manage.py collectstatic --noinput &&
             gunicorn mi_proyecto.wsgi:application --bind 0.0.0.0:8000"
    volumes:
      - .:/app
      - static_volume:/app/staticfiles
      - media_volume:/app/media
    ports:
      - "8000:8000"
    env_file:
      - .env
    environment:
      - DJANGO_SETTINGS_MODULE=mi_proyecto.settings.produccion
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy

  nginx:
    image: nginx:alpine
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - static_volume:/app/staticfiles:ro
      - media_volume:/app/media:ro
    ports:
      - "80:80"
    depends_on:
      - web

volumes:
  postgres_data:
  redis_data:
  static_volume:
  media_volume:

Archivo .env

# .env (NO incluir en el repositorio)
SECRET_KEY=tu_clave_secreta_muy_larga_y_aleatoria
DEBUG=False
ALLOWED_HOSTS=localhost,127.0.0.1,mi-dominio.com

# Base de datos
DB_ENGINE=django.db.backends.postgresql
DB_NAME=mi_app
DB_USER=postgres
DB_PASSWORD=contraseña_segura
DB_HOST=db
DB_PORT=5432

# Redis
REDIS_URL=redis://redis:6379/1

# Email
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=noreply@mi-app.com
EMAIL_HOST_PASSWORD=app_password

Comandos Docker útiles

# Construir y arrancar todos los servicios
docker-compose up --build -d

# Ver logs en tiempo real
docker-compose logs -f web

# Ejecutar comandos en el contenedor
docker-compose exec web python manage.py createsuperuser
docker-compose exec web python manage.py shell
docker-compose exec web python manage.py migrate

# Parar y eliminar contenedores (mantiene volúmenes)
docker-compose down

# Parar y eliminar TODO incluyendo volúmenes (¡elimina la base de datos!)
docker-compose down -v

# Reconstruir solo el servicio web
docker-compose up -d --build web

docker-compose.override.yml para desarrollo

# docker-compose.override.yml (sobreescribe docker-compose.yml en desarrollo)
version: '3.9'

services:
  web:
    command: python manage.py runserver 0.0.0.0:8000
    environment:
      - DJANGO_SETTINGS_MODULE=mi_proyecto.settings.desarrollo
      - DEBUG=True
    volumes:
      - .:/app  # Recarga automática con cambios

Nginx para Docker

# nginx.conf
upstream django {
    server web:8000;
}

server {
    listen 80;
    client_max_body_size 20M;

    location /static/ {
        alias /app/staticfiles/;
        expires 30d;
    }

    location /media/ {
        alias /app/media/;
        expires 7d;
    }

    location / {
        proxy_pass http://django;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Docker garantiza que la aplicación se ejecuta en el mismo entorno en desarrollo y producción, eliminando el problema "en mi máquina funciona" y facilitando los despliegues reproducibles.

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Django es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de Django

Explora más contenido relacionado con Django y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Escribir un Dockerfile optimizado para una aplicación Django. Configurar docker-compose con Django, PostgreSQL y Redis. Gestionar variables de entorno y secretos en contenedores. Ejecutar collectstatic y migraciones en el proceso de build y arranque. Configurar volúmenes para persistencia de datos y archivos media.