# ============================================================ # Stage 1: Builder — install deps + compile Python bytecode # ============================================================ FROM python:3.12-slim AS builder WORKDIR /build # System deps needed to compile psycopg2, xgboost, etc. RUN apt-get update && apt-get install -y --no-install-recommends \ gcc \ g++ \ libpq-dev \ libffi-dev \ libssl-dev \ && rm -rf /var/lib/apt/lists/* # Upgrade pip + install wheel for faster builds RUN pip install --upgrade pip wheel # Copy only requirements first (layer caching) COPY requirements.txt . # Install into a prefix we can copy cleanly RUN pip install --prefix=/install --no-cache-dir -r requirements.txt # ============================================================ # Stage 2: Runner — minimal production image # ============================================================ FROM python:3.12-slim AS runner LABEL maintainer="DevOps " LABEL org.opencontainers.image.title="Turf SaaS" LABEL org.opencontainers.image.description="H3R7Tech Turf Predictions SaaS" # Runtime system deps only RUN apt-get update && apt-get install -y --no-install-recommends \ libpq5 \ curl \ && rm -rf /var/lib/apt/lists/* # Create non-root app user RUN groupadd -r appuser && useradd -r -g appuser appuser WORKDIR /app # Copy installed packages from builder COPY --from=builder /install /usr/local # Copy application source (exclude files via .dockerignore) COPY . . # Create directories for persistent data RUN mkdir -p /app/data/db /app/data/models /app/logs \ && chown -R appuser:appuser /app # Switch to non-root user USER appuser # Expose all service ports EXPOSE 8790 8791 8792 8793 # Health check — hits the combined API HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD curl -f http://localhost:8790/health || exit 1 # Default: run combined API via gunicorn # Override CMD per service in docker-compose CMD ["gunicorn", "--bind", "0.0.0.0:8790", "--workers", "2", "--timeout", "120", "combined_api:app"]