apex-backend / Dockerfile
ssookra's picture
wave-51d cascade-#60 OTel install + manual middleware fallback (observability.py + Dockerfile + full apex tree sync)
027ca33 verified
Raw
History Blame
5.13 kB
# APEX backend container (Phase 5 task 5.2 + wave-48 deploy fixes)
#
# Build:
# docker build -t apex-backend:0.2.0 app/backend
#
# Run (local):
# docker run --rm -p 8000:8000 \
# -v ${PWD}/fixtures:/srv/fixtures:ro \
# -e APEX_AUDIT_LOG_PATH=/srv/audit/audit-log.jsonl \
# -e OPENROUTER_API_KEY=$OPENROUTER_API_KEY \
# apex-backend:0.2.0
#
# Smoke (after `docker run`):
# curl http://localhost:8000/healthz
# curl http://localhost:8000/api/session-context
# curl http://localhost:8000/api/orchestration
#
# Production deploy targets (per Phase 5 task 5.1):
# - HuggingFace Spaces (Docker SDK, free CPU tier)
# 1. Create Space at huggingface.co/new-space (Docker SDK, CPU basic)
# 2. Copy app/backend/* + fixtures/ into the Space repo
# 3. Add README.md HF Spaces frontmatter (see app/backend/README.md)
# 4. git push to huggingface.co; Spaces builds + serves automatically
# - Fly.io: `fly launch --no-deploy --image apex-backend:0.2.0`
# - Modal: `modal deploy` from a wrapped `modal.Image.from_dockerfile()`
#
# wave-48 fixes vs the v0.1.0 Dockerfile:
# 1. `pip install -r requirements.txt` for real (was pinning only 4
# packages by name; cvxpylayers + transformers were silently
# missing). Skipped torch+cuda; install CPU torch separately for
# size.
# 2. `COPY fixtures` so `/api/analyze` + `/api/orchestration` can
# resolve `fixtures/personas/sarah-reynolds-*` on a fresh
# container (was 503-ing because fixtures were dev-only).
# 3. HEALTHCHECK extended to 60s start period to accommodate TTM lazy
# load when `APEX_ENABLE_TTM=1`.
FROM python:3.11-slim AS base
# --- system deps -------------------------------------------------------
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
git \
curl \
build-essential \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /srv/app
# --- python deps (light layer; CPU torch only, no cuda) ---------------
# Install CPU-only torch first (much smaller than CUDA wheel; CPU is
# what HF Spaces free tier provides). cvxpy + cvxpylayers + scs +
# clarabel + transformers + granite-tsfm + httpx all install via the
# main requirements.txt pin.
COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir --upgrade pip wheel setuptools
RUN pip install --no-cache-dir torch==2.5.1 --index-url https://download.pytorch.org/whl/cpu
# requirements.txt was authored against Vinh's Windows+CUDA env; filter
# out the torch line + install the rest. Anything we don't need at
# runtime (llama_cpp_python is heavy + only used by the offline G1b
# bench script, never by the FastAPI server) is dropped via the grep.
# OpenTelemetry packages excluded from the lean install because
# opentelemetry-instrumentation 0.60b0 pins wrapt<2.0.0 which conflicts
# with Vinh's wrapt==2.2.1 pin. observability.py lazy-imports OTel +
# logs a no-op warning when the packages are absent, so the server
# still boots cleanly without them. Reinstate when an OTel release
# accepts wrapt 2.x.
RUN grep -vE "^(torch==|llama_cpp_python==|fastf1==|opentelemetry-)" requirements.txt > requirements.lean.txt \
&& pip install --no-cache-dir -r requirements.lean.txt \
&& pip install --no-cache-dir \
fastapi \
"uvicorn[standard]" \
python-multipart \
structlog
# Wave-51d cascade-#60: install OTel packages needed for Honeycomb wire-up.
# Skipping opentelemetry-instrumentation-fastapi due to wrapt<2.0 peer dep
# vs Vinh's wrapt==2.2.1 pin (see comment above). observability.py wave-51d
# falls back to manual request-tracing middleware when FastAPIInstrumentor
# missing; still ships per-request spans with HTTP method + path + status.
RUN pip install --no-cache-dir \
opentelemetry-api==1.39.0 \
opentelemetry-sdk==1.39.0 \
opentelemetry-exporter-otlp-proto-http==1.39.0
# --- app code + fixtures ----------------------------------------------
# COPY assumes the build context contains: apex/ + fixtures/ + (optional)
# docs/. For HF Spaces deploy, the deploy script symlinks/copies
# fixtures from `../../fixtures` into the build context first; for
# repo-root `docker build -f app/backend/Dockerfile .` the COPY paths
# below still resolve. Local-only `docker build app/backend` requires
# `cp -r ../../fixtures app/backend/fixtures` BEFORE building.
COPY apex apex
COPY fixtures /srv/app/fixtures
# --- runtime ----------------------------------------------------------
ENV PYTHONPATH=/srv/app \
APEX_AUDIT_LOG_PATH=/srv/audit/audit-log.jsonl \
APEX_FIXTURES_DIR=/srv/app/fixtures \
APEX_COMMIT_SHA=container \
APEX_ENABLE_TTM=0 \
PYTHONUNBUFFERED=1
RUN mkdir -p /srv/audit && chmod 0777 /srv/audit
EXPOSE 7860 8000
# HF Spaces routes traffic to port 7860 by default; uvicorn binds both
# to keep local docker-run + Fly.io + HF Spaces all happy.
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s \
CMD curl -fsS http://localhost:${PORT:-7860}/healthz || curl -fsS http://localhost:8000/healthz || exit 1
CMD ["sh", "-c", "uvicorn apex.server:app --host 0.0.0.0 --port ${PORT:-7860}"]