GitHub Actions commited on
Commit
0bf6516
Β·
1 Parent(s): 4468cb1

deploy: sync Dockerfile.hf to Dockerfile for Hugging Face

Browse files
Files changed (1) hide show
  1. Dockerfile +39 -79
Dockerfile CHANGED
@@ -1,109 +1,69 @@
1
  # ─────────────────────────────────────────────────────────────────────────────
2
- # CustomerCore β€” Production Dockerfile (Phase 10)
3
  #
4
- # WHY MULTI-STAGE BUILD?
5
- # Multi-stage builds separate the build environment from the runtime environment.
6
- # Stage 1 (builder): Installs all dependencies including build tools (gcc, etc.)
7
- # Stage 2 (runtime): Copies only the installed packages, not the build tools.
8
- # Result: Final image is ~60% smaller, has a smaller attack surface (no gcc in prod).
 
 
9
  #
10
- # This image is for the full CustomerCore stack including PySpark/JVM.
11
- # For Hugging Face Spaces deployment (2 vCPU, 16GB RAM), use Dockerfile.hf
12
- # which strips PySpark to fit within HF's resource limits.
13
  #
14
- # BASE IMAGE CHOICE: python:3.12-slim-bookworm
15
- # - slim: Minimal Debian Bookworm (no docs, man pages, debug tools)
16
- # - bookworm: Debian 12 LTS β€” security patches until 2028
17
- # - Not alpine: PySpark's JVM has compatibility issues with Alpine's musl libc
 
18
  # ─────────────────────────────────────────────────────────────────────────────
19
 
20
- # ── Stage 1: Builder ─────────────────────────────────────────────────────────
21
- FROM python:3.12-slim-bookworm AS builder
22
 
23
- # Set build environment
24
- ENV PYTHONDONTWRITEBYTECODE=1 \
25
- PYTHONUNBUFFERED=1 \
26
- PIP_NO_CACHE_DIR=1 \
27
- PIP_DISABLE_PIP_VERSION_CHECK=1
28
-
29
- WORKDIR /build
30
-
31
- # Install build dependencies (only needed at build time, not runtime)
32
- RUN apt-get update && apt-get install -y --no-install-recommends \
33
- gcc \
34
- g++ \
35
- libffi-dev \
36
- libssl-dev \
37
- && rm -rf /var/lib/apt/lists/*
38
-
39
- # Install Python dependencies into a prefix directory (not system Python)
40
- # This makes it easy to copy just the packages into the runtime stage
41
- COPY requirements.txt .
42
- RUN --mount=type=cache,target=/root/.cache/pip \
43
- sed -i '/pywin32/d' requirements.txt && \
44
- pip install --prefix=/install --extra-index-url https://download.pytorch.org/whl/cpu -r requirements.txt
45
-
46
-
47
- # ── Stage 2: Runtime ──────────────────────────────────────────────────────────
48
- FROM python:3.12-slim-bookworm AS runtime
49
-
50
- # Labels for Docker Hub / GitHub Container Registry metadata
51
- LABEL org.opencontainers.image.title="CustomerCore API" \
52
- org.opencontainers.image.description="Enterprise B2B AI Customer Support Platform" \
53
- org.opencontainers.image.version="1.0.0" \
54
- org.opencontainers.image.authors="Saibalaji Namburi" \
55
- org.opencontainers.image.source="https://github.com/saibalajinamburi/CustomerCore"
56
 
57
  ENV PYTHONDONTWRITEBYTECODE=1 \
58
  PYTHONUNBUFFERED=1 \
59
  PYTHONPATH=/app \
60
  APP_ENV=production \
61
- PORT=8080
 
62
 
63
- # Runtime system dependencies
64
  RUN apt-get update && apt-get install -y --no-install-recommends \
65
  curl \
66
  && rm -rf /var/lib/apt/lists/*
67
 
68
- # Create non-root user (security best practice)
69
- # Running as root in a container is a major security risk:
70
- # if the container is compromised, root in the container = root on the host
71
- # when using certain Docker configurations.
72
- RUN groupadd -r customercore && useradd -r -g customercore customercore
73
 
74
  WORKDIR /app
75
 
76
- # Copy installed packages from builder stage
77
- COPY --from=builder /install /usr/local
 
 
 
78
 
79
- # Copy application source code
80
  COPY src/ ./src/
81
  COPY pyproject.toml .
82
 
83
- # Create directories that the app needs at runtime
84
- RUN mkdir -p logs data/bronze data/silver data/gold \
85
- && chown -R customercore:customercore /app
86
 
87
- # Switch to non-root user
88
- USER customercore
89
 
90
- # Health check β€” Docker checks this every 30s to know if the container is healthy
91
- # If it fails 3 times in a row, Docker marks the container as unhealthy
92
- HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
93
- CMD curl -f http://localhost:${PORT}/api/v1/health || exit 1
94
 
95
- # Expose the API port
96
- EXPOSE ${PORT}
97
 
98
- # Production server command:
99
- # - uvicorn: ASGI server for FastAPI
100
- # - workers: Set to CPU count (2 for HF Spaces, 4+ for Kubernetes)
101
- # - host 0.0.0.0: Listen on all interfaces (required in containers)
102
- # - log-level warning: Reduce noise (our structlog middleware handles request logging)
103
- # - no-access-log: Disabled β€” our middleware logs structured JSON instead
104
  CMD ["uvicorn", "src.api.main:app", \
105
  "--host", "0.0.0.0", \
106
- "--port", "8080", \
107
- "--workers", "2", \
108
- "--log-level", "warning", \
109
- "--no-access-log"]
 
1
  # ─────────────────────────────────────────────────────────────────────────────
2
+ # CustomerCore β€” Hugging Face Spaces Dockerfile (Phase 10)
3
  #
4
+ # WHY A SEPARATE DOCKERFILE FOR HF SPACES?
5
+ # HF Spaces has specific constraints:
6
+ # - 2 vCPUs, 16GB RAM on free tier (Zero GPU)
7
+ # - No JVM/JDK allowed on the smallest tier (PySpark requires 500MB+ JDK)
8
+ # - Container must listen on port 7860 (HF Spaces requirement)
9
+ # - No root user (HF runs as user 1000)
10
+ # - 50GB ephemeral storage (data is lost on restart β€” use Supabase for persistence)
11
  #
12
+ # This image strips PySpark and uses a lightweight requirements file.
13
+ # The API still works: BM25 retrieval, LLM routing, and LangGraph triage all function
14
+ # without PySpark. The Bronze→Silver data pipeline is not needed for inference.
15
  #
16
+ # HF Spaces deployment:
17
+ # 1. Create a new Space at huggingface.co/spaces
18
+ # 2. Select "Docker" as the SDK
19
+ # 3. Add this file as Dockerfile in the repo root
20
+ # 4. Set secrets in Space settings (same values as Doppler)
21
  # ─────────────────────────────────────────────────────────────────────────────
22
 
23
+ FROM python:3.12-slim-bookworm
 
24
 
25
+ LABEL org.opencontainers.image.title="CustomerCore API (HF Spaces)" \
26
+ org.opencontainers.image.description="CustomerCore β€” Lightweight deployment for Hugging Face Spaces" \
27
+ org.opencontainers.image.version="1.0.0"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  ENV PYTHONDONTWRITEBYTECODE=1 \
30
  PYTHONUNBUFFERED=1 \
31
  PYTHONPATH=/app \
32
  APP_ENV=production \
33
+ # HF Spaces requires port 7860
34
+ PORT=7860
35
 
 
36
  RUN apt-get update && apt-get install -y --no-install-recommends \
37
  curl \
38
  && rm -rf /var/lib/apt/lists/*
39
 
40
+ # HF Spaces runs as user 1000 β€” create matching user
41
+ RUN useradd -m -u 1000 hfuser
 
 
 
42
 
43
  WORKDIR /app
44
 
45
+ # Use the slim CI requirements file β€” already Linux-safe (no pywin32, pyspark, etc.)
46
+ COPY requirements-ci.txt .
47
+ RUN pip install --no-cache-dir \
48
+ --extra-index-url https://download.pytorch.org/whl/cpu \
49
+ -r requirements-ci.txt
50
 
 
51
  COPY src/ ./src/
52
  COPY pyproject.toml .
53
 
54
+ RUN mkdir -p logs data \
55
+ && chown -R hfuser:hfuser /app
 
56
 
57
+ USER hfuser
 
58
 
59
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \
60
+ CMD curl -f http://localhost:7860/api/v1/health || exit 1
 
 
61
 
62
+ EXPOSE 7860
 
63
 
64
+ # Single worker on HF free tier (2 vCPU)
 
 
 
 
 
65
  CMD ["uvicorn", "src.api.main:app", \
66
  "--host", "0.0.0.0", \
67
+ "--port", "7860", \
68
+ "--workers", "1", \
69
+ "--log-level", "warning"]