diff --git a/.gitignore b/.gitignore index 1bf8b06..4517f7e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ dist/ build/ *.log /tmp/ +.claude/ # uv # uv.lock is committed intentionally for reproducible builds. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8ecc39f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,66 @@ +# InfoXtractor container image. +# +# Base image ships CUDA 12.4 runtime libraries so the Surya OCR client can +# use the RTX 3090 on the deploy host. Ubuntu 22.04 is the LTS used across +# the home-server stack (immich-ml, monitoring) so GPU drivers line up. +FROM nvidia/cuda:12.4.0-runtime-ubuntu22.04 + +ENV DEBIAN_FRONTEND=noninteractive \ + PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + PIP_NO_CACHE_DIR=1 \ + PIP_DISABLE_PIP_VERSION_CHECK=1 + +# --- System deps -------------------------------------------------------- +# - python3.12 via deadsnakes PPA (pinned; Ubuntu 22.04 ships 3.10 only) +# - libmagic1 : python-magic backend for MIME sniffing +# - libgl1 : libGL.so needed by Pillow/OpenCV wheels used by Surya +# - libglib2.0 : shared by Pillow/PyMuPDF headless rendering +# - curl : post-receive hook's /healthz probe & general ops +# - ca-certs : httpx TLS verification +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + software-properties-common \ + ca-certificates \ + curl \ + gnupg \ + && add-apt-repository -y ppa:deadsnakes/ppa \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + python3.12 \ + python3.12-venv \ + python3.12-dev \ + python3-pip \ + libmagic1 \ + libgl1 \ + libglib2.0-0 \ + && ln -sf /usr/bin/python3.12 /usr/local/bin/python \ + && ln -sf /usr/bin/python3.12 /usr/local/bin/python3 \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# --- uv (dependency resolver used by the project) ----------------------- +RUN python -m pip install --upgrade pip \ + && python -m pip install "uv>=0.4" + +WORKDIR /app + +# Copy just the dependency manifests first so the heavy `uv sync` layer +# caches whenever only application code changes. +COPY pyproject.toml uv.lock .python-version ./ + +# Prod + OCR extras, no dev tooling. --frozen means "must match uv.lock"; +# CI catches drift before it reaches the image. +RUN uv sync --frozen --no-dev --extra ocr + +# --- Application code --------------------------------------------------- +COPY src src +COPY alembic alembic +COPY alembic.ini ./ + +EXPOSE 8994 + +# Migrations are idempotent (alembic upgrade head is a no-op on a current +# DB) so running them on every start keeps the image + DB aligned without +# an extra orchestration step. +CMD ["sh", "-c", "uv run alembic upgrade head && uv run uvicorn ix.app:create_app --factory --host 0.0.0.0 --port 8994"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9fabae8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,35 @@ +# InfoXtractor Docker Compose stack. +# +# Single service. Postgres + Ollama live in separate long-running +# containers on the host (postgis + ollama); we reach them via +# `host.docker.internal`, which is mapped to the gateway through +# `extra_hosts` so the container works whether the Compose plugin version +# adds it automatically or not. +# +# The GPU reservation block matches the shape used by immich-ml / +# monitoring on the same host, so the existing NVIDIA runtime +# configuration applies without changes. + +services: + infoxtractor: + build: . + container_name: infoxtractor + restart: always + ports: + - "8994:8994" + env_file: .env + runtime: nvidia + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: 1 + capabilities: [gpu] + labels: + infrastructure.web_url: "http://192.168.68.42:8994" + backup.enable: "true" + backup.type: "postgres" + backup.name: "infoxtractor" + extra_hosts: + - "host.docker.internal:host-gateway"