finrag-api / Dockerfile
sharmaaryan's picture
Embedded Qdrant vector store (no external cluster)
a8bc5d0
Raw
History Blame Contribute Delete
2.49 kB
# FinRAG backend image β€” portable across hosts (Hugging Face Spaces, Render,
# Cloud Run, local). Build context = repo ROOT (it needs backend/ + data/):
# docker build -t finrag-api .
#
# Image layout mirrors the dev tree so REPO_ROOT resolves identically:
# config.py at /app/backend/src/finrag/config.py β†’ parents[3] == /app
# β†’ DuckDB + BM25 (REPO_ROOT/data/...) live at /app/data. WORKDIR=/app keeps
# settings.duckdb_path ("./data/...") valid too.
#
# Port: listens on $PORT if the host injects one (Render/Cloud Run), else 8000.
# On Hugging Face Spaces, declare `app_port: 8000` in the Space README frontmatter.
# ---- builder: resolve + install deps into a venv (no ingestion/dev groups) ----
FROM python:3.11-slim AS builder
COPY --from=ghcr.io/astral-sh/uv:0.11.15 /uv /uvx /bin/
ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
WORKDIR /app/backend
COPY backend/pyproject.toml backend/uv.lock ./
RUN uv sync --frozen --no-install-project --no-dev
COPY backend/ ./
RUN uv sync --frozen --no-dev
# ---- runtime: slim, non-root ----
FROM python:3.11-slim AS runtime
# libgomp1 covers numpy/rank-bm25's OpenMP dependency on slim.
RUN apt-get update && apt-get install -y --no-install-recommends libgomp1 \
&& rm -rf /var/lib/apt/lists/*
RUN useradd -m -u 1000 appuser
WORKDIR /app
# Installed venv + editable project source (finrag β†’ backend/src), then the two
# runtime data artifacts (Qdrant vectors live in the cloud cluster, not here).
COPY --from=builder --chown=appuser:appuser /app/backend /app/backend
COPY --chown=appuser:appuser data/duckdb /app/data/duckdb
COPY --chown=appuser:appuser data/bm25_index.pkl /app/data/bm25_index.pkl
# Embedded Qdrant vector store β€” baked in like DuckDB/BM25 so the image is fully
# self-contained (no external cluster to idle-wipe, no QDRANT_URL/KEY secret).
COPY --chown=appuser:appuser data/qdrant /app/data/qdrant
ENV PATH="/app/backend/.venv/bin:$PATH" \
PYTHONUNBUFFERED=1 \
PYTHONIOENCODING=utf-8 \
QDRANT_PATH=./data/qdrant \
PORT=8000
USER appuser
EXPOSE 8000
# Healthcheck honors $PORT so it stays correct on any host.
HEALTHCHECK --interval=30s --timeout=5s --start-period=25s --retries=3 \
CMD python -c "import os,sys,urllib.request; p=os.environ.get('PORT','8000'); sys.exit(0 if urllib.request.urlopen(f'http://localhost:{p}/health',timeout=3).status==200 else 1)"
# Shell form so ${PORT} expands at runtime.
CMD ["sh", "-c", "uvicorn finrag.main:app --host 0.0.0.0 --port ${PORT:-8000}"]