deploy/docker/Dockerfile
Rama main · réplica de lectura del repositorio original.
# syntax=docker/dockerfile:1.7
# --- builder ---
FROM python:3.11-slim AS builder
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
WORKDIR /build
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN curl -LsSf https://astral.sh/uv/install.sh | sh && \
cp /root/.local/bin/uv /usr/local/bin/uv
# Deterministic, dependencies-ONLY install pinned from uv.lock (NOT pyproject
# ranges) and EXCLUDING the project itself (--no-emit-project). Two payoffs:
# 1. reproducible — the resolved dep set is fixed by the lock, so the same
# commit always yields the same site-packages bytes;
# 2. cache-stable — this ~1GB layer's inputs are only pyproject.toml + uv.lock,
# so a code-only change does NOT rebuild it and cluster nodes reuse the
# already-pulled layer (no slow multi-minute re-pull → no helm hook timeout).
# The project code itself is NOT installed here; it ships as /app/src and runs
# via PYTHONPATH in the runtime stage (a separate, tiny layer).
COPY pyproject.toml uv.lock README.md ./
RUN uv export --frozen --no-dev --no-emit-project -o /tmp/requirements.txt && \
uv pip install --system --no-cache -r /tmp/requirements.txt
# --- runtime: distroless ---
# Pinned to a known-good digest. Bump via Renovate (PR + Trivy gate).
FROM gcr.io/distroless/python3-debian12:nonroot AS runtime
WORKDIR /app
# Dependencies (stable layer — changes only when uv.lock changes).
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /usr/local/bin/uvicorn /usr/local/bin/uvicorn
COPY --from=builder /usr/local/bin/alembic /usr/local/bin/alembic
# distroless `python3` lives at /usr/bin/python3.11 with sys.path NOT including
# our paths by default. Put the project source (/app/src) FIRST so `ai_api` is
# imported from the small code layer, then the deps in site-packages. Everything
# is invoked as `python3 -m …` (uvicorn / alembic / ai_api.cli.*), so no reliance
# on console-script shebangs.
ENV PYTHONPATH=/app/src:/usr/local/lib/python3.11/site-packages \
PATH=/usr/local/bin:$PATH \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
# Project code — its own small layer (changes on every code edit, but it's tiny).
COPY src/ ./src/
COPY alembic/ ./alembic/
COPY alembic.ini ./
COPY deploy/docker/healthcheck.py /app/healthcheck.py
USER nonroot
EXPOSE 8000
HEALTHCHECK --interval=10s --timeout=5s --retries=5 \
CMD ["python3", "/app/healthcheck.py"]
ENTRYPOINT ["python3"]
CMD ["-m", "uvicorn", "ai_api.main:app", "--host", "0.0.0.0", "--port", "8000"]