-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
73 lines (62 loc) · 3.54 KB
/
Copy pathDockerfile
File metadata and controls
73 lines (62 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# Single image, two roles. The WEB service (default CMD) runs the FastAPI app.
# The WORKER service (T1, Celery) runs the SAME image with a different start
# command — set on the Railway worker service (see railway.json + DEPLOY.md).
#
# Base: official slim Python 3.12. No ffmpeg: ingestion is captions-based
# (youtube-transcript-api / Supadata / yt-dlp SUBTITLE download) — nothing
# downloads or transcodes audio.
FROM python:3.12-slim AS base
# - PYTHONUNBUFFERED: logs stream immediately (Railway log tailing).
# - PYTHONDONTWRITEBYTECODE: no .pyc clutter in the image.
# - UV_* : install into the system env (no extra venv layer), reproducible,
# no bytecode compile at sync time.
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
UV_PROJECT_ENVIRONMENT=/usr/local \
UV_COMPILE_BYTECODE=0 \
UV_LINK_MODE=copy
# ca-certificates: TLS for OpenAI / YouTube. Clean apt lists to keep layers lean.
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# uv from the official static binary. Pin a SPECIFIC version (not :latest) so a
# future rebuild can't pull a uv that changes lockfile handling — uv's own Docker
# guide recommends version-pinning for reproducible builds. 0.10.7 matches the uv
# that generated uv.lock (version=1, revision=3). Lives in /usr/local/bin (PATH).
COPY --from=ghcr.io/astral-sh/uv:0.10.7 /uv /uvx /usr/local/bin/
WORKDIR /app
# Dependency layer: copy ONLY the manifests first so `uv sync` is cached and only
# re-runs when pyproject.toml / uv.lock change (not on every src/ edit).
# --frozen: fail if uv.lock is stale (reproducible builds, same as CI).
# --no-install-project: this repo ships code under src/ as plain modules (run via
# --app-dir src), not as an installed package, so we only need the deps here.
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev --no-install-project
# Application code. data/ is excluded via .dockerignore — the vector index is
# supplied at runtime by a Railway persistent volume mounted at /app/data/chroma
# (matches VectorStore's relative "data/chroma" default; see DEPLOY.md).
COPY src ./src
# Alembic migrations, so schema setup can run from the image itself (no host
# Python needed): docker compose run --rm web alembic upgrade head
# alembic/env.py resolves DATABASE_URL via rag.db.database_url(), i.e. the same
# env var the app uses — in compose that's the internal postgres service DNS.
COPY alembic.ini ./
COPY alembic ./alembic
# Railway injects $PORT at runtime; default to 8000 for local `docker run`.
ENV PORT=8000
EXPOSE 8000
# Default = WEB role. Bind 0.0.0.0 so the container is reachable; --app-dir src
# makes `import server`/`import rag` resolve without an editable install.
# Shell form so $PORT expands at container start (Railway sets it per-deploy).
CMD ["sh", "-c", "uvicorn server:app --app-dir src --host 0.0.0.0 --port ${PORT:-8000}"]
# --- WORKER role (Celery) ----------------------------------------------------
# src/worker.py exposes the Celery app (`worker.celery_app`) + the run_ingest
# task. The worker runs this SAME image with the start command overridden (on
# the Railway worker service and in docker-compose.yml's `worker` service):
#
# celery -A worker.celery_app worker --loglevel=info --concurrency=2
#
# Run it with PYTHONPATH=src so `import worker` resolves; the broker/result
# backend come from CELERY_BROKER_URL / CELERY_RESULT_BACKEND, falling back to
# REDIS_URL (see DEPLOY.md + docker-compose.yml). No Dockerfile change between
# the two roles; only the start command differs.