Repository navigation
Expand file tree
/
Copy pathDockerfile
More file actions
68 lines (59 loc) · 3.09 KB
/
Copy pathDockerfile
File metadata and controls
68 lines (59 loc) · 3.09 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
# The standalone serving image: tabctx + tabicl + tabpfn + torch, serving
# `python -m tabctx.serve` (serve/standalone.py) -- no Ray. Built and
# pushed by .github/workflows/docker_image.yml on each release tag, and
# smoke-tested there against the fake backend (no GPU in CI).
#
# Base: plain python:3.12-slim, not a pytorch/cuda image. torch's PyPI
# wheels bundle the CUDA runtime libraries; only the driver comes from
# the host, injected by the NVIDIA container toolkit that any Kubernetes
# GPU device plugin already requires. This keeps the Python version ours
# (tabctx needs >= 3.12; the pytorch images pin their own) and the torch
# version an explicit, overridable pin instead of whatever a base image
# carried. GPU validation is the deploying platform's rehearsal, by
# design: CI has no GPU.
#
# Weights are NOT baked in. Deployments mount them read-only and load
# offline, e.g.:
# TABPFN_MODEL_CACHE_DIR=/model-weights/tabctx/tabpfn
# HF_HUB_CACHE=/model-weights/tabctx/hf/hub HF_HUB_OFFLINE=1
#
# Runs as a non-root user with no sudo anywhere in the image (lesson of
# an upstream deployment's 2026-09-01 incident: an in-container RCE must
# not get root for free).
ARG PYTHON_IMAGE=python:3.12-slim-bookworm
FROM ${PYTHON_IMAGE}
# torch is deliberately pinned here, not in pyproject (the library runs
# on whatever torch its host provides; the image must be reproducible).
ARG TORCH_VERSION=2.9.1
COPY --from=ghcr.io/astral-sh/uv:0.9 /uv /usr/local/bin/uv
# A C compiler for Triton: torch.compile (TABCTX_COMPILE, on by default)
# builds a small C helper at runtime and, without one, silently falls back
# to eager kernels, about 1.3x slower. The base image ships the Python
# headers it also needs.
RUN apt-get update \
&& apt-get install -y --no-install-recommends gcc libc6-dev \
&& rm -rf /var/lib/apt/lists/*
RUN useradd --create-home --uid 10001 tabctx
WORKDIR /opt/tabctx
COPY pyproject.toml uv.lock README.md LICENSE.md ./
COPY src ./src
# Every dependency at its uv.lock version, so a PR's smoke build and the
# release build ship the same model libraries. Except torch: the lock
# carries whatever torch the dev environment resolved, and the image keeps
# its own pin, so torch and the CUDA libraries and Triton it pins exactly
# are dropped from the export and resolved with the pin instead. One
# resolution for both, so the extras' unpinned `torch` and the pin cannot
# diverge. The project itself goes in last, without re-resolving.
RUN uv export --frozen --no-dev --no-hashes --no-emit-project \
--extra standalone --extra tabicl --extra tabpfn -o /tmp/locked.txt \
&& grep -v -E '^(torch|triton|nvidia-)' /tmp/locked.txt > /tmp/requirements.txt \
&& uv pip install --system --no-cache \
"torch==${TORCH_VERSION}" -r /tmp/requirements.txt \
&& uv pip install --system --no-cache --no-deps . \
&& rm /tmp/locked.txt /tmp/requirements.txt
USER tabctx
WORKDIR /home/tabctx
EXPOSE 8000
# --host 0.0.0.0: the container is reached through a Service; the
# standalone default (127.0.0.1) is for processes on a shared host.
ENTRYPOINT ["python", "-m", "tabctx.serve", "--host", "0.0.0.0"]