diff --git a/backend/Dockerfile b/backend/Dockerfile index 5213bb00c50..84c90e16f67 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -4,6 +4,33 @@ ARG UV_IMAGE=ghcr.io/astral-sh/uv:0.11.7@sha256:240fb85ab0f263ef12f492d8476aa3a2 FROM $UV_IMAGE AS uvbin +# ---------- Rust extension ---------- +# Copies only the native build's inputs, so the fat-LTO compile stays cached across Python-only changes +FROM $LITELLM_BUILD_IMAGE AS rust-native + +WORKDIR /app +USER root + +COPY --from=uvbin /uv /uvx /usr/local/bin/ + +RUN for i in 1 2 3; do \ + apk add --no-cache bash gcc python-3.13 python-3.13-dev openssl openssl-dev && break; \ + [ $i = 3 ] && { echo "apk add failed after 3 retries" >&2; exit 1; }; \ + sleep 5; \ + done + +ENV UV_PYTHON_DOWNLOADS=0 + +COPY pyproject.toml README.md rust-toolchain.toml ./ +COPY .cargo ./.cargo +COPY litellm-rust ./litellm-rust + +RUN --mount=type=cache,target=/root/.cache/uv \ + mkdir -p litellm/rust_bridge /wheels && \ + touch litellm/__init__.py litellm/rust_bridge/__init__.py && \ + uvx --python python3.13 --from maturin==1.15.0 --with puccinialin==0.1.14 \ + python -c "import maturin; maturin.build_wheel('/wheels')" + # ---------- Builder ---------- FROM $LITELLM_BUILD_IMAGE AS builder @@ -54,7 +81,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \ COPY . . RUN --mount=type=cache,target=/root/.cache/uv \ - uv sync --frozen --no-default-groups --no-editable \ + uv sync --frozen --no-install-project --no-default-groups --no-editable \ --extra proxy \ --extra proxy-runtime \ --group admin-mcp \ @@ -63,6 +90,9 @@ RUN --mount=type=cache,target=/root/.cache/uv \ --extra saml \ --python python3.13 +RUN --mount=type=bind,from=rust-native,source=/wheels,target=/wheels \ + uv pip install --python /app/.venv/bin/python --no-deps /wheels/litellm-*.whl + RUN cp "$(python -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])')"/litellm/rust_bridge/_native*.so litellm/rust_bridge/ RUN HOME=/opt/prisma XDG_CACHE_HOME=/opt/prisma/.cache PRISMA_BINARY_CACHE_DIR=/opt/prisma/binaries \ diff --git a/gateway/Dockerfile b/gateway/Dockerfile index ee45f293ef8..051b1c30c8f 100644 --- a/gateway/Dockerfile +++ b/gateway/Dockerfile @@ -20,6 +20,33 @@ RUN curl -fsSL -o pgbouncer.tar.gz "https://www.pgbouncer.org/downloads/files/${ make -j"$(nproc)" pgbouncer && \ install -m 0755 pgbouncer /usr/local/bin/pgbouncer +# ---------- Rust extension ---------- +# Copies only the native build's inputs, so the fat-LTO compile stays cached across Python-only changes +FROM $LITELLM_BUILD_IMAGE AS rust-native + +WORKDIR /app +USER root + +COPY --from=uvbin /uv /uvx /usr/local/bin/ + +RUN for i in 1 2 3; do \ + apk add --no-cache bash gcc python-3.13 python-3.13-dev openssl openssl-dev && break; \ + [ $i = 3 ] && { echo "apk add failed after 3 retries" >&2; exit 1; }; \ + sleep 5; \ + done + +ENV UV_PYTHON_DOWNLOADS=0 + +COPY pyproject.toml README.md rust-toolchain.toml ./ +COPY .cargo ./.cargo +COPY litellm-rust ./litellm-rust + +RUN --mount=type=cache,target=/root/.cache/uv \ + mkdir -p litellm/rust_bridge /wheels && \ + touch litellm/__init__.py litellm/rust_bridge/__init__.py && \ + uvx --python python3.13 --from maturin==1.15.0 --with puccinialin==0.1.14 \ + python -c "import maturin; maturin.build_wheel('/wheels')" + # ---------- Builder ---------- FROM $LITELLM_BUILD_IMAGE AS builder @@ -66,11 +93,11 @@ RUN --mount=type=cache,target=/root/.cache/uv \ --extra bedrock-realtime \ --python python3.13 -# Stage 2 — copy source and install the project + workspace members. +# Stage 2 — copy source and install the workspace members. COPY . . RUN --mount=type=cache,target=/root/.cache/uv \ - uv sync --frozen --no-default-groups --no-editable \ + uv sync --frozen --no-install-project --no-default-groups --no-editable \ --extra proxy \ --extra proxy-runtime \ --group admin-mcp \ @@ -79,6 +106,9 @@ RUN --mount=type=cache,target=/root/.cache/uv \ --extra bedrock-realtime \ --python python3.13 +RUN --mount=type=bind,from=rust-native,source=/wheels,target=/wheels \ + uv pip install --python /app/.venv/bin/python --no-deps /wheels/litellm-*.whl + # PYTHONPATH=/app makes the source tree shadow the installed package, so the # compiled Rust extension must live next to the source or it is never imported. RUN cp "$(python -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])')"/litellm/rust_bridge/_native*.so litellm/rust_bridge/ diff --git a/migrations/Dockerfile b/migrations/Dockerfile index 255b94b0ea8..b39a9bfa9bf 100644 --- a/migrations/Dockerfile +++ b/migrations/Dockerfile @@ -24,6 +24,32 @@ FROM $UV_IMAGE AS uvbin # under nodeenv. Crucially we do NOT run `prisma generate` at RUNTIME; the # old migration job did, on every pod start, which is the wasteful behaviour # the componentization is fixing. +# Copies only the native build's inputs, so the fat-LTO compile stays cached across Python-only changes +FROM $LITELLM_BUILD_IMAGE AS rust-native + +WORKDIR /app +USER root + +COPY --from=uvbin /uv /uvx /usr/local/bin/ + +RUN for i in 1 2 3; do \ + apk add --no-cache bash gcc python-3.13 python-3.13-dev openssl openssl-dev && break; \ + [ $i = 3 ] && { echo "apk add failed after 3 retries" >&2; exit 1; }; \ + sleep 5; \ + done + +ENV UV_PYTHON_DOWNLOADS=0 + +COPY pyproject.toml README.md rust-toolchain.toml ./ +COPY .cargo ./.cargo +COPY litellm-rust ./litellm-rust + +RUN --mount=type=cache,target=/root/.cache/uv \ + mkdir -p litellm/rust_bridge /wheels && \ + touch litellm/__init__.py litellm/rust_bridge/__init__.py && \ + uvx --python python3.13 --from maturin==1.15.0 --with puccinialin==0.1.14 \ + python -c "import maturin; maturin.build_wheel('/wheels')" + FROM $LITELLM_BUILD_IMAGE AS builder WORKDIR /app @@ -58,15 +84,18 @@ RUN --mount=type=cache,target=/root/.cache/uv \ --extra extra_proxy \ --python python3.13 -# Stage 2 — copy source and install the project + workspace members. +# Stage 2 — copy source and install the workspace members. COPY . . RUN --mount=type=cache,target=/root/.cache/uv \ - uv sync --frozen --no-default-groups --no-editable \ + uv sync --frozen --no-install-project --no-default-groups --no-editable \ --extra proxy \ --extra extra_proxy \ --python python3.13 +RUN --mount=type=bind,from=rust-native,source=/wheels,target=/wheels \ + uv pip install --python /app/.venv/bin/python --no-deps /wheels/litellm-*.whl + RUN cp "$(python -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])')"/litellm/rust_bridge/_native*.so litellm/rust_bridge/ COPY migrations/run.py /app/run.py