main
rock 1,016 lines 44.7 KB
Raw
1 # default base image
2 ARG REMOTE_VLLM="0"
3 ARG VLLM_REPO="https://github.com/vllm-project/vllm.git"
4 ARG VLLM_BRANCH="main"
5 ARG COMMON_WORKDIR=/app
6 ARG BASE_IMAGE=rocm/vllm-dev:base
7 ARG CI_BASE_IMAGE=rocm/vllm-dev:ci_base
8 ARG ROCM_TRITON_KERNELS_COMMIT=669b31acc1dd1b3fd93286afd5db67f65d9f7557
9 ARG INSTALL_LMCACHE=false
10 # NIC backend for MoRI RDMA support.
11 # By default (all), drivers and userspace libraries for all supported NIC types
12 # (ainic and bnxt) are installed; MoRI selects the appropriate one at runtime.
13 # To install drivers for a single NIC type only, set NIC_BACKEND explicitly:
14 # --build-arg NIC_BACKEND=ainic # AMD AINIC (Pensando) only
15 # --build-arg NIC_BACKEND=bnxt # Broadcom Thor-2 only
16 # --build-arg NIC_BACKEND=none # Install nothing.
17 ARG NIC_BACKEND=all
18 # AMD AINIC apt repo settings
19 # Users can specify a custom version compatible with their host drivers.
20 # The default version has been tested with ionic-dkms=26.03.3.001
21 # (libionic1=54.0-187-1), required for MoRI-EP/NIXL on Pollara/AINIC.
22 ARG AINIC_VERSION=1.117.5-a-77
23 ARG UBUNTU_CODENAME=jammy
24
25 # Sccache configuration. Release builds use this today; CI can opt in when a
26 # shared S3-compatible cache backend is available.
27 ARG USE_SCCACHE
28 ARG SCCACHE_DOWNLOAD_URL
29 ARG SCCACHE_ENDPOINT
30 ARG SCCACHE_BUCKET_NAME=vllm-build-sccache
31 ARG SCCACHE_REGION_NAME=us-west-2
32 ARG SCCACHE_S3_NO_CREDENTIALS=0
33
34 FROM ${BASE_IMAGE} AS base
35
36 ARG ARG_PYTORCH_ROCM_ARCH
37 ENV PYTORCH_ROCM_ARCH=${ARG_PYTORCH_ROCM_ARCH:-${PYTORCH_ROCM_ARCH}}
38
39 # Install build dependencies and utilities
40 RUN apt-get update -q -y && apt-get install -q -y \
41 sqlite3 libsqlite3-dev libfmt-dev libmsgpack-dev libsuitesparse-dev \
42 apt-transport-https ca-certificates wget curl \
43 libnuma-dev ccache mold
44 RUN --mount=type=cache,target=/root/.cache/pip \
45 python3 -m pip install --upgrade pip
46 # Note: mold is installed but not set as the system default linker because
47 # some packages use JIT compilation at runtime with flags mold does not support.
48 # Build stages opt in via LDFLAGS="-fuse-ld=mold".
49 # Remove sccache only if not using sccache (it exists in base image from Dockerfile.rocm_base)
50 ARG USE_SCCACHE
51 RUN if [ "$USE_SCCACHE" != "1" ]; then \
52 apt-get purge -y sccache || true; \
53 python3 -m pip uninstall -y sccache || true; \
54 rm -f "$(which sccache)" || true; \
55 fi
56
57 # Install UV — download first, then run, so a curl failure is not masked by the pipe
58 RUN curl -LsSf --retry 3 --retry-delay 5 https://astral.sh/uv/install.sh -o /tmp/uv-install.sh \
59 && env UV_INSTALL_DIR="/usr/local/bin" sh /tmp/uv-install.sh \
60 && rm -f /tmp/uv-install.sh \
61 && uv --version
62
63 # This timeout (in seconds) is necessary when installing some dependencies via uv since it's likely to time out
64 # Reference: https://github.com/astral-sh/uv/pull/1694
65 ENV UV_HTTP_TIMEOUT=500
66 ENV UV_INDEX_STRATEGY="unsafe-best-match"
67 # Use copy mode to avoid hardlink failures with Docker cache mounts
68 ENV UV_LINK_MODE=copy
69 # ccache directory - persisted across layer rebuilds via cache mounts.
70 ENV CCACHE_DIR=/root/.cache/ccache
71 ENV CCACHE_COMPILERCHECK=content
72 # Empty by default so build steps fall back to $(nproc); CI can override.
73 ARG max_jobs
74 ENV MAX_JOBS=${max_jobs}
75
76 # Install sccache if USE_SCCACHE is enabled (for release builds)
77 ARG USE_SCCACHE
78 ARG SCCACHE_DOWNLOAD_URL
79 ARG SCCACHE_ENDPOINT
80 ARG SCCACHE_BUCKET_NAME
81 ARG SCCACHE_REGION_NAME
82 ARG SCCACHE_S3_NO_CREDENTIALS
83 RUN if [ "$USE_SCCACHE" = "1" ]; then \
84 if command -v sccache >/dev/null 2>&1; then \
85 echo "sccache already installed, skipping installation"; \
86 sccache --version; \
87 else \
88 echo "Installing sccache..." \
89 && SCCACHE_ARCH="x86_64" \
90 && SCCACHE_VERSION="v0.8.1" \
91 && SCCACHE_DL_URL="${SCCACHE_DOWNLOAD_URL:-https://github.com/mozilla/sccache/releases/download/${SCCACHE_VERSION}/sccache-${SCCACHE_VERSION}-${SCCACHE_ARCH}-unknown-linux-musl.tar.gz}" \
92 && curl -L -o /tmp/sccache.tar.gz ${SCCACHE_DL_URL} \
93 && tar -xzf /tmp/sccache.tar.gz -C /tmp \
94 && mv /tmp/sccache-${SCCACHE_VERSION}-${SCCACHE_ARCH}-unknown-linux-musl/sccache /usr/bin/sccache \
95 && chmod +x /usr/bin/sccache \
96 && rm -rf /tmp/sccache.tar.gz /tmp/sccache-${SCCACHE_VERSION}-${SCCACHE_ARCH}-unknown-linux-musl \
97 && sccache --version; \
98 fi; \
99 fi
100
101 # Set sccache environment variables only when USE_SCCACHE=1
102 # This prevents S3 config from leaking into images when sccache is not used
103 ARG USE_SCCACHE
104 ENV SCCACHE_BUCKET=${USE_SCCACHE:+${SCCACHE_BUCKET_NAME}}
105 ENV SCCACHE_REGION=${USE_SCCACHE:+${SCCACHE_REGION_NAME}}
106 ENV SCCACHE_S3_NO_CREDENTIALS=${USE_SCCACHE:+${SCCACHE_S3_NO_CREDENTIALS}}
107 ENV SCCACHE_IDLE_TIMEOUT=${USE_SCCACHE:+0}
108
109 ARG COMMON_WORKDIR
110 WORKDIR ${COMMON_WORKDIR}
111
112
113 # -----------------------
114 # vLLM fetch stages
115 FROM base AS fetch_vllm_0
116 ONBUILD COPY ./ vllm/
117 FROM base AS fetch_vllm_1
118 ARG VLLM_REPO
119 ARG VLLM_BRANCH
120 ONBUILD RUN git clone ${VLLM_REPO} \
121 && cd vllm \
122 && git fetch -v --prune -- origin ${VLLM_BRANCH} \
123 && git checkout FETCH_HEAD \
124 && if [ ${VLLM_REPO} != "https://github.com/vllm-project/vllm.git" ] ; then \
125 git remote add upstream "https://github.com/vllm-project/vllm.git" \
126 && git fetch upstream ; fi
127 FROM fetch_vllm_${REMOTE_VLLM} AS fetch_vllm
128
129 # Resolve the device-independent source version once for every downstream
130 # artifact. setuptools-scm reads Git metadata for local/remote sources and the
131 # archive metadata generated for canonical CI contexts.
132 FROM fetch_vllm AS vllm-version
133 ARG COMMON_WORKDIR
134 RUN --mount=type=cache,id=vllm-rocm-uv,target=/root/.cache/uv \
135 cd ${COMMON_WORKDIR}/vllm \
136 && uv pip install --system -r requirements/build/rust.txt \
137 && python3 -c \
138 "from setuptools_scm import get_version; print(get_version(git_describe_command=['git', 'describe', '--dirty', '--tags', '--long', '--abbrev=40', '--match', 'v[0-9]*']))" \
139 > /vllm-version.txt
140
141 # -----------------------
142 # Rust toolchain inputs
143 #
144 # Keep these separate from Rust source inputs so Rust source-only changes do not
145 # invalidate the long-lived ci_base image that carries the toolchain.
146 FROM scratch AS rust_toolchain_input_0
147 COPY rust-toolchain.toml /rust-toolchain-input/vllm/rust-toolchain.toml
148
149 FROM base AS rust_toolchain_input_1
150 ARG VLLM_REPO
151 ARG VLLM_BRANCH
152 RUN git clone --no-checkout --filter=blob:none ${VLLM_REPO} /rust-toolchain-input/vllm \
153 && cd /rust-toolchain-input/vllm \
154 && git fetch -v --prune -- origin ${VLLM_BRANCH} \
155 && git sparse-checkout init --no-cone \
156 && git sparse-checkout set \
157 rust-toolchain.toml \
158 && git checkout FETCH_HEAD
159
160 FROM rust_toolchain_input_${REMOTE_VLLM} AS rust-toolchain-input
161
162 # -----------------------
163 # Rust build inputs
164 #
165 # REMOTE_VLLM=0: use only the local files that can affect Rust artifacts.
166 # REMOTE_VLLM=1: fetch only those same files from the requested remote ref.
167 FROM scratch AS rust_input_0
168 COPY requirements/build/rust.txt /rust-input/vllm/requirements/build/rust.txt
169 COPY rust/Cargo.lock rust/Cargo.toml /rust-input/vllm/rust/
170 COPY rust/proto /rust-input/vllm/rust/proto
171 COPY rust/src /rust-input/vllm/rust/src
172 COPY rust-toolchain.toml /rust-input/vllm/rust-toolchain.toml
173 COPY tools/build_rust.py /rust-input/vllm/tools/build_rust.py
174 COPY tools/build_rust.sh /rust-input/vllm/tools/build_rust.sh
175
176 FROM base AS rust_input_1
177 ARG VLLM_REPO
178 ARG VLLM_BRANCH
179 RUN git clone --no-checkout --filter=blob:none ${VLLM_REPO} /rust-input/vllm \
180 && cd /rust-input/vllm \
181 && git fetch -v --prune -- origin ${VLLM_BRANCH} \
182 && git sparse-checkout init --no-cone \
183 && git sparse-checkout set \
184 requirements/build/rust.txt \
185 rust/Cargo.lock \
186 rust/Cargo.toml \
187 rust/proto/** \
188 rust/src/** \
189 rust-toolchain.toml \
190 tools/build_rust.py \
191 tools/build_rust.sh \
192 && git checkout FETCH_HEAD
193
194 FROM rust_input_${REMOTE_VLLM} AS rust-input
195
196 # -----------------------
197 # Rust toolchain
198 FROM base AS rust-toolchain
199
200 ENV CARGO_HOME=/root/.cargo
201 ENV RUSTUP_HOME=/root/.rustup
202 ENV PATH=${CARGO_HOME}/bin:${PATH}
203
204 RUN apt-get update -q -y && apt-get install -q -y --no-install-recommends \
205 ca-certificates curl \
206 && rm -rf /var/lib/apt/lists/*
207
208 COPY --from=rust-toolchain-input /rust-toolchain-input/vllm/rust-toolchain.toml /tmp/rust-toolchain.toml
209 RUN TOOLCHAIN="$(grep '^channel' /tmp/rust-toolchain.toml | sed 's/.*= *"\(.*\)"/\1/')" \
210 && if ! command -v rustup >/dev/null 2>&1; then \
211 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
212 | sh -s -- -y --default-toolchain none; \
213 fi \
214 && rustup toolchain install "${TOOLCHAIN}" \
215 && rustup default "${TOOLCHAIN}" \
216 && rustc --version \
217 && cargo --version
218
219 # -----------------------
220 # Rust build stage
221 # Builds the `vllm-rs` frontend in a dedicated stage so the wheel build stages
222 # don't need the rust toolchain.
223 FROM rust-toolchain AS rust-build
224 ARG COMMON_WORKDIR
225 ARG USE_SCCACHE
226
227 # Cap cargo parallelism to avoid exhausting the AMD CI host's open-file limit
228 # (rustc spawns enough concurrent processes to hit RLIMIT_NOFILE otherwise).
229 ENV CARGO_BUILD_JOBS=4
230 ENV CARGO_NET_RETRY=10
231 ENV RUSTUP_MAX_RETRIES=10
232
233 WORKDIR ${COMMON_WORKDIR}/vllm
234
235 COPY --from=rust-input /rust-input/vllm/requirements/build/rust.txt requirements/build/rust.txt
236
237 # BuildKit can run this stage in parallel with ROCm native builds. Keep Rust on
238 # a separate local sccache daemon while sharing the same remote cache backend.
239 ENV SCCACHE_SERVER_PORT=4227
240
241 RUN --mount=type=cache,id=vllm-rocm-uv,target=/root/.cache/uv \
242 uv pip install --system -r requirements/build/rust.txt
243
244 COPY --from=rust-input /rust-input/vllm/rust rust
245 COPY --from=rust-input /rust-input/vllm/rust-toolchain.toml rust-toolchain.toml
246 COPY --from=rust-input /rust-input/vllm/tools/build_rust.py tools/build_rust.py
247 COPY --from=rust-input /rust-input/vllm/tools/build_rust.sh tools/build_rust.sh
248 COPY --from=vllm-version /vllm-version.txt /tmp/vllm-version.txt
249
250 # Build the release binary. Cargo's registry/git caches can be written by
251 # concurrent BuildKit jobs on shared workers, so lock those cache mounts while
252 # keeping the cache benefit. Do not cache target/, because stale target metadata
253 # can outlive source updates across BuildKit cache reuse.
254 RUN --mount=type=cache,id=vllm-rocm-cargo-registry,target=/root/.cargo/registry,sharing=locked \
255 --mount=type=cache,id=vllm-rocm-cargo-git,target=/root/.cargo/git,sharing=locked \
256 if [ "$USE_SCCACHE" = "1" ]; then \
257 export RUSTC_WRAPPER=sccache \
258 && sccache --show-stats; \
259 fi \
260 && export SETUPTOOLS_SCM_PRETEND_VERSION="$(cat /tmp/vllm-version.txt)" \
261 && bash tools/build_rust.sh \
262 && test -x vllm/vllm-rs \
263 && if [ "$USE_SCCACHE" = "1" ]; then \
264 sccache --show-stats; \
265 fi
266
267 # -----------------------
268 # Shared vLLM build dependencies
269 #
270 # Install requirements once, before bringing source-specific inputs into either
271 # consumer. Native compilation and wheel packaging then share this expensive
272 # layer while retaining their independent source cache boundaries.
273 FROM base AS build_vllm_dependencies
274 ARG COMMON_WORKDIR
275 ENV VLLM_TARGET_DEVICE=rocm
276 WORKDIR ${COMMON_WORKDIR}/vllm
277
278 COPY --from=fetch_vllm \
279 ${COMMON_WORKDIR}/vllm/requirements/common.txt \
280 ${COMMON_WORKDIR}/vllm/requirements/rocm.txt \
281 requirements/
282
283 # Use constraints file to protect triton, pybind11, and torch dependencies.
284 RUN --mount=type=cache,id=vllm-rocm-uv,target=/root/.cache/uv \
285 uv pip install --system -c /etc/rocm-constraints.txt -r requirements/rocm.txt
286
287 # Fetch only the pinned ROCm Triton kernels package. Keeping this before the
288 # vLLM source COPYs makes the download reusable when native sources change.
289 FROM base AS rocm-triton-kernels
290 ARG ROCM_TRITON_KERNELS_COMMIT
291 ADD https://codeload.github.com/ROCm/triton/tar.gz/${ROCM_TRITON_KERNELS_COMMIT} \
292 /tmp/rocm-triton.tar.gz
293 RUN mkdir -p /opt/rocm-triton-kernels \
294 && tar --extract --gzip --file /tmp/rocm-triton.tar.gz \
295 --directory /opt/rocm-triton-kernels --strip-components=4 \
296 --no-same-owner \
297 "triton-${ROCM_TRITON_KERNELS_COMMIT}/python/triton_kernels/triton_kernels" \
298 && test -f /opt/rocm-triton-kernels/__init__.py \
299 && rm /tmp/rocm-triton.tar.gz
300
301 # -----------------------
302 # vLLM native build stages
303 #
304 # csrc-build intentionally copies only files that affect ROCm native extension
305 # compilation. That keeps unrelated CI/test/docs edits from invalidating the
306 # expensive HIP/C++ build layer.
307 FROM build_vllm_dependencies AS csrc-build
308 ARG ROCM_TRITON_KERNELS_COMMIT
309 COPY --from=rocm-triton-kernels \
310 /opt/rocm-triton-kernels /opt/rocm-triton-kernels
311 ENV TRITON_KERNELS_SRC_DIR=/opt/rocm-triton-kernels
312
313 # pyproject.toml is bind-mounted so it is not persisted in the csrc-build image,
314 # but it still participates in the BuildKit cache key for this RUN step.
315 COPY setup.py CMakeLists.txt ./
316 COPY tools/build_rust.py tools/build_rust.py
317 COPY cmake cmake/
318 COPY csrc csrc/
319 COPY vllm/envs.py vllm/envs.py
320 COPY vllm/__init__.py vllm/__init__.py
321
322 ENV SETUPTOOLS_SCM_PRETEND_VERSION="0.0.0+rocm.csrc.build"
323
324 RUN --mount=type=bind,source=pyproject.toml,target=${COMMON_WORKDIR}/vllm/pyproject.toml \
325 --mount=type=cache,id=vllm-rocm-ccache,target=/root/.cache/ccache \
326 { grep -Fq "set(TRITON_KERNELS_TAG \"${ROCM_TRITON_KERNELS_COMMIT}\")" \
327 cmake/external_projects/triton_kernels.cmake \
328 || echo "WARNING: Dockerfile.rock ROCM_TRITON_KERNELS_COMMIT (${ROCM_TRITON_KERNELS_COMMIT}) does not match cmake TRITON_KERNELS_TAG; the Docker build uses the Dockerfile pin, cmake governs only non-Docker builds"; } \
329 && export CCACHE_BASEDIR="$PWD" \
330 && echo "=== ccache stats before ROCm native build ===" \
331 && (ccache --show-stats || true) \
332 && (ccache --zero-stats || true) \
333 && EFFECTIVE_MAX_JOBS="${MAX_JOBS:-$(nproc)}" \
334 && echo "Building ROCm native extension wheel with MAX_JOBS=${EFFECTIVE_MAX_JOBS}" \
335 && PYTHONDONTWRITEBYTECODE=1 LDFLAGS="-fuse-ld=mold" MAX_JOBS="${EFFECTIVE_MAX_JOBS}" python3 setup.py bdist_wheel --dist-dir=dist \
336 && test -d dist \
337 && ls dist/*.whl >/dev/null \
338 && echo "=== ccache stats after ROCm native build ===" \
339 && (ccache --show-stats || true)
340
341 # Build the full vLLM ROCm wheel by reusing the native extension wheel from
342 # csrc-build. This stage still rebuilds for Python/package changes, but skips
343 # the expensive dependency installation and HIP/C++ compilation when their
344 # respective inputs are unchanged.
345 FROM build_vllm_dependencies AS build_vllm
346 COPY --from=fetch_vllm ${COMMON_WORKDIR}/vllm ${COMMON_WORKDIR}/vllm
347 COPY --from=csrc-build ${COMMON_WORKDIR}/vllm/dist /precompiled-wheels
348 COPY --from=vllm-version /vllm-version.txt /tmp/vllm-version.txt
349
350 # Drop the pre-built Rust artifacts into the source tree. setup.py detects
351 # them and ships them as-is, skipping the local Rust build.
352 COPY --from=rust-build ${COMMON_WORKDIR}/vllm/vllm/vllm-rs ${COMMON_WORKDIR}/vllm/vllm/vllm-rs
353 COPY --from=rust-build ${COMMON_WORKDIR}/vllm/vllm/_rust_*.so ${COMMON_WORKDIR}/vllm/vllm/
354
355 RUN cd "${COMMON_WORKDIR}/vllm" \
356 && export SETUPTOOLS_SCM_PRETEND_VERSION="$(cat /tmp/vllm-version.txt)" \
357 && export VLLM_USE_PRECOMPILED=1 \
358 && export VLLM_PRECOMPILED_WHEEL_LOCATION="$(ls /precompiled-wheels/*.whl)" \
359 && export VLLM_DOCKER_BUILD_CONTEXT=1 \
360 && echo "Packaging vLLM ROCm wheel using precompiled extensions from ${VLLM_PRECOMPILED_WHEEL_LOCATION}" \
361 && PYTHONDONTWRITEBYTECODE=1 python3 setup.py bdist_wheel --dist-dir=dist \
362 && test -d dist \
363 && ls dist/*.whl >/dev/null
364 FROM scratch AS export_vllm
365 ARG COMMON_WORKDIR
366 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/dist/*.whl /
367 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/requirements /requirements
368 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/benchmarks /benchmarks
369 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/tests /tests
370 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/examples /examples
371 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/tools/benchmark_helion_kernels.py /tools/benchmark_helion_kernels.py
372 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/tools/install_torchcodec_rocm.sh /tools/install_torchcodec_rocm.sh
373 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/docker/Dockerfile /docker/Dockerfile
374 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/docker/Dockerfile.cpu /docker/Dockerfile.cpu
375 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/docker/Dockerfile.rocm /docker/
376 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/docker/Dockerfile.rocm_base /docker/Dockerfile.rocm_base
377 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/docker/ci-rocm.hcl /docker/ci-rocm.hcl
378 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/docker/docker-bake.hcl /docker/docker-bake.hcl
379 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/docker/docker-bake-rocm.hcl /docker/docker-bake-rocm.hcl
380 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/.buildkite /.buildkite
381 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/pyproject.toml /pyproject.toml
382 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/rust /rust
383 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/rust-toolchain.toml /rust-toolchain.toml
384 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/vllm/v1 /vllm_v1
385
386 # NIXL/UCX build stages
387 FROM base AS build_nixl
388 ARG NIXL_BRANCH="231d56753047c989062a5cb2ac703a1ad761c7d2"
389 ARG NIXL_REPO="https://github.com/ai-dynamo/nixl.git"
390 ARG UCX_BRANCH="96e58a16039f6d7d213bc967b8069238742c5194"
391 ARG UCX_REPO="https://github.com/openucx/ucx.git"
392 ENV UCX_HOME=/usr/local/ucx
393 ENV NIXL_HOME=/usr/local/nixl
394
395 # NIXL build system dependencies and RDMA support
396 RUN apt-get -y update && apt-get -y install autoconf libtool pkg-config \
397 libgrpc-dev \
398 libgrpc++-dev \
399 libprotobuf-dev \
400 protobuf-compiler-grpc \
401 libcpprest-dev \
402 libaio-dev \
403 librdmacm1 \
404 librdmacm-dev \
405 libibverbs1 \
406 libibverbs-dev \
407 ibverbs-utils \
408 rdmacm-utils \
409 ibverbs-providers \
410 && rm -rf /var/lib/apt/lists/*
411
412 RUN --mount=type=cache,target=/root/.cache/uv \
413 uv pip install --system meson meson-python pyyaml types-PyYAML \
414 auditwheel build patchelf pytest tomlkit "setuptools>=80.9.0"
415
416 RUN --mount=type=cache,target=/root/.cache/ccache \
417 cd /usr/local/src && \
418 git clone ${UCX_REPO} && \
419 cd ucx && \
420 git checkout ${UCX_BRANCH} && \
421 ./autogen.sh && \
422 mkdir build && cd build && \
423 CC="ccache gcc" CXX="ccache g++" \
424 ../configure \
425 --prefix=/usr/local/ucx \
426 --enable-shared \
427 --disable-static \
428 --disable-doxygen-doc \
429 --enable-optimizations \
430 --enable-devel-headers \
431 --with-rocm=${ROCM_PATH} \
432 --with-verbs \
433 --with-dm \
434 --enable-mt && \
435 make -j$(nproc) && \
436 make install
437
438 ENV PATH=/usr/local/ucx/bin:$PATH
439 ENV LD_LIBRARY_PATH=${UCX_HOME}/lib:${LD_LIBRARY_PATH}
440
441 RUN --mount=type=cache,target=/root/.cache/ccache \
442 git clone ${NIXL_REPO} /opt/nixl && \
443 cd /opt/nixl && \
444 git checkout ${NIXL_BRANCH} && \
445 CC="ccache gcc" CXX="ccache g++" \
446 meson setup build --prefix=${NIXL_HOME} \
447 -Ducx_path=${UCX_HOME} \
448 -Dwheel_variant=rocm \
449 -Dbuild_tests=false \
450 -Dbuild_examples=false && \
451 cd build && \
452 ninja -j$(nproc) && \
453 ninja install && \
454 echo "${NIXL_HOME}/lib/$(uname -m)-linux-gnu" \
455 > /etc/ld.so.conf.d/nixl.conf && \
456 echo "${NIXL_HOME}/lib/$(uname -m)-linux-gnu/plugins" \
457 >> /etc/ld.so.conf.d/nixl.conf && \
458 ldconfig
459
460 # Generate the ROCm NIXL wheel. Upstream's generic wheel helper detects CUDA,
461 # so configure the ROCm wheel variant directly through Meson.
462 # Exclude libcore and libpull from auditwheel: transitive dependencies
463 # that are not shipped in the wheel and vary across base images.
464 RUN cd /opt/nixl && \
465 ./contrib/tomlutil.py --wheel-name nixl-rocm pyproject.toml && \
466 CC="ccache gcc" CXX="ccache g++" \
467 uv build --wheel --no-build-isolation --out-dir /tmp/nixl_wheels \
468 --python ${PYTHON_VERSION} \
469 -Csetup-args=-Ducx_path=${UCX_HOME} \
470 -Csetup-args=-Dwheel_variant=rocm \
471 -Csetup-args=-Dbuild_tests=false \
472 -Csetup-args=-Dbuild_examples=false && \
473 mkdir -p /tmp/nixl_wheels/repaired /app/install && \
474 auditwheel repair \
475 --exclude 'libamdhip64*' \
476 --exclude 'libcore*' \
477 --exclude 'libpull*' \
478 /tmp/nixl_wheels/nixl_rocm*.whl \
479 --plat manylinux_2_34_$(uname -m) \
480 --wheel-dir /tmp/nixl_wheels/repaired && \
481 ./contrib/wheel_add_ucx_plugins.py \
482 --ucx-plugins-dir ${UCX_HOME}/lib/ucx \
483 --nixl-plugins-dir ${NIXL_HOME}/lib/$(uname -m)-linux-gnu/plugins \
484 /tmp/nixl_wheels/repaired/*.whl && \
485 cp /tmp/nixl_wheels/repaired/*.whl /app/install
486
487 # Fetch and verify pinned LMCache source.
488 FROM base AS lmcache_source
489 ARG LMCACHE_REPO="https://github.com/LMCache/LMCache.git"
490 ARG LMCACHE_REF="140819c9d57a975dbc5678a6459a218e544cb58b"
491 ARG LMCACHE_VERSION="0.5.3"
492
493 # Remove NVIDIA-only dependencies and accept the release image's NumPy version.
494 RUN printf '%s\n' "${LMCACHE_REF}" | grep -Eq '^[0-9a-f]{40}$' \
495 && git clone --depth=1 --branch "v${LMCACHE_VERSION}" \
496 "${LMCACHE_REPO}" /app/lmcache \
497 && test "$(git -C /app/lmcache rev-parse HEAD)" = "${LMCACHE_REF}" \
498 && test "$(grep -Ec '^(cufile-python|nvtx)([<=>[:space:]]|$)' \
499 /app/lmcache/requirements/common.txt)" -eq 2 \
500 && test "$(grep -Fxc 'numpy<=2.2.6' \
501 /app/lmcache/requirements/common.txt)" -eq 1 \
502 && sed -i -E \
503 -e '/^(cufile-python|nvtx)([<=>[:space:]]|$)/d' \
504 -e 's/^numpy<=2\.2\.6$/numpy<=2.3.5/' \
505 /app/lmcache/requirements/common.txt \
506 && rm -rf /app/lmcache/.git
507
508 FROM base AS build_lmcache
509 COPY --from=lmcache_source \
510 /app/lmcache/requirements/build.txt /tmp/lmcache-build-requirements.txt
511 RUN --mount=type=cache,id=vllm-rocm-uv,target=/root/.cache/uv \
512 uv pip install --system -r /tmp/lmcache-build-requirements.txt
513
514 ARG LMCACHE_VERSION="0.5.3"
515 ARG LMCACHE_ROCM_ARCH="gfx942;gfx950"
516 ARG USE_SCCACHE
517
518 COPY --from=lmcache_source /app/lmcache /app/lmcache
519 WORKDIR /app/lmcache
520
521 RUN --mount=type=cache,id=vllm-rocm-ccache,target=/root/.cache/ccache \
522 set -eu; \
523 printf '%s\n' "${LMCACHE_ROCM_ARCH}" \
524 | grep -Eq '^gfx[0-9a-z]+(;gfx[0-9a-z]+)*$'; \
525 offload_flags="$(printf '%s' "${LMCACHE_ROCM_ARCH}" \
526 | sed 's/;/ --offload-arch=/g; s/^/--offload-arch=/')"; \
527 if [ "${USE_SCCACHE:-0}" = "1" ]; then \
528 export HIP_CLANG_PATH=/opt/sccache-wrappers; \
529 fi; \
530 mkdir -p /app/install; \
531 SETUPTOOLS_SCM_PRETEND_VERSION="${LMCACHE_VERSION}" \
532 PYTORCH_ROCM_ARCH="${LMCACHE_ROCM_ARCH}" \
533 HIPCC_COMPILE_FLAGS_APPEND="${offload_flags}" \
534 BUILD_WITH_HIP=1 CXX=hipcc \
535 python3 setup.py bdist_wheel --dist-dir=/app/install; \
536 test "$(find /app/install -maxdepth 1 -name '*.whl' | wc -l)" -eq 1
537
538 RUN --mount=type=tmpfs,target=/tmp/lmcache-wheel \
539 set -eu; \
540 python3 -m zipfile -e /app/install/*.whl /tmp/lmcache-wheel; \
541 c_ops="$(find /tmp/lmcache-wheel -type f -name 'c_ops*.so')"; \
542 test "$(find /tmp/lmcache-wheel -type f -name 'c_ops*.so' | wc -l)" -eq 1; \
543 expected="$(printf '%s' "${LMCACHE_ROCM_ARCH}" | tr ';' '\n' | sort -u)"; \
544 actual="$(llvm-objdump --offloading "${c_ops}" \
545 | grep -oE 'gfx[0-9a-z]+' | sort -u)"; \
546 if [ "${actual}" != "${expected}" ]; then \
547 printf 'LMCache code objects mismatch\nexpected:\n%s\nactual:\n%s\n' \
548 "${expected}" "${actual}" >&2; \
549 exit 1; \
550 fi
551
552 # DeepEP build stage. ROCShmem is provided by TheRock SDK
553 # ROCSHMEM_DIR set to the SDK install path so DeepEP finds the headers, etc.
554 FROM base AS build_deepep
555 ENV ROCSHMEM_DIR=${ROCM_PATH}
556 ARG DEEPEP_BRANCH="0f63d3e9"
557 ARG DEEPEP_REPO="https://github.com/ROCm/DeepEP.git"
558 ARG DEEPEP_NIC="cx7"
559
560 # Build DeepEP wheel. DeepEP looks for rocshmem at ROCSHMEM_DIR.
561 # DeepEP only supports gfx942 and gfx950, so avoid gfx90a in the default list.
562 # We pass --rocm-gfx942-fp8-fnuz-max 224 to align the DeepEP dispatch FP8
563 # quantization bound with vLLM's own clamp
564 # (vllm/model_executor/layers/quantization/utils/fp8_utils.py): 224 for E4M3FNUZ
565 RUN --mount=type=cache,target=/root/.cache/ccache \
566 export PYTORCH_ROCM_ARCH="gfx942;gfx950" \
567 && git clone ${DEEPEP_REPO} \
568 && cd DeepEP \
569 && git checkout ${DEEPEP_BRANCH} \
570 && LDFLAGS="-fuse-ld=mold" MAX_JOBS="${MAX_JOBS:-$(nproc)}" python3 setup.py --variant rocm --rocm-explicit-ctx --nic ${DEEPEP_NIC} --rocm-gfx942-fp8-fnuz-max 224 bdist_wheel --dist-dir=/app/deep_install
571
572 # MoRI runtime dependencies live in Dockerfile.rocm so NIC backend changes do
573 # not force users to rebuild the long-lived Dockerfile.rocm_base image.
574 FROM base AS mori_base
575 ARG NIC_BACKEND
576 ARG AINIC_VERSION
577 ARG UBUNTU_CODENAME
578 RUN /bin/bash -lc 'set -euo pipefail; \
579 \
580 install_ainic() { \
581 apt-get update && apt-get install -y --no-install-recommends ca-certificates curl gnupg apt-transport-https; \
582 rm -rf /var/lib/apt/lists/*; \
583 mkdir -p /etc/apt/keyrings; \
584 curl -fsSL https://repo.radeon.com/rocm/rocm.gpg.key | gpg --dearmor > /etc/apt/keyrings/amdainic.gpg; \
585 echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/amdainic.gpg] https://repo.radeon.com/amdainic/pensando/ubuntu/${AINIC_VERSION} ${UBUNTU_CODENAME} main" \
586 > /etc/apt/sources.list.d/amdainic.list; \
587 apt-get update && apt-get install -y --no-install-recommends \
588 libionic-dev \
589 ionic-common \
590 ; \
591 rm -rf /var/lib/apt/lists/*; \
592 }; \
593 \
594 # NOTE: requires FW 235.2.86.0 and kernel drivers on the host: \
595 # bnxt-en-dkms=1.10.3.235.2.86.0 bnxt-re-dkms=235.2.86.0 (from packages.broadcom.com PPA) \
596 install_bnxt() { \
597 install -m 0755 -d /etc/apt/keyrings; \
598 curl -fsSL https://packages.broadcom.com/artifactory/api/security/keypair/PackagesKey/public \
599 -o /etc/apt/keyrings/broadcom-nic.asc; \
600 chmod a+r /etc/apt/keyrings/broadcom-nic.asc; \
601 echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/broadcom-nic.asc] https://packages.broadcom.com/artifactory/ethernet-nic-debian-public jammy main" \
602 > /etc/apt/sources.list.d/broadcom-nic.list; \
603 apt-get update && apt-get install -y --no-install-recommends \
604 bnxt-rocelib=235.2.86.0 \
605 ; \
606 cp -a /usr/local/lib/x86_64-linux-gnu/libbnxt_re* /usr/local/lib/; \
607 ldconfig; \
608 rm -rf /var/lib/apt/lists/*; \
609 }; \
610 \
611 echo "[MORI] Install MoRI proxy deps"; \
612 pip install --quiet --ignore-installed blinker && \
613 pip install --quiet quart msgpack aiohttp pyzmq; \
614 echo "[MORI] NIC_BACKEND=${NIC_BACKEND}"; \
615 \
616 # NIC backend deps — mori auto-detects NIC at runtime (MORI_DEVICE_NIC env var override). \
617 # Only vendor packages are installed here for dlopen; no compile-time flags needed. \
618 case "${NIC_BACKEND}" in \
619 none) ;; \
620 all) install_ainic; install_bnxt ;; \
621 ainic) install_ainic ;; \
622 bnxt) install_bnxt ;; \
623 *) echo "ERROR: unknown NIC_BACKEND=${NIC_BACKEND}. Use one of: none, ainic, bnxt, all"; exit 2 ;; \
624 esac'
625
626 # -----------------------
627 # vLLM wheel release build stage (for building distributable wheels)
628 # This stage pins dependencies to custom ROCm wheel versions and handles version detection
629 FROM fetch_vllm AS build_vllm_wheel_release
630
631 ARG COMMON_WORKDIR
632 ARG ROCM_TRITON_KERNELS_COMMIT
633 COPY --from=vllm-version /vllm-version.txt /tmp/vllm-version.txt
634 COPY --from=rocm-triton-kernels \
635 /opt/rocm-triton-kernels /opt/rocm-triton-kernels
636 ENV TRITON_KERNELS_SRC_DIR=/opt/rocm-triton-kernels
637
638 # Drop the pre-built Rust artifacts into the source tree. setup.py detects
639 # them and ships them as-is, skipping the local Rust build.
640 COPY --from=rust-build ${COMMON_WORKDIR}/vllm/vllm/vllm-rs ${COMMON_WORKDIR}/vllm/vllm/vllm-rs
641 COPY --from=rust-build ${COMMON_WORKDIR}/vllm/vllm/_rust_*.so ${COMMON_WORKDIR}/vllm/vllm/
642
643 # Create /install directory for custom wheels
644 RUN mkdir -p /install
645
646 # Copy custom ROCm wheels from docker/context if they exist
647 # COPY ensures Docker cache is invalidated when wheels change
648 # .keep file ensures directory always exists for COPY to work
649 COPY docker/context/base-wheels/ /tmp/base-wheels/
650 # This is how we know if we are building for a wheel release or not.
651 # If there are not wheels found there, we are not building for a wheel release.
652 # So we exit with an error. To skip this stage.
653 RUN if [ -n "$(ls /tmp/base-wheels/*.whl 2>/dev/null)" ]; then \
654 echo "Found custom wheels - copying to /install"; \
655 cp /tmp/base-wheels/*.whl /install/ && \
656 echo "Copied custom wheels:"; \
657 ls -lh /install/; \
658 else \
659 echo "ERROR: No custom wheels found in docker/context/base-wheels/"; \
660 echo "Wheel releases require pre-built ROCm wheels."; \
661 exit 1; \
662 fi
663
664 # GIT_REPO_CHECK: Verify repo is clean and tags are available (for release builds)
665 # This matches CUDA's Dockerfile behavior for proper version detection via setuptools_scm
666 ARG GIT_REPO_CHECK=0
667 RUN if [ "$GIT_REPO_CHECK" != "0" ]; then \
668 echo "Running repository checks..."; \
669 cd vllm && bash tools/check_repo.sh; \
670 fi
671
672 # Install the packaging helpers before modifying requirements/rocm.txt.
673 RUN --mount=type=cache,target=/root/.cache/uv \
674 { grep -Fq "set(TRITON_KERNELS_TAG \"${ROCM_TRITON_KERNELS_COMMIT}\")" \
675 vllm/cmake/external_projects/triton_kernels.cmake \
676 || echo "WARNING: Dockerfile.rock ROCM_TRITON_KERNELS_COMMIT (${ROCM_TRITON_KERNELS_COMMIT}) does not match cmake TRITON_KERNELS_TAG; the Docker build uses the Dockerfile pin, cmake governs only non-Docker builds"; } \
677 && cd vllm \
678 && uv pip install --system setuptools_scm regex
679
680 # Fail if git-based package dependencies are found in requirements files
681 # (uv doesn't handle git+ URLs well, and packages should be distributed on PyPI)
682 # Extra notes: pip install is able to handle git+ URLs, but uv doesn't.
683 RUN echo "Checking for git-based packages in requirements files..." \
684 && echo "Checking common.txt for git-based packages:" \
685 && if grep -q 'git+' ${COMMON_WORKDIR}/vllm/requirements/common.txt; then \
686 echo "ERROR: Git-based packages found in common.txt:"; \
687 grep 'git+' ${COMMON_WORKDIR}/vllm/requirements/common.txt; \
688 echo "Please publish these packages to PyPI instead of using git dependencies."; \
689 exit 1; \
690 else \
691 echo " ✓ No git-based packages found in common.txt"; \
692 fi \
693 && echo "Checking rocm.txt for git-based packages:" \
694 && if grep -q 'git+' ${COMMON_WORKDIR}/vllm/requirements/rocm.txt; then \
695 echo "ERROR: Git-based packages found in rocm.txt:"; \
696 grep 'git+' ${COMMON_WORKDIR}/vllm/requirements/rocm.txt; \
697 echo "Please publish these packages to PyPI instead of using git dependencies."; \
698 exit 1; \
699 else \
700 echo " ✓ No git-based packages found in rocm.txt"; \
701 fi \
702 && echo "All requirements files are clean - no git-based packages found"
703
704 # Pin vLLM dependencies to exact versions of custom ROCm wheels
705 # This ensures 'pip install vllm' automatically installs correct torch/triton/torchvision/amdsmi
706 COPY tools/vllm-rocm/pin_rocm_dependencies.py /tmp/pin_rocm_dependencies.py
707 RUN echo "Pinning vLLM dependencies to custom wheel versions..." \
708 && python3 /tmp/pin_rocm_dependencies.py /install ${COMMON_WORKDIR}/vllm/requirements/rocm.txt
709
710 # Install dependencies using custom wheels from /install
711 RUN --mount=type=cache,target=/root/.cache/uv \
712 cd vllm \
713 && echo "Building vLLM with custom wheels from /install" \
714 && uv pip install --system --find-links /install -r requirements/rocm.txt
715
716 # Build wheel using the shared source version to avoid dirty state from modified requirements/rocm.txt
717 # (setup.py auto-detects ccache/sccache in PATH)
718 RUN --mount=type=cache,id=vllm-rocm-ccache,target=/root/.cache/ccache \
719 cd vllm \
720 && export CCACHE_BASEDIR="$PWD" \
721 && export SETUPTOOLS_SCM_PRETEND_VERSION="$(cat /tmp/vllm-version.txt)" \
722 && echo "Building wheel with version: ${SETUPTOOLS_SCM_PRETEND_VERSION}" \
723 && MAX_JOBS="${MAX_JOBS:-$(nproc)}" python3 setup.py bdist_wheel --dist-dir=dist
724
725 FROM scratch AS export_vllm_wheel_release
726 ARG COMMON_WORKDIR
727 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/dist/*.whl /
728 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/requirements /requirements
729 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/benchmarks /benchmarks
730 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/tests /tests
731 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/examples /examples
732 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/tools/benchmark_helion_kernels.py /tools/benchmark_helion_kernels.py
733 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/tools/install_torchcodec_rocm.sh /tools/install_torchcodec_rocm.sh
734 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/docker/Dockerfile /docker/Dockerfile
735 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/docker/Dockerfile.cpu /docker/Dockerfile.cpu
736 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/docker/Dockerfile.rocm /docker/
737 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/docker/Dockerfile.rocm_base /docker/Dockerfile.rocm_base
738 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/docker/ci-rocm.hcl /docker/ci-rocm.hcl
739 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/docker/docker-bake.hcl /docker/docker-bake.hcl
740 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/docker/docker-bake-rocm.hcl /docker/docker-bake-rocm.hcl
741 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/.buildkite /.buildkite
742 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/pyproject.toml /pyproject.toml
743 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/rust /rust
744 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/rust-toolchain.toml /rust-toolchain.toml
745 COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/vllm/v1 /vllm_v1
746
747 # -----------------------
748 # CI base image (Tier 1) - stable, rarely changing CI dependencies.
749 # Per-PR test builds pull this as CI_BASE_IMAGE so the test stage only layers
750 # in the vLLM artifacts for the current commit.
751 FROM mori_base AS ci_base
752 ARG COMMON_WORKDIR
753
754 ENV CARGO_HOME=/root/.cargo
755 ENV RUSTUP_HOME=/root/.rustup
756 ENV PATH=${CARGO_HOME}/bin:${PATH}
757
758 # Bake the Rust toolchain into ci_base so Rust build/test steps do not
759 # need to fetch it on each per-commit image build.
760 COPY --from=rust-toolchain /root/.cargo /root/.cargo
761 COPY --from=rust-toolchain /root/.rustup /root/.rustup
762
763 # Update rdma-core to support latest rocshmem.
764 ARG DEEPEP_NIC
765 RUN if [ "${DEEPEP_NIC}" = "cx7" ] || [ "${DEEPEP_NIC}" = "io" ]; then \
766 git clone --branch v62.0 --depth 1 https://github.com/linux-rdma/rdma-core.git /tmp/rdma-core && \
767 cd /tmp/rdma-core && \
768 mkdir -p build && cd build && \
769 cmake -GNinja -DCMAKE_INSTALL_PREFIX=/usr -DNO_MAN_PAGES=1 .. && \
770 ninja && ninja install && ldconfig && rm -rf /tmp/rdma-core; \
771 fi
772
773 # Install NIXL + DeepEP wheels.
774 RUN --mount=type=bind,from=build_nixl,src=/app/install,target=/nixl_install \
775 --mount=type=bind,from=build_deepep,src=/app/deep_install,target=/deep_install \
776 uv pip install --system /nixl_install/*.whl /deep_install/*.whl
777
778 # RDMA userspace libraries plus FFmpeg dev libs needed by torchcodec.
779 RUN timeout --kill-after=30s 5m apt-get update -q -y --error-on=any \
780 -o Acquire::Retries=3 \
781 -o Acquire::http::Timeout=30 \
782 -o Acquire::https::Timeout=30 \
783 && apt-get install -q -y --no-install-recommends \
784 -o Acquire::Retries=3 \
785 -o Acquire::http::Timeout=30 \
786 -o Acquire::https::Timeout=30 \
787 librdmacm1 \
788 libibverbs1 \
789 ibverbs-providers \
790 ibverbs-utils \
791 util-linux \
792 unzip \
793 libsodium23 \
794 pkg-config ffmpeg libavcodec-dev libavformat-dev libavutil-dev \
795 libswscale-dev libavdevice-dev libavfilter-dev libswresample-dev \
796 && rm -rf /var/lib/apt/lists/*
797
798 # Install torchcodec from source for ROCm/torch ABI compatibility.
799 COPY tools/install_torchcodec_rocm.sh /tmp/install_torchcodec.sh
800 RUN --mount=type=cache,target=/root/.cache/uv \
801 --mount=type=cache,target=/root/.cache/pip \
802 --mount=type=cache,target=/root/.cache/torchcodec-wheels \
803 bash /tmp/install_torchcodec.sh \
804 && rm /tmp/install_torchcodec.sh \
805 && apt-get clean && rm -rf /var/lib/apt/lists/*
806
807 # Pre-install shared ROCm runtime dependencies.
808 COPY requirements/common.txt requirements/rocm.txt /tmp/ci-base-requirements/
809 RUN --mount=type=cache,target=/root/.cache/uv \
810 uv pip install --system -c /etc/rocm-constraints.txt \
811 -r /tmp/ci-base-requirements/rocm.txt \
812 && rm -rf /tmp/ci-base-requirements
813
814 # Enable fast and less brittle model downloads in tests.
815 ENV HF_XET_HIGH_PERFORMANCE=1
816 ENV HF_HUB_DOWNLOAD_TIMEOUT=60
817
818 # Keep torch.cuda.is_available() fork-safe (see vllm/env_override.py).
819 ENV PYTORCH_NVML_BASED_CUDA_CHECK=1
820
821 # Pre-install vLLM test dependencies.
822 COPY requirements/test/rocm.txt /tmp/rocm-test-reqs.txt
823 RUN --mount=type=cache,target=/root/.cache/uv \
824 uv pip install --system -r /tmp/rocm-test-reqs.txt
825
826 # Rebuild fastsafetensors from source so its C++ extension is compiled with
827 # USE_ROCM and can detect libamdhip64.so at runtime.
828 RUN --mount=type=cache,target=/root/.cache/pip \
829 FASTSAFETENSORS_REQ="$(grep -E '^fastsafetensors(==| @ )' /tmp/rocm-test-reqs.txt | head -1)" \
830 && test -n "${FASTSAFETENSORS_REQ}" \
831 && python3 -m pip install --force-reinstall --no-deps \
832 --no-binary fastsafetensors "${FASTSAFETENSORS_REQ}" \
833 && rm /tmp/rocm-test-reqs.txt
834
835 # Set MIOPEN ENVS to resolve performance regressions in MIOpen 3D convolution kernel.
836 # See: https://github.com/pytorch/pytorch/issues/169857
837 ENV MIOPEN_DEBUG_CONV_DIRECT=0
838 ENV MIOPEN_DEBUG_CONV_GEMM=0
839
840 # Use legacy IPC mode for HSA to avoid GPU memory pinning issues with UCX rocm_ipc.
841 # See: https://github.com/ROCm/rocm-libraries/issues/6266
842 ENV HSA_ENABLE_IPC_MODE_LEGACY=1
843 ENV UCX_RMA_PPLN_ENABLE=y
844 ENV UCX_ROCM_COPY_SIGPOOL_MAX_ELEMS=inf
845
846 # ROCm profiler limits workaround.
847 RUN echo "ROCTRACER_MAX_EVENTS=10000000" > ${COMMON_WORKDIR}/libkineto.conf
848 ENV KINETO_CONFIG="${COMMON_WORKDIR}/libkineto.conf"
849
850 # Install vllm_test_utils in ci_base for ci_base + wheel parity.
851 COPY tests/vllm_test_utils /tmp/vllm_test_utils
852 RUN --mount=type=cache,target=/root/.cache/uv \
853 uv pip install --system /tmp/vllm_test_utils \
854 && rm -rf /tmp/vllm_test_utils
855
856 RUN --mount=type=bind,from=build_lmcache,src=/app/install,target=/lmcache_install \
857 --mount=type=bind,source=requirements/test/rocm.txt,target=/tmp/lmcache-constraints.txt \
858 --mount=type=cache,target=/root/.cache/uv \
859 uv pip install --system --constraint /tmp/lmcache-constraints.txt \
860 /lmcache_install/*.whl \
861 && python3 -c "import lmcache, lmcache.c_ops; print('lmcache', lmcache.__version__)"
862
863 # -----------------------
864 # Test vLLM image (Tier 2) - vLLM-only layer on top of ci_base.
865 FROM ${CI_BASE_IMAGE} AS test
866 ARG COMMON_WORKDIR
867
868 # Install the vLLM wheel (--no-deps: all deps already in ci_base).
869 RUN --mount=type=bind,from=export_vllm,src=/,target=/install \
870 --mount=type=cache,target=/root/.cache/uv \
871 cd /install \
872 && uv pip install --system --no-deps *.whl
873
874 # Store the vLLM wheel in the image for python-only install tests.
875 COPY --from=export_vllm /*.whl /opt/vllm-wheels/
876
877 WORKDIR /vllm-workspace
878 COPY --from=build_vllm ${COMMON_WORKDIR}/vllm /vllm-workspace
879
880 # Copy in the v1 package (for python-only install test group).
881 COPY --from=export_vllm /vllm_v1 /usr/local/lib/python${PYTHON_VERSION}/dist-packages/vllm/v1
882
883 # Hide source under src/ so it won't shadow the installed package in tests.
884 RUN mkdir src && mv vllm src/vllm
885
886 # Catch GPU<->CPU syncs in execute_model/sample_tokens during tests.
887 ENV VLLM_GPU_SYNC_CHECK=error
888
889 FROM test AS test_smoke
890 ARG ROCM_SMOKE_ID
891 RUN --network=none \
892 bash /vllm-workspace/.buildkite/scripts/rocm/smoke-test-image.sh --inside \
893 && printf '%s\n' "${ROCM_SMOKE_ID:-local}" > /vllm-smoke-ok
894
895 FROM scratch AS export_test_smoke
896 COPY --from=test_smoke /vllm-smoke-ok /
897
898 # -----------------------
899 # Final vLLM image
900 FROM mori_base AS final_common
901 ENV UV_COMPILE_BYTECODE=1
902
903 RUN python3 -m pip install --upgrade pip && rm -rf /var/lib/apt/lists/*
904
905 # Clean up sccache from release image (not needed at runtime)
906 # This removes the binary and wrappers that may have been installed during build
907 RUN rm -f /usr/bin/sccache || true \
908 && rm -rf /opt/sccache-wrappers || true
909
910 # Unset sccache environment variables for the release image
911 # This prevents S3 bucket config from leaking into production images
912 ENV SCCACHE_BUCKET=
913 ENV SCCACHE_REGION=
914 ENV SCCACHE_ENDPOINT=
915 ENV SCCACHE_S3_NO_CREDENTIALS=
916 ENV SCCACHE_IDLE_TIMEOUT=
917
918 # Error related to odd state for numpy 1.20.3 where there is no METADATA etc, but an extra LICENSES_bundled.txt.
919 # Manually remove it so that later steps of numpy upgrade can continue
920 RUN case "$(which python3)" in \
921 *"/opt/conda/envs/py_3.9"*) \
922 rm -rf /opt/conda/envs/py_3.9/lib/python3.9/site-packages/numpy-1.20.3.dist-info/;; \
923 *) ;; esac
924
925 RUN --mount=type=cache,target=/root/.cache/uv \
926 uv pip install --system --upgrade huggingface-hub
927
928 # Install vLLM using uv (inherited from base stage)
929 # Note: No -U flag to avoid upgrading PyTorch ROCm to CUDA version
930 # Keep OpenTelemetry within LMCache's cap.
931 RUN --mount=type=bind,from=export_vllm,src=/,target=/install \
932 --mount=type=cache,target=/root/.cache/uv \
933 cd /install \
934 && echo "opentelemetry-api<=1.40.0" > /tmp/otel-constraints.txt \
935 && uv pip install --system -c /etc/rocm-constraints.txt -c /tmp/otel-constraints.txt -r requirements/rocm.txt \
936 && pip uninstall -y vllm \
937 && uv pip install --system -c /etc/rocm-constraints.txt -c /tmp/otel-constraints.txt *.whl \
938 && rm /tmp/otel-constraints.txt
939
940 # Install NIXL ROCm wheel
941 RUN --mount=type=bind,from=build_nixl,src=/app/install,target=/nixl_install \
942 uv pip install --system /nixl_install/*.whl
943
944 # Recompute the base's triton fingerprint to detect resolver interference.
945 RUN EXPECTED=$(grep '^TRITON_SHA256: ' /app/versions.txt | cut -d' ' -f2) \
946 && ACTUAL=$(find $(python3 -c 'import triton, os; print(os.path.dirname(triton.__file__))') \
947 -type f \( -name '*.py' -o -name '*.so' \) | sort | xargs sha256sum | sha256sum | cut -d' ' -f1) \
948 && echo "triton sha256 expected=${EXPECTED} actual=${ACTUAL}" \
949 && test -n "${EXPECTED}" \
950 && test "${EXPECTED}" = "${ACTUAL}" \
951 && python3 -c "import torch; assert torch.version.hip, f'non-ROCm torch: {torch.__version__}'; print(f'torch={torch.__version__}')"
952
953 # Recompute the base's pybind11 fingerprint to detect resolver interference.
954 RUN EXPECTED=$(grep '^PYBIND11_SHA256: ' /app/versions.txt | cut -d' ' -f2) \
955 && EXPECTED_ABI=$(grep '^PYBIND11_INTERNALS_VERSION: ' /app/versions.txt | cut -d' ' -f2) \
956 && INC=$(python3 -c 'import pybind11; print(pybind11.get_include())') \
957 && ACTUAL=$(find "${INC}" -type f -name '*.h' | sort | xargs sha256sum | sha256sum | cut -d' ' -f1) \
958 && ACTUAL_ABI=$(grep -rhE '^#[[:space:]]*define PYBIND11_INTERNALS_VERSION' "${INC}" | awk '{print $NF}') \
959 && echo "pybind11 $(pip show pybind11 | awk '/^Version:/ {print $2}')" \
960 "sha256 expected=${EXPECTED} actual=${ACTUAL}" \
961 "internals expected=${EXPECTED_ABI} actual=${ACTUAL_ABI}" \
962 && test -n "${EXPECTED}" \
963 && test "${EXPECTED}" = "${ACTUAL}" \
964 && test "${EXPECTED_ABI}" = "${ACTUAL_ABI}"
965
966 ARG COMMON_WORKDIR
967 ARG BASE_IMAGE
968 ARG NIC_BACKEND
969 ARG AINIC_VERSION
970
971 # Copy over the benchmark scripts as well
972 COPY --from=export_vllm /benchmarks ${COMMON_WORKDIR}/vllm/benchmarks
973 COPY --from=export_vllm /examples ${COMMON_WORKDIR}/vllm/examples
974 COPY --from=export_vllm /docker ${COMMON_WORKDIR}/vllm/docker
975
976 # Use legacy IPC mode for HSA to avoid GPU memory pinning issues with UCX rocm_ipc
977 # See: https://github.com/ROCm/rocm-libraries/issues/6266
978 ENV HSA_ENABLE_IPC_MODE_LEGACY=1
979 ENV UCX_RMA_PPLN_ENABLE=y
980 ENV UCX_ROCM_COPY_SIGPOOL_MAX_ELEMS=inf
981
982 ENV TOKENIZERS_PARALLELISM=false
983
984 # ENV that can improve safe tensor loading, and end-to-end time
985 ENV SAFETENSORS_FAST_GPU=1
986
987 # Performance environment variable.
988 ENV HIP_FORCE_DEV_KERNARG=1
989
990 # Keep torch.cuda.is_available() fork-safe (see vllm/env_override.py).
991 ENV PYTORCH_NVML_BASED_CUDA_CHECK=1
992
993 # Workaround for ROCm profiler limits
994 RUN echo "ROCTRACER_MAX_EVENTS=10000000" > ${COMMON_WORKDIR}/libkineto.conf
995 ENV KINETO_CONFIG="${COMMON_WORKDIR}/libkineto.conf"
996 RUN echo "VLLM_BASE_IMAGE=${BASE_IMAGE}" >> ${COMMON_WORKDIR}/versions.txt \
997 && echo "MORI_NIC_BACKEND=${NIC_BACKEND}" >> ${COMMON_WORKDIR}/versions.txt \
998 && echo "AINIC_VERSION=${AINIC_VERSION}" >> ${COMMON_WORKDIR}/versions.txt
999
1000 CMD ["/bin/bash"]
1001
1002 FROM final_common AS final_lmcache_false
1003
1004 FROM final_common AS final_lmcache_true
1005 RUN --mount=type=bind,from=build_lmcache,src=/app/install,target=/lmcache_install \
1006 --mount=type=cache,target=/root/.cache/uv \
1007 uv pip install --system /lmcache_install/*.whl \
1008 && test "$(python3 -c 'import numpy; print(numpy.__version__)')" = "2.3.5" \
1009 && uv pip check --system \
1010 && python3 -c "import lmcache, lmcache.c_ops; print('lmcache', lmcache.__version__)"
1011
1012 FROM final_lmcache_${INSTALL_LMCACHE} AS final
1013
1014 #Set entrypoint for vllm-openai official images
1015 FROM final AS vllm-openai
1016 ENTRYPOINT ["vllm", "serve"]