13 — Dockerfile
← Anterior: 12 — Cloud Tasks y Scheduler
Un Dockerfile es una receta para construir una imagen Docker. Este capítulo crea uno optimizado para Django en Cloud Run.
El Dockerfile
Crea Dockerfile en la raíz del repo (junto a manage.py):
# ── Base image ────────────────────────────────────────────────────────────────
FROM python:3.12-slim
# ── Install uv ───────────────────────────────────────────────────────────────
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
# ── Working directory ─────────────────────────────────────────────────────────
WORKDIR /app
# ── Install Python dependencies ───────────────────────────────────────────────
COPY web/pyproject.toml web/uv.lock ./
RUN uv sync --frozen --no-dev
# ── Copy application source ───────────────────────────────────────────────────
COPY web/ .
# ── Environment variables ───────────────────────────────────────────────────────
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
DJANGO_SETTINGS_MODULE=core.settings.prod \
PORT=8080
# ── Port ──────────────────────────────────────────────────────────────────────
EXPOSE 8080
# ── Start command ─────────────────────────────────────────────────────────────
CMD ["uv", "run", "gunicorn", \
"--bind", "0.0.0.0:8080", \
"--workers", "2", \
"--timeout", "60", \
"--log-file", "-", \
"core.wsgi"]
.dockerignore
Crea .dockerignore en la raíz del repo para prevenir que archivos innecesarios se envíen al contexto de build de Docker:
.git
web/.venv
web/media/
web/staticfiles/
web/htmlcov/
**/__pycache__
**/*.pyc
**/*.pyo
.env
*.md
DEPLOY/
Esto mantiene la imagen pequeña y previene que secretos se incluyan accidentalmente.
Opciones de Gunicorn explicadas
| Opción | Valor | Por qué |
|---|---|---|
--bind 0.0.0.0:8080 |
Escuchar en todas las interfaces, puerto 8080 | Cloud Run espera el puerto 8080 |
--workers 2 |
2 procesos worker | Manejar solicitudes concurrentes |
--timeout 60 |
60 segundos de timeout | Matar solicitudes lentas para prevenir bloqueo |
--log-file - |
Escribir logs a stdout | Cloud Logging captura stdout |
core.wsgi |
Punto de entrada WSGI | Located at web/core/wsgi.py |
Construir y probar localmente
Construir la imagen:
Probarla localmente (requiere un Postgres local o mock DATABASE_URL):
docker run --rm \
-e DATABASE_URL="postgresql://postgres:postgres@host.docker.internal:5432/mycoolproject_dev" \
-e SECRET_KEY="local-test-key" \
-e ALLOWED_HOSTS="localhost" \
-p 8080:8080 \
mycoolproject-app
Visita http://localhost:8080 para verificar que inicia.
El nombre de la imagen
En main.tf, el servicio Cloud Run referencia la imagen:
Esto se resuelve a:
GitHub Actions hará push de imágenes con:
- Etiqueta latest — siempre apunta al build más reciente
- Etiqueta <git-sha> — única por commit, para rollbacks
Build de dos etapas (opcional)
Para imágenes más pequeñas, puedes usar un build de dos etapas:
# Stage 1: Build
FROM python:3.12-slim as builder
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
WORKDIR /app
COPY web/pyproject.toml web/uv.lock ./
RUN uv sync --frozen --no-dev
COPY web/ .
# Stage 2: Runtime
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /app/web/ ./web/
COPY --from=builder /app/.venv/ ./.venv/
ENV PATH="/app/.venv/bin:$PATH"
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
DJANGO_SETTINGS_MODULE=core.settings.prod \
PORT=8080
EXPOSE 8080
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "--workers", "2", "--timeout", "60", "--log-file", "-", "core.wsgi"]
Esto resulta en una imagen más pequeña porque excluye las herramientas de build. Por simplicidad, usamos la versión de una etapa en esta guía.
Navegación
- 01 — Introducción: Qué vamos a construir
- 02 — Visión general de Terraform
- 03 — Servicios en la nube explicados
- 04 — Base de datos PlanetScale explicada
- 05 — Configuración del proyecto y estado de Terraform
- 06 — Proyecto GCP y APIs
- 07 — Artifact Registry
- 08 — Gestión de Secretos
- 09 — Cloud Storage
- 10 — Service Accounts e IAM
- 11 — Cloud Run
- 12 — Cloud Tasks y Scheduler
- 13 — Dockerfile (Capítulo actual)
- 14 — Primer Despliegue
- 15 — Dominio personalizado y SSL
- 16 — Workload Identity Federation
- 17 — GitHub Actions CI/CD
- 18 — Referencia Rápida