# ============================================================================== # TradeSense AI — Production Google Cloud Run Dockerfile (Milestone 19) # Multi-stage slim build, non-root execution, dynamic $PORT handling. # ============================================================================== FROM python:3.11-slim AS builder WORKDIR /app RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ curl \ && rm -rf /var/lib/apt/lists/* COPY pyproject.toml . # Install dependencies in virtual environment RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" RUN pip install --no-cache-dir --upgrade pip setuptools wheel RUN pip install --no-cache-dir \ fastapi \ uvicorn \ pydantic \ numpy \ pandas \ scipy \ statsmodels \ scikit-learn \ yfinance \ pytest \ httpx # Final slim runtime container FROM python:3.11-slim AS runner WORKDIR /app ENV PATH="/opt/venv/bin:$PATH" \ PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 \ PORT=8080 \ APP_ENV=production \ STORAGE_BACKEND=local # Copy virtualenv from builder COPY --from=builder /opt/venv /opt/venv # Create unprivileged system user (UID 10001) RUN groupadd -g 10001 appgroup && \ useradd -u 10001 -g appgroup -s /bin/sh -m appuser # Copy application source code COPY backend /app/backend COPY quant /app/quant COPY templates /app/templates COPY static /app/static COPY data /app/data # Set ownership to non-root user RUN chown -R appuser:appgroup /app USER appuser # Container local healthcheck (for Docker inspection) HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \ CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:' + str(os.environ.get('PORT', 8080)) + '/health').read()" || exit 1 # Cloud Run dynamic PORT binding EXPOSE 8080 CMD ["sh", "-c", "exec uvicorn backend.app.main:app --host 0.0.0.0 --port ${PORT:-8080} --workers 2 --proxy-headers"]