[CI] Preserve Rust Docker cache across commits (#53290)
Signed-off-by: mgoin <mgoin64@gmail.com> Co-authored-by: OpenAI Codex <codex@openai.com>
Misha Goin committed
Aug 25, 2026 at 14:13 UTC
c9331d8064808e3402ec79ae8631f48cebdc827a
5 files changed
+50
-25
docker/Dockerfile
+12
-10
@@ -253,7 +253,7 @@ ENV TORCH_CUDA_ARCH_LIST=${torch_cuda_arch_list}
253
# build stage doesn't need the rust toolchain or the rust source.
254
# This stage reuses the Python environment from base and runs in parallel with
255
# csrc-build/extensions-build.
256
-FROM base AS rust-build
256
+FROM base AS rust-build-cache
257
ARG USE_SCCACHE
258
ARG SCCACHE_ENDPOINT
259
@@ -283,26 +283,28 @@ ENV CARGO_BUILD_JOBS=4
283
# separate local sccache daemon while sharing the same remote cache backend.
284
ENV SCCACHE_SERVER_PORT=4227
285
286
-# Only Rust inputs are present, so suppress the artificial dirty state caused
287
-# by other tracked files being absent from this build stage.
288
-ENV SETUPTOOLS_SCM_PRETEND_METADATA={dirty=false}
289
-
290
-# Build the release artifacts. Cache cargo registry/git, but not target/,
291
-# because stale target metadata can outlive source updates across BuildKit
292
-# cache reuse.
286
+# Build with a stable version so this target snapshot is keyed only by Rust
287
+# inputs. The child stage below relinks the crates that embed the exact version.
288
RUN --mount=type=cache,target=/root/.cargo/registry,sharing=locked \
289
--mount=type=cache,target=/root/.cargo/git,sharing=locked \
295
- --mount=type=bind,source=.git,target=.git \
290
--mount=type=secret,id=aws-credentials,target=/root/.aws/credentials,required=false \
291
if [ "$USE_SCCACHE" = "1" ]; then \
292
if [ -n "${SCCACHE_ENDPOINT}" ]; then export SCCACHE_ENDPOINT="${SCCACHE_ENDPOINT}"; fi; \
293
export RUSTC_WRAPPER=sccache; \
294
sccache --show-stats; \
295
fi \
302
- && bash build_rust.sh \
296
+ && SETUPTOOLS_SCM_PRETEND_VERSION="0.0.0+docker.cache" bash build_rust.sh \
297
&& if [ "$USE_SCCACHE" = "1" ]; then \
298
sccache --show-stats; \
299
fi
300
+
301
+# Relink with the exact Git-derived package version.
302
+FROM rust-build-cache AS rust-build
303
+
304
+RUN --mount=type=cache,target=/root/.cargo/registry,sharing=locked \
305
+ --mount=type=cache,target=/root/.cargo/git,sharing=locked \
306
+ --mount=type=bind,source=.git,target=.git \
307
+ SETUPTOOLS_SCM_PRETEND_METADATA="{dirty=false}" bash build_rust.sh
308
#################### RUST BUILD IMAGE ####################
309
310
#################### CSRC BUILD IMAGE ####################
docker/Dockerfile.cpu
+12
-10
@@ -129,7 +129,7 @@ RUN echo 'ulimit -c 0' >> ~/.bashrc
129
# Build the Rust frontend (`vllm-rs`) in a dedicated stage so the wheel build
130
# stage doesn't need the rust toolchain. This stage runs in parallel
131
# with the main vllm-build stage.
132
-FROM base AS rust-build
132
+FROM base AS rust-build-cache
133
ENV DEBIAN_FRONTEND=noninteractive
134
135
RUN apt-get update -y \
@@ -163,25 +163,27 @@ COPY build_rust.sh build_rust.sh
163
# (rustc spawns enough concurrent processes to hit RLIMIT_NOFILE otherwise).
164
ENV CARGO_BUILD_JOBS=4
165
166
-# Only Rust inputs are present, so suppress the artificial dirty state caused
167
-# by other tracked files being absent from this build stage.
168
-ENV SETUPTOOLS_SCM_PRETEND_METADATA={dirty=false}
169
-
170
-# Build the release artifacts. Cache cargo registry/git, but not target/,
171
-# because stale target metadata can outlive source updates across BuildKit
172
-# cache reuse.
166
+# Build with a stable version so this target snapshot is keyed only by Rust
167
+# inputs. The child stage below relinks the crates that embed the exact version.
168
RUN --mount=type=cache,target=/root/.cargo/registry,sharing=locked \
169
--mount=type=cache,target=/root/.cargo/git,sharing=locked \
175
- --mount=type=bind,source=.git,target=.git \
170
--mount=type=secret,id=aws-credentials,target=/root/.aws/credentials,required=false \
171
if [ "$USE_SCCACHE" = "1" ]; then \
172
export RUSTC_WRAPPER=sccache; \
173
if [ -n "${SCCACHE_ENDPOINT}" ]; then export SCCACHE_ENDPOINT="${SCCACHE_ENDPOINT}"; fi; \
174
sccache --show-stats; \
175
fi && \
182
- bash build_rust.sh && \
176
+ SETUPTOOLS_SCM_PRETEND_VERSION="0.0.0+docker.cache" bash build_rust.sh && \
177
if [ "$USE_SCCACHE" = "1" ]; then sccache --show-stats; fi
178
179
+# Relink with the exact Git-derived package version.
180
+FROM rust-build-cache AS rust-build
181
+
182
+RUN --mount=type=cache,target=/root/.cargo/registry,sharing=locked \
183
+ --mount=type=cache,target=/root/.cargo/git,sharing=locked \
184
+ --mount=type=bind,source=.git,target=.git \
185
+ SETUPTOOLS_SCM_PRETEND_METADATA="{dirty=false}" bash build_rust.sh
186
+
187
######################### SOURCE PREP IMAGE #########################
188
# Shared prep (source, rust artifacts, build deps) for both vllm-build and
189
# vllm-dev, so the two independent compiles (bdist_wheel vs. setup.py
docker/Dockerfile.xpu
+10
-5
@@ -1,7 +1,7 @@
1
######################### RUST BUILD IMAGE #########################
2
# Build the Rust frontend (`vllm-rs`) in a dedicated stage so the main image
3
# doesn't need the rust toolchain. Runs in parallel with vllm-base.
4
-FROM ubuntu:22.04 AS rust-build
4
+FROM ubuntu:22.04 AS rust-build-cache
5
ENV DEBIAN_FRONTEND=noninteractive
6
7
RUN apt-get update -y \
@@ -25,14 +25,19 @@ COPY build_rust.sh build_rust.sh
25
# (rustc spawns enough concurrent processes to hit RLIMIT_NOFILE otherwise).
26
ENV CARGO_BUILD_JOBS=4
27
28
-# Only Rust inputs are present, so suppress the artificial dirty state caused
29
-# by other tracked files being absent from this build stage.
30
-ENV SETUPTOOLS_SCM_PRETEND_METADATA={dirty=false}
28
+# Build with a stable version so this target snapshot is keyed only by Rust
29
+# inputs. The child stage below relinks the crates that embed the exact version.
30
+RUN --mount=type=cache,target=/root/.cargo/registry,sharing=locked \
31
+ --mount=type=cache,target=/root/.cargo/git,sharing=locked \
32
+ SETUPTOOLS_SCM_PRETEND_VERSION="0.0.0+docker.cache" bash build_rust.sh
33
+
34
+# Relink with the exact Git-derived package version.
35
+FROM rust-build-cache AS rust-build
36
37
RUN --mount=type=cache,target=/root/.cargo/registry,sharing=locked \
38
--mount=type=cache,target=/root/.cargo/git,sharing=locked \
39
--mount=type=bind,source=.git,target=.git \
35
- bash build_rust.sh
40
+ SETUPTOOLS_SCM_PRETEND_METADATA="{dirty=false}" bash build_rust.sh
41
42
FROM ubuntu:24.04 AS vllm-base
43
docs/assets/contributing/dockerfile-stages-dependency.png
Binary files a/docs/assets/contributing/dockerfile-stages-dependency.png and b/docs/assets/contributing/dockerfile-stages-dependency.png differ
tests/tools/test_docker_build_metadata_args.py
+16
@@ -153,6 +153,22 @@ def test_vllm_openai_image_embeds_metadata_contract() -> None:
153
assert expected in dockerfile
154
155
156
+def test_rust_build_cache_excludes_git_metadata() -> None:
157
+ for name in ("Dockerfile", "Dockerfile.cpu", "Dockerfile.xpu"):
158
+ dockerfile = (REPO_ROOT / "docker" / name).read_text()
159
+ cached_stage, exact_version_stage = dockerfile.split(
160
+ "FROM rust-build-cache AS rust-build", maxsplit=1
161
+ )
162
+ exact_version_stage = exact_version_stage.split("\nFROM ", maxsplit=1)[0]
163
+ cached_run = cached_stage.rsplit("RUN ", maxsplit=1)[1]
164
+
165
+ assert 'SETUPTOOLS_SCM_PRETEND_VERSION="0.0.0+docker.cache"' in cached_run
166
+ assert "source=.git,target=.git" not in cached_run
167
+ assert "source=.git,target=.git" in exact_version_stage
168
+ assert 'SETUPTOOLS_SCM_PRETEND_METADATA="{dirty=false}"' in exact_version_stage
169
+ assert "bash build_rust.sh" in exact_version_stage
170
+
171
+
172
def test_rocm_ci_base_bake_embeds_content_hash_label() -> None:
173
bake_file = (REPO_ROOT / "docker" / "docker-bake-rocm.hcl").read_text()
174