# Multi-stage Dockerfile for all Python microservices. # Build args: # SERVICE_MODULE — Python module name under services/ (e.g. "news_fetcher") # --------------------------------------------------------------------------- # Stage 1: builder — install Python dependencies # --------------------------------------------------------------------------- FROM python:3.12-slim AS builder WORKDIR /app # Install uv for fast dependency resolution RUN pip install uv # Copy ONLY dependency metadata first — this layer is cached until # pyproject.toml changes, so dependency install is skipped on pure code changes. COPY pyproject.toml . # Create minimal package stubs so uv can resolve the local editable install # without copying all source (which would bust the cache on every commit). RUN mkdir -p shared services backtester && \ uv pip install --system --no-cache-dir ".[api,news,sentiment,trading,backtester]" && \ uv pip install --system --no-cache-dir curl_cffi 2>/dev/null || true # NOW copy the actual source code (changes here don't re-trigger dep install) COPY shared/ shared/ COPY services/ services/ COPY backtester/ backtester/ COPY alembic/ alembic/ COPY alembic.ini . # Re-install in-place so the package metadata points to actual source RUN uv pip install --system --no-cache-dir --no-deps -e . # --------------------------------------------------------------------------- # Stage 2: slim runtime image # --------------------------------------------------------------------------- FROM python:3.12-slim RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/* WORKDIR /app # Copy installed packages and CLI entry-points from the builder COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages COPY --from=builder /usr/local/bin /usr/local/bin # Copy application source code COPY --from=builder /app . ARG SERVICE_MODULE="api_gateway" ENV SERVICE_MODULE=${SERVICE_MODULE} ARG HEALTH_PORT="9090" ENV HEALTH_PORT=${HEALTH_PORT} # Check /metrics endpoint (all services expose it via OpenTelemetry) HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \ CMD curl -sf http://localhost:${HEALTH_PORT}/metrics > /dev/null || exit 1 CMD python -m services.${SERVICE_MODULE}.main