From f1ed5b6e232f9375490181ec1a2940bad92ea9b8 Mon Sep 17 00:00:00 2001 From: Steve Cliff Date: Fri, 21 Aug 2026 18:33:34 +0100 Subject: [PATCH] Split the torch layer and drop 7.8GB of orphaned CUDA libs from the CPU image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CPU image was 11.2GB — larger than the CUDA one — and its single 6.72GB torch layer could not be pushed at all: the registry drops any blob upload taking longer than 60s, and that layer needed ~61s. Both problems came from install ordering. Dockerfile.cpu installed the project and sentence-transformers first, which resolved the default CUDA torch and pulled ~2.7GB of nvidia-* wheels, then reinstalled torch from the CPU index. Reinstalling replaces torch but leaves its transitive CUDA dependencies behind, orphaned and unused (torch reports 2.13.0+cpu, cuda.is_available() False). Installing CPU torch first, from the CPU index, means nothing ever requests a CUDA build. Everything else then resolves against the torch already present. CPU image 11.2GB -> 3.43GB largest layer 6.72GB -> 896MB push failed 5/5 at 60s -> succeeds in 8.6s Dockerfile.nvidia gets the same split. Its torch layer is unavoidably large (~2.8GiB compressed, ~52s at current throughput) so it stays the tightest thing in the stack, but splitting the application install off keeps that layer cached and the app layer small. Both now install torch before the source COPYs, so editing application code no longer invalidates the multi-GB layer. Co-Authored-By: Claude Opus 5 (1M context) --- engine/Dockerfile.cpu | 24 ++++++++++++++++++++---- engine/Dockerfile.nvidia | 15 ++++++++++++--- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/engine/Dockerfile.cpu b/engine/Dockerfile.cpu index cb79b59..be9aa27 100644 --- a/engine/Dockerfile.cpu +++ b/engine/Dockerfile.cpu @@ -13,16 +13,32 @@ COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv WORKDIR /app +# Install CPU torch first, on its own, from the CPU index. +# +# Order matters: anything that depends on torch (sentence-transformers) will +# otherwise resolve the default CUDA build and pull ~2.7GB of nvidia-* wheels. +# Reinstalling torch afterwards replaces torch but leaves those wheels behind, +# orphaned and unused — which is how the CPU image ended up larger than the +# CUDA one. Installing CPU torch up front means nothing ever requests CUDA. +# +# Keeping it in its own layer also bounds the blob size: the registry drops +# uploads that take longer than 60s, so no single layer should approach ~3GB. +# Placing it before the source COPYs keeps this expensive layer cached when +# only application code changes. +RUN uv venv .venv && \ + . .venv/bin/activate && \ + UV_HTTP_TIMEOUT=600 uv pip install torch torchvision \ + --index-url https://download.pytorch.org/whl/cpu + COPY pyproject.toml ./ COPY kb/ kb/ COPY main.py ./ COPY VERSION ./ -RUN uv venv .venv && \ - . .venv/bin/activate && \ - uv pip install -e . && \ +# Remaining dependencies resolve against the CPU torch already present. +RUN . .venv/bin/activate && \ uv pip install "sentence-transformers[onnx]" && \ - uv pip install --reinstall torch torchvision --index-url https://download.pytorch.org/whl/cpu + uv pip install -e . ENV PATH="/app/.venv/bin:$PATH" ENV VIRTUAL_ENV="/app/.venv" diff --git a/engine/Dockerfile.nvidia b/engine/Dockerfile.nvidia index e9f602c..e1de270 100644 --- a/engine/Dockerfile.nvidia +++ b/engine/Dockerfile.nvidia @@ -13,14 +13,23 @@ COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv WORKDIR /app +# Install CUDA torch on its own, before the source COPYs. +# +# This is the bulk of the image (~2.8GiB compressed). Splitting it from the +# application install keeps it cached when only code changes, and keeps the +# app layer small. The registry drops any blob upload that takes longer than +# 60s, so this layer is deliberately the only large one. +RUN uv venv .venv && \ + . .venv/bin/activate && \ + UV_HTTP_TIMEOUT=600 uv pip install torch torchvision \ + --index-url https://download.pytorch.org/whl/cu130 + COPY pyproject.toml ./ COPY kb/ kb/ COPY main.py ./ COPY VERSION ./ -RUN uv venv .venv && \ - . .venv/bin/activate && \ - UV_HTTP_TIMEOUT=600 uv pip install torch torchvision --index-url https://download.pytorch.org/whl/cu130 && \ +RUN . .venv/bin/activate && \ uv pip install -e . ENV PATH="/app/.venv/bin:$PATH"