headroom_2 / Dockerfile
tudragon154203
merge dev: dockerignore Rust artifacts, cost tracker, image compressor close
6eb6419
Raw
History Blame Contribute Delete
5.82 kB
ARG PYTHON_VERSION=3.11
ARG UV_VERSION=0.6.17
# Rebuilt: 2026-06-02 — force Docker cache invalidation for Redis stats fix
# Pinned 2026-04-15. Update via Dependabot or: docker pull python:3.11-slim
ARG PYTHON_DIGEST=sha256:233de06753d30d120b1a3ce359d8d3be8bda78524cd8f520c99883bfe33964cf
ARG BASE_IMAGE=python:${PYTHON_VERSION}-slim@${PYTHON_DIGEST}
# Pinned 2026-04-15. Update via Dependabot or: docker pull gcr.io/distroless/python3-debian13
ARG DISTROLESS_DIGEST=sha256:ed3a4beb46f8f8baac068743ba1b1f95ea3f793422129cf6dd23967f779b6018
ARG DISTROLESS_IMAGE=gcr.io/distroless/python3-debian13
ARG PYTHON_SITE_PACKAGES=/usr/local/lib/python${PYTHON_VERSION}/site-packages
# ---- Build stage: compile native extensions, build wheel ----
FROM python:${PYTHON_VERSION}-slim@${PYTHON_DIGEST} AS builder
ARG UV_VERSION
ARG PYTHON_SITE_PACKAGES
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
g++ \
curl \
libssl-dev \
pkg-config \
unzip \
&& rm -rf /var/lib/apt/lists/*
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal --default-toolchain stable
ENV PATH="/root/.cargo/bin:${PATH}"
RUN python -m pip install --no-cache-dir uv==${UV_VERSION} maturin
WORKDIR /build
# Layer 1: install deps only (cached unless pyproject.toml/uv.lock change)
COPY pyproject.toml uv.lock README.md ./
# Stub package so uv can resolve the local extras without full source
RUN mkdir -p headroom && touch headroom/__init__.py
ARG HEADROOM_EXTRAS=proxy,code,ml
# Install base extras, then swap onnxruntime for GPU variant if requested.
# When gpu extra is set, torch (from [ml]) pulls nvidia-*-cu13 packages.
# onnxruntime-gpu needs CUDA 12 libs (.so.12), so we force-install the cu12
# variants alongside cu13 — they coexist in separate site-packages dirs.
RUN --mount=type=cache,target=/root/.cache/uv \
UV_HTTP_TIMEOUT=300 uv pip install --system ".[${HEADROOM_EXTRAS}]" && \
if echo "${HEADROOM_EXTRAS}" | grep -q gpu; then \
uv pip uninstall --system onnxruntime && \
UV_HTTP_TIMEOUT=300 uv pip install --system --force-reinstall \
"onnxruntime-gpu>=1.16.0" \
"nvidia-cublas-cu12>=12.0" \
"nvidia-cuda-runtime-cu12>=12.0" \
"nvidia-cudnn-cu12>=9.0" \
"nvidia-cufft-cu12>=11.0" \
"nvidia-cuda-nvrtc-cu12>=12.0"; \
fi
# Layer 2: copy real source, reinstall only headroom-ai (no deps), then build
# the Rust extension via maturin build (no venv needed — uses system Python).
COPY headroom/ headroom/
COPY Cargo.toml Cargo.lock ./
COPY crates/ crates/
COPY scripts/build_rust_extension.sh scripts/build_rust_extension.sh
COPY .cargo/ .cargo/
RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install --system --no-deps --reinstall-package headroom-ai . && \
bash ./scripts/build_rust_extension.sh
# ---- Runtime stage: python-slim with CUDA 12 + 13 pip libs ----
FROM ${BASE_IMAGE} AS runtime-slim-base
ARG RUNTIME_USER=nonroot
ARG PYTHON_VERSION
ARG PYTHON_SITE_PACKAGES
RUN apt-get update && \
apt-get install -y --no-install-recommends curl libgomp1 && \
rm -rf /var/lib/apt/lists/*
# Copy site-packages from builder (includes nvidia-*-cu12 + cu13 pip libs).
COPY --from=builder ${PYTHON_SITE_PACKAGES} ${PYTHON_SITE_PACKAGES}
# Copy Rust extension binary built by maturin into site-packages.
COPY --from=builder /build/headroom/_core*.so /build/headroom/_core*.pyd /build/headroom/_core*.dylib /usr/local/lib/python${PYTHON_VERSION}/site-packages/headroom/ 2>/dev/null || true
# Create headroom CLI entrypoint — exec python3 from this image's PATH.
RUN echo '#!/bin/sh' > /usr/local/bin/headroom && \
echo 'exec python3 -m headroom.cli "$@"' >> /usr/local/bin/headroom && \
chmod +x /usr/local/bin/headroom
RUN mkdir -p /home/nonroot /data && \
if [ "$RUNTIME_USER" = "nonroot" ]; then \
groupadd --gid 1000 nonroot && \
useradd --uid 1000 --gid nonroot --create-home nonroot && \
mkdir -p /home/nonroot/.headroom && \
chown -R nonroot:nonroot /data /home/nonroot; \
else \
mkdir -p /root/.headroom; \
fi
USER ${RUNTIME_USER}
WORKDIR /home/nonroot
ENV HEADROOM_HOST=0.0.0.0 \
HEADROOM_PORT=7860 \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
LD_LIBRARY_PATH=${PYTHON_SITE_PACKAGES}/nvidia/cublas/lib:${PYTHON_SITE_PACKAGES}/nvidia/cuda_runtime/lib:${PYTHON_SITE_PACKAGES}/nvidia/cudnn/lib:${PYTHON_SITE_PACKAGES}/nvidia/cufft/lib:${PYTHON_SITE_PACKAGES}/nvidia/curand/lib:${PYTHON_SITE_PACKAGES}/nvidia/cuda_nvrtc/lib
EXPOSE 7860
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD curl --fail --silent "http://127.0.0.1:${HEADROOM_PORT:-7860}/readyz"
ENTRYPOINT ["headroom", "proxy"]
FROM ${DISTROLESS_IMAGE}@${DISTROLESS_DIGEST} AS runtime-slim
ARG RUNTIME_USER=nonroot
ARG PYTHON_SITE_PACKAGES
COPY --from=builder ${PYTHON_SITE_PACKAGES} ${PYTHON_SITE_PACKAGES}
USER ${RUNTIME_USER}
WORKDIR /app
ENV HEADROOM_HOST=0.0.0.0 \
HEADROOM_PORT=7860 \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONPATH=${PYTHON_SITE_PACKAGES} \
LD_LIBRARY_PATH=${PYTHON_SITE_PACKAGES}/nvidia/cublas/lib:${PYTHON_SITE_PACKAGES}/nvidia/cuda_runtime/lib:${PYTHON_SITE_PACKAGES}/nvidia/cudnn/lib:${PYTHON_SITE_PACKAGES}/nvidia/cufft/lib:${PYTHON_SITE_PACKAGES}/nvidia/curand/lib:${PYTHON_SITE_PACKAGES}/nvidia/cuda_nvrtc/lib
EXPOSE 7860
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD ["python3", "-c", "import os, urllib.request; port = os.environ.get('HEADROOM_PORT', '7860'); urllib.request.urlopen(f'http://127.0.0.1:{port}/readyz', timeout=5)"]
ENTRYPOINT ["python3", "-m", "headroom.cli", "proxy"]
# Default published image remains python-slim runtime
FROM runtime-slim-base AS runtime