11# ---- Stage 1: Builder ----
22 FROM python:3.12-slim AS builder
33
4- # Define a build argument to signal if running in GitHub Actions
5- ARG IS_GITHUB_ACTION =false
4+ # Define a build argument to signal if we should install CPU-specific torch
5+ ARG USE_CPU_TORCH =false
66 ARG AWS_REGION
77
88 ENV PYTHONDONTWRITEBYTECODE=1
2727 # Copy only dependency files first - this layer is cached unless dependencies change
2828 COPY pyproject.toml requirements.lock ./
2929
30- # Conditionally install PyTorch CPU versions if IS_GITHUB_ACTION is true
31- RUN --mount=type=cache,target=/root/.cache/pip \
32- if [ "$IS_GITHUB_ACTION" = "true" ]; then \
33- echo "IS_GITHUB_ACTION is true. Installing PyTorch CPU versions..." ; \
34- pip install \
35- --index-url https://download.pytorch.org/whl/cpu \
36- torch==2.8.0+cpu \
37- torchvision==0.23.0+cpu \
38- torchaudio==2.8.0+cpu; \
39- else \
40- echo "IS_GITHUB_ACTION is false or not set. Skipping explicit PyTorch CPU-specific installation." ; \
41- echo "PyTorch (if required) will be installed from requirements.lock." ; \
42- fi
43-
44- # Install dependencies from lock file (cached layer - reused unless requirements.lock changes)
45- # BuildKit cache mount keeps pip cache between builds for faster rebuilds
46- RUN --mount=type=cache,target=/root/.cache/pip \
47- if [ "$IS_GITHUB_ACTION" = "true" ]; then \
48- echo "IS_GITHUB_ACTION is true. Skipping requirements.lock (already installed CPU deps)." ; \
49- else \
50- echo "IS_GITHUB_ACTION is false. Installing from requirements.lock..." ; \
51- pip install -r requirements.lock; \
52- fi
30+ # Install dependencies from lock file (cached layer - reused unless requirements.lock changes)
31+ # BuildKit cache mount keeps pip cache between builds for faster rebuilds
32+ # If USE_CPU_TORCH is true, we install CPU-specific wheels and filter them out of the lockfile
33+ RUN --mount=type=cache,target=/root/.cache/pip \
34+ if [ "$USE_CPU_TORCH" = "true" ]; then \
35+ echo "USE_CPU_TORCH=true: Installing CPU-only PyTorch..." && \
36+ pip install --index-url https://download.pytorch.org/whl/cpu \
37+ torch==2.8.0+cpu \
38+ torchvision==0.23.0+cpu \
39+ torchaudio==2.8.0+cpu && \
40+ echo "Filtering standard torch packages from requirements.lock..." && \
41+ grep -vE "^(torch|torchvision|torchaudio)==" requirements.lock > requirements.filtered.lock && \
42+ pip install -r requirements.filtered.lock; \
43+ else \
44+ echo "USE_CPU_TORCH=false: Installing standard dependencies..." && \
45+ pip install -r requirements.lock; \
46+ fi
5347
5448 # ===== OPTIMIZATION: Copy source code LAST (busts cache on code changes) =====
5549 # Copy source code - this layer rebuilds when code changes but reuses dependency layers above
7064 (ls -lhR /usr/local/lib/python3.12/site-packages/nvidia || echo "NVIDIA directory not found." ) && \
7165 (ls -lhR /usr/local/lib/python3.12/site-packages/torch/lib/*cuda* || echo "No CUDA libs in torch/lib." )
7266
73- # ---- Stage 2: Final ----
74- FROM python:3.12-slim AS final
67+ # ---- Stage 2: Final ----
68+ FROM python:3.12-slim AS final
69+
70+ ENV PYTHONDONTWRITEBYTECODE=1
71+ ENV PYTHONUNBUFFERED=1
72+ ENV AWS_REGION=${AWS_REGION:-us-east-1}
73+
74+ RUN apt-get update && \
75+ apt-get install -y --no-install-recommends \
76+ curl \
77+ && apt-get clean && \
78+ rm -rf /var/lib/apt/lists/*
79+
80+ WORKDIR /app
81+
82+ # Copy installed packages from builder stage
83+ COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
84+ COPY --from=builder /usr/local/bin /usr/local/bin
85+
86+ # Copy source code from builder stage (already built into the package)
87+ COPY --from=builder /app/polismath/ ./polismath/
88+ COPY --from=builder /app/scripts/ ./scripts/
89+ COPY --from=builder /app/umap_narrative/ ./umap_narrative/
90+ COPY --from=builder /app/*.py ./
91+
92+ RUN mkdir -p data
93+ EXPOSE 8080
94+ # PYTHONPATH not needed since packages are properly installed via pip
95+
96+ # Make scripts executable
97+ RUN chmod +x run_delphi.py scripts/setup_ollama.sh
98+
99+ CMD ["bash" , "-c" , "\
100+ echo 'Ensuring DynamoDB tables are set up (runs in all environments)...'; \
101+ python create_dynamodb_tables.py --region ${AWS_REGION} && \
102+ echo 'DynamoDB table setup script finished.'; \
103+ \
104+ if [ -n \" ${DYNAMODB_ENDPOINT}\" ]; then \
105+ echo 'DYNAMODB_ENDPOINT is set, assuming local/dev environment. Running additional local setup scripts...'; \
106+ echo 'Setting up MinIO bucket...' && python setup_minio.py && \
107+ echo 'Setting up Ollama model (local script)...' && ./scripts/setup_ollama.sh && \
108+ echo 'Starting job poller without ddtrace...' && \
109+ python scripts/job_poller.py --interval=2; \
110+ else \
111+ echo 'DYNAMODB_ENDPOINT is not set, assuming production-like environment. Skipping local setup scripts.'; \
112+ if [ \" ${AWS_REGION}\" = \" us-east-1\" ]; then \
113+ echo 'Starting job poller WITH ddtrace in us-east-1...' && \
114+ ddtrace-run python scripts/job_poller.py --interval=2 --region ${AWS_REGION}; \
115+ else \
116+ echo 'Starting job poller WITHOUT ddtrace in other regions...' && \
117+ python scripts/job_poller.py --interval=2 --region ${AWS_REGION}; \
118+ fi; \
119+ fi \
120+ " ]
75121
76- ENV PYTHONDONTWRITEBYTECODE=1
77- ENV PYTHONUNBUFFERED=1
78- ENV AWS_REGION=${AWS_REGION:-us-east-1}
122+ # ---- Stage 3: Test ----
123+ # Extends final stage with dev dependencies for CI/testing
124+ FROM final AS test
79125
80- RUN apt-get update && \
81- apt-get install -y --no-install-recommends \
82- curl \
83- && apt-get clean && \
84- rm -rf /var/lib/apt/lists/*
126+ # Copy pyproject.toml to install dev dependencies
127+ COPY pyproject.toml .
85128
86- WORKDIR /app
129+ # Install dev dependencies (pytest, etc.) using caching
130+ RUN --mount=type=cache,target=/root/.cache/pip \
131+ pip install --no-cache-dir ".[dev]"
87132
88- # Copy installed packages from builder stage
89- COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
90- COPY --from=builder /usr/local/bin /usr/local/bin
91-
92- # Copy source code from builder stage (already built into the package)
93- COPY --from=builder /app/polismath/ ./polismath/
94- COPY --from=builder /app/scripts/ ./scripts/
95- COPY --from=builder /app/umap_narrative/ ./umap_narrative/
96- COPY --from=builder /app/*.py ./
97-
98- RUN mkdir -p data
99- EXPOSE 8080
100- # PYTHONPATH not needed since packages are properly installed via pip
101-
102- # Make scripts executable
103- RUN chmod +x run_delphi.py scripts/setup_ollama.sh
104-
105- CMD ["bash" , "-c" , "\
106- echo 'Ensuring DynamoDB tables are set up (runs in all environments)...'; \
107- python create_dynamodb_tables.py --region ${AWS_REGION} && \
108- echo 'DynamoDB table setup script finished.'; \
109- \
110- if [ -n \" ${DYNAMODB_ENDPOINT}\" ]; then \
111- echo 'DYNAMODB_ENDPOINT is set, assuming local/dev environment. Running additional local setup scripts...'; \
112- echo 'Setting up MinIO bucket...' && python setup_minio.py && \
113- echo 'Setting up Ollama model (local script)...' && ./scripts/setup_ollama.sh && \
114- echo 'Starting job poller without ddtrace...' && \
115- python scripts/job_poller.py --interval=2; \
116- else \
117- echo 'DYNAMODB_ENDPOINT is not set, assuming production-like environment. Skipping local setup scripts.'; \
118- if [ \" ${AWS_REGION}\" = \" us-east-1\" ]; then \
119- echo 'Starting job poller WITH ddtrace in us-east-1...' && \
120- ddtrace-run python scripts/job_poller.py --interval=2 --region ${AWS_REGION}; \
121- else \
122- echo 'Starting job poller WITHOUT ddtrace in other regions...' && \
123- python scripts/job_poller.py --interval=2 --region ${AWS_REGION}; \
124- fi; \
125- fi \
126- " ]
133+ # Default command for test container (can be overridden)
134+ CMD ["tail" , "-f" , "/dev/null" ]
0 commit comments