# syntax=docker/dockerfile:1 FROM python:3.13-slim # Pull uv binary from the official image (no pip overhead) COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/ # Non-root user for security RUN adduser --disabled-password --no-create-home appuser WORKDIR /app # Install dependencies first (layer is cached unless lock file changes) COPY pyproject.toml uv.lock ./ RUN uv sync --frozen --no-dev --no-install-project # Copy application source COPY src/ ./src/ # data.csv is NOT baked into the image — it is mounted at runtime via docker-compose # so updates to the CSV don't require a rebuild. RUN chown -R appuser:appuser /app USER appuser # WORKDIR=/app → gunicorn CWD is /app → data.csv resolves to /app/data.csv (mounted volume) # PYTHONPATH=/app/src → 'app' module resolves to src/app.py ENV PYTHONPATH=/app/src EXPOSE 8000 HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000')" CMD ["uv", "run", "--no-dev", "gunicorn", \ "--workers", "2", \ "--bind", "0.0.0.0:8000", \ "--access-logfile", "-", \ "--error-logfile", "-", \ "app:app"]