1
+# default base image
2
+ARG REMOTE_VLLM="0"
3
+ARG COMMON_WORKDIR=/app
4
+ARG BASE_IMAGE=rocm/vllm-dev:base
5
+ARG CI_BASE_IMAGE=rocm/vllm-dev:ci_base
6
+# NIC backend for MoRI RDMA support.
7
+# By default (all), drivers and userspace libraries for all supported NIC types
8
+# (ainic and bnxt) are installed; MoRI selects the appropriate one at runtime.
9
+# To install drivers for a single NIC type only, set NIC_BACKEND explicitly:
10
+# --build-arg NIC_BACKEND=ainic # AMD AINIC (Pensando) only
11
+# --build-arg NIC_BACKEND=bnxt # Broadcom Thor-2 only
12
+# --build-arg NIC_BACKEND=none # Install nothing.
13
+ARG NIC_BACKEND=all
14
+# AMD AINIC apt repo settings
15
+# Users can specify a custom version compatible with their host drivers.
16
+# The default version has been tested with ioinic-dkms=25.11.1.001
17
+ARG AINIC_VERSION=1.117.3-hydra
18
+ARG UBUNTU_CODENAME=jammy
19
+
20
+# Sccache configuration. Release builds use this today; CI can opt in when a
21
+# shared S3-compatible cache backend is available.
22
+ARG USE_SCCACHE
23
+ARG SCCACHE_DOWNLOAD_URL
24
+ARG SCCACHE_ENDPOINT
25
+ARG SCCACHE_BUCKET_NAME=vllm-build-sccache
26
+ARG SCCACHE_REGION_NAME=us-west-2
27
+ARG SCCACHE_S3_NO_CREDENTIALS=0
28
+
29
+FROM ${BASE_IMAGE} AS base
30
+
31
+ARG ARG_PYTORCH_ROCM_ARCH=gfx1250
32
+ENV PYTORCH_ROCM_ARCH=${ARG_PYTORCH_ROCM_ARCH:-${PYTORCH_ROCM_ARCH}}
33
+
34
+# Install build dependencies and utilities
35
+RUN apt-get update -q -y && apt-get install -q -y \
36
+ sqlite3 libsqlite3-dev libfmt-dev libmsgpack-dev libsuitesparse-dev \
37
+ apt-transport-https ca-certificates wget curl \
38
+ build-essential libnuma-dev ccache mold
39
+RUN --mount=type=cache,target=/root/.cache/pip \
40
+ python3 -m pip install --upgrade pip
41
+# Note: mold is installed but not set as the system default linker because
42
+# some packages use JIT compilation at runtime with flags mold does not support.
43
+# Build stages opt in via LDFLAGS="-fuse-ld=mold".
44
+# Remove sccache only if not using sccache (it exists in base image from Dockerfile.rocm_base)
45
+ARG USE_SCCACHE
46
+RUN if [ "$USE_SCCACHE" != "1" ]; then \
47
+ apt-get purge -y sccache || true; \
48
+ python3 -m pip uninstall -y sccache || true; \
49
+ rm -f "$(which sccache)" || true; \
50
+ fi
51
+
52
+# Install UV — download first, then run, so a curl failure is not masked by the pipe
53
+RUN curl -LsSf --retry 3 --retry-delay 5 https://astral.sh/uv/install.sh -o /tmp/uv-install.sh \
54
+ && env UV_INSTALL_DIR="/usr/local/bin" sh /tmp/uv-install.sh \
55
+ && rm -f /tmp/uv-install.sh \
56
+ && uv --version
57
+
58
+# This timeout (in seconds) is necessary when installing some dependencies via uv since it's likely to time out
59
+# Reference: https://github.com/astral-sh/uv/pull/1694
60
+ENV UV_HTTP_TIMEOUT=500
61
+ENV UV_INDEX_STRATEGY="unsafe-best-match"
62
+# Use copy mode to avoid hardlink failures with Docker cache mounts
63
+ENV UV_LINK_MODE=copy
64
+# python binary fall back for non venv builds
65
+ENV UV_PYTHON=${VIRTUAL_ENV:-/usr}/bin/python3
66
+# Expose paths from wheel installation
67
+ENV PKG_CONFIG_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib/pkgconfig:${PKG_CONFIG_PATH}
68
+# ccache directory - persisted across layer rebuilds via cache mounts.
69
+ENV CCACHE_DIR=/root/.cache/ccache
70
+ENV CCACHE_COMPILERCHECK=content
71
+# Empty by default so build steps fall back to $(nproc); CI can override.
72
+ARG max_jobs
73
+ENV MAX_JOBS=${max_jobs}
74
+
75
+# Install sccache if USE_SCCACHE is enabled (for release builds)
76
+ARG USE_SCCACHE
77
+ARG SCCACHE_DOWNLOAD_URL
78
+ARG SCCACHE_ENDPOINT
79
+ARG SCCACHE_BUCKET_NAME
80
+ARG SCCACHE_REGION_NAME
81
+ARG SCCACHE_S3_NO_CREDENTIALS
82
+RUN if [ "$USE_SCCACHE" = "1" ]; then \
83
+ if command -v sccache >/dev/null 2>&1; then \
84
+ echo "sccache already installed, skipping installation"; \
85
+ sccache --version; \
86
+ else \
87
+ echo "Installing sccache..." \
88
+ && SCCACHE_ARCH="x86_64" \
89
+ && SCCACHE_VERSION="v0.8.1" \
90
+ && 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}" \
91
+ && curl -L -o /tmp/sccache.tar.gz ${SCCACHE_DL_URL} \
92
+ && tar -xzf /tmp/sccache.tar.gz -C /tmp \
93
+ && mv /tmp/sccache-${SCCACHE_VERSION}-${SCCACHE_ARCH}-unknown-linux-musl/sccache /usr/bin/sccache \
94
+ && chmod +x /usr/bin/sccache \
95
+ && rm -rf /tmp/sccache.tar.gz /tmp/sccache-${SCCACHE_VERSION}-${SCCACHE_ARCH}-unknown-linux-musl \
96
+ && sccache --version; \
97
+ fi; \
98
+ fi
99
+
100
+# Set sccache environment variables only when USE_SCCACHE=1
101
+# This prevents S3 config from leaking into images when sccache is not used
102
+ARG USE_SCCACHE
103
+ENV SCCACHE_BUCKET=${USE_SCCACHE:+${SCCACHE_BUCKET_NAME}}
104
+ENV SCCACHE_REGION=${USE_SCCACHE:+${SCCACHE_REGION_NAME}}
105
+ENV SCCACHE_S3_NO_CREDENTIALS=${USE_SCCACHE:+${SCCACHE_S3_NO_CREDENTIALS}}
106
+ENV SCCACHE_IDLE_TIMEOUT=${USE_SCCACHE:+0}
107
+
108
+ARG COMMON_WORKDIR
109
+WORKDIR ${COMMON_WORKDIR}
110
+
111
+
112
+# -----------------------
113
+# vLLM fetch stages
114
+FROM base AS fetch_vllm_0
115
+ONBUILD COPY ./ vllm/
116
+FROM base AS fetch_vllm_1
117
+ARG VLLM_REPO="https://github.com/ROCm/vllm.git"
118
+ARG VLLM_BRANCH="455_wip"
119
+ENV VLLM_REPO=${VLLM_REPO}
120
+ENV VLLM_BRANCH=${VLLM_BRANCH}
121
+ONBUILD RUN git clone ${VLLM_REPO} \
122
+ && cd vllm \
123
+ && git fetch -v --prune -- origin ${VLLM_BRANCH} \
124
+ && git checkout FETCH_HEAD \
125
+ && if [ ${VLLM_REPO} != "https://github.com/vllm-project/vllm.git" ] ; then \
126
+ git remote add upstream "https://github.com/vllm-project/vllm.git" \
127
+ && git fetch upstream ; fi
128
+FROM fetch_vllm_${REMOTE_VLLM} AS fetch_vllm
129
+
130
+# -----------------------
131
+# Rust build stage
132
+# Builds the `vllm-rs` frontend in a dedicated stage so the wheel build stages
133
+# don't need the rust toolchain or protoc.
134
+FROM fetch_vllm AS rust-build
135
+ARG COMMON_WORKDIR
136
+
137
+# protoc is used by tonic-build/prost-build.
138
+RUN apt-get update -q -y && apt-get install -q -y --no-install-recommends \
139
+ ca-certificates curl unzip \
140
+ && rm -rf /var/lib/apt/lists/*
141
+
142
+COPY tools/install_protoc.sh /tmp/install_protoc.sh
143
+RUN /tmp/install_protoc.sh && rm /tmp/install_protoc.sh
144
+
145
+# Cap cargo parallelism to avoid exhausting the AMD CI host's open-file limit
146
+# (rustc spawns enough concurrent processes to hit RLIMIT_NOFILE otherwise).
147
+ENV CARGO_BUILD_JOBS=4
148
+ENV CARGO_NET_RETRY=10
149
+ENV RUSTUP_MAX_RETRIES=10
150
+
151
+RUN --mount=type=cache,id=vllm-rocm-uv,target=/root/.cache/uv \
152
+ cd ${COMMON_WORKDIR}/vllm \
153
+ && uv pip install --system -r requirements/build/rust.txt
154
+
155
+# Build the release binary. Cargo's registry/git caches can be written by
156
+# concurrent BuildKit jobs on shared workers, so lock those cache mounts while
157
+# keeping the cache benefit. Do not cache target/, because stale target metadata
158
+# can outlive source updates across BuildKit cache reuse.
159
+RUN --mount=type=cache,id=vllm-rocm-cargo-registry,target=/root/.cargo/registry,sharing=locked \
160
+ --mount=type=cache,id=vllm-rocm-cargo-git,target=/root/.cargo/git,sharing=locked \
161
+ cd ${COMMON_WORKDIR}/vllm \
162
+ && bash build_rust.sh \
163
+ && test -x vllm/vllm-rs
164
+
165
+# -----------------------
166
+# vLLM native build stages
167
+#
168
+# csrc-build intentionally copies only files that affect ROCm native extension
169
+# compilation. That keeps unrelated CI/test/docs edits from invalidating the
170
+# expensive HIP/C++ build layer.
171
+FROM base AS csrc-build
172
+ARG COMMON_WORKDIR
173
+WORKDIR ${COMMON_WORKDIR}/vllm
174
+
175
+COPY requirements/rocm.txt requirements/rocm.txt
176
+COPY requirements/common.txt requirements/common.txt
177
+RUN --mount=type=cache,id=vllm-rocm-uv,target=/root/.cache/uv \
178
+ uv pip install --system -r requirements/rocm.txt
179
+
180
+# pyproject.toml is bind-mounted in the RUN step so metadata-only changes do
181
+# not invalidate the expensive native build layer.
182
+COPY setup.py CMakeLists.txt ./
183
+COPY tools/build_rust.py tools/build_rust.py
184
+COPY cmake cmake/
185
+COPY csrc csrc/
186
+COPY vllm/envs.py vllm/envs.py
187
+COPY vllm/__init__.py vllm/__init__.py
188
+
189
+ENV VLLM_TARGET_DEVICE=rocm
190
+ENV SETUPTOOLS_SCM_PRETEND_VERSION="0.0.0+rocm.csrc.build"
191
+
192
+RUN --mount=type=bind,source=pyproject.toml,target=${COMMON_WORKDIR}/vllm/pyproject.toml \
193
+ --mount=type=cache,id=vllm-rocm-ccache,target=/root/.cache/ccache \
194
+ export CCACHE_BASEDIR="$PWD" \
195
+ && echo "=== ccache stats before ROCm native build ===" \
196
+ && (ccache --show-stats || true) \
197
+ && (ccache --zero-stats || true) \
198
+ && EFFECTIVE_MAX_JOBS="${MAX_JOBS:-$(nproc)}" \
199
+ && echo "Building ROCm native extension wheel with MAX_JOBS=${EFFECTIVE_MAX_JOBS}" \
200
+ && LDFLAGS="-fuse-ld=mold" MAX_JOBS="${EFFECTIVE_MAX_JOBS}" python3 setup.py bdist_wheel --dist-dir=dist \
201
+ && test -d dist \
202
+ && ls dist/*.whl >/dev/null \
203
+ && echo "=== ccache stats after ROCm native build ===" \
204
+ && (ccache --show-stats || true)
205
+
206
+# Build the full vLLM ROCm wheel by reusing the native extension wheel from
207
+# csrc-build. This stage still rebuilds for Python/package changes, but skips
208
+# the expensive HIP/C++ compile when native inputs are unchanged.
209
+FROM fetch_vllm AS build_vllm
210
+ARG COMMON_WORKDIR
211
+ENV VLLM_TARGET_DEVICE=rocm
212
+
213
+COPY --from=csrc-build ${COMMON_WORKDIR}/vllm/dist /precompiled-wheels
214
+
215
+# Drop the pre-built Rust artifacts into the source tree. setup.py detects
216
+# them and ships them as-is, skipping the local Rust build.
217
+COPY --from=rust-build ${COMMON_WORKDIR}/vllm/vllm/vllm-rs ${COMMON_WORKDIR}/vllm/vllm/vllm-rs
218
+COPY --from=rust-build ${COMMON_WORKDIR}/vllm/vllm/_rust_*.so ${COMMON_WORKDIR}/vllm/vllm/
219
+
220
+RUN --mount=type=cache,id=vllm-rocm-uv,target=/root/.cache/uv \
221
+ cd vllm \
222
+ && uv pip install --system -r requirements/rocm.txt \
223
+ && export VLLM_USE_PRECOMPILED=1 \
224
+ && export VLLM_PRECOMPILED_WHEEL_LOCATION="$(ls /precompiled-wheels/*.whl)" \
225
+ && export VLLM_DOCKER_BUILD_CONTEXT=1 \
226
+ && echo "Packaging vLLM ROCm wheel using precompiled extensions from ${VLLM_PRECOMPILED_WHEEL_LOCATION}" \
227
+ && python3 setup.py bdist_wheel --dist-dir=dist \
228
+ && test -d dist \
229
+ && ls dist/*.whl >/dev/null
230
+FROM scratch AS export_vllm
231
+ARG COMMON_WORKDIR
232
+COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/dist/*.whl /
233
+COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/requirements /requirements
234
+COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/benchmarks /benchmarks
235
+COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/tests /tests
236
+COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/examples /examples
237
+COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/tools/install_torchcodec_rocm.sh /tools/install_torchcodec_rocm.sh
238
+COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/docker/Dockerfile.rocm /docker/
239
+COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/.buildkite /.buildkite
240
+COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/pyproject.toml /pyproject.toml
241
+COPY --from=build_vllm ${COMMON_WORKDIR}/vllm/vllm/v1 /vllm_v1
242
+
243
+# RIXL/UCX build stages
244
+FROM base AS build_rixl
245
+ARG RIXL_BRANCH="39be1de8"
246
+ARG RIXL_REPO="https://github.com/ROCm/RIXL.git"
247
+ARG UCX_BRANCH="bfb51733"
248
+ARG UCX_REPO="https://github.com/openucx/ucx.git"
249
+# ENV ROCM_PATH=/opt/rocm -> correct ROCM_PATH is set in base image
250
+ENV UCX_HOME=/usr/local/ucx
251
+ENV RIXL_HOME=/usr/local/rixl
252
+ENV RIXL_BENCH_HOME=/usr/local/rixl_bench
253
+
254
+# RIXL build system dependences and RDMA support
255
+RUN apt-get -y update && apt-get -y install autoconf libtool pkg-config \
256
+ libgrpc-dev \
257
+ libgrpc++-dev \
258
+ libprotobuf-dev \
259
+ protobuf-compiler-grpc \
260
+ libcpprest-dev \
261
+ libaio-dev \
262
+ librdmacm1 \
263
+ librdmacm-dev \
264
+ libibverbs1 \
265
+ libibverbs-dev \
266
+ ibverbs-utils \
267
+ rdmacm-utils \
268
+ ibverbs-providers \
269
+ && rm -rf /var/lib/apt/lists/*
270
+
271
+RUN --mount=type=cache,target=/root/.cache/uv \
272
+ uv pip install --system meson auditwheel patchelf tomlkit
273
+
274
+RUN --mount=type=cache,target=/root/.cache/ccache \
275
+ cd /usr/local/src && \
276
+ git clone ${UCX_REPO} && \
277
+ cd ucx && \
278
+ git checkout ${UCX_BRANCH} && \
279
+ ./autogen.sh && \
280
+ mkdir build && cd build && \
281
+ CC="ccache gcc" CXX="ccache g++" \
282
+ ../configure \
283
+ --prefix=/usr/local/ucx \
284
+ --enable-shared \
285
+ --disable-static \
286
+ --disable-doxygen-doc \
287
+ --enable-optimizations \
288
+ --enable-devel-headers \
289
+ --with-rocm=${ROCM_PATH} \
290
+ --with-verbs \
291
+ --with-dm \
292
+ --enable-mt && \
293
+ make -j$(nproc) && \
294
+ make install
295
+
296
+ENV PATH=/usr/local/ucx/bin:$PATH
297
+ENV LD_LIBRARY_PATH=${UCX_HOME}/lib:${LD_LIBRARY_PATH}
298
+
299
+RUN --mount=type=cache,target=/root/.cache/ccache \
300
+ git clone ${RIXL_REPO} /opt/rixl && \
301
+ cd /opt/rixl && \
302
+ git checkout ${RIXL_BRANCH} && \
303
+ CC="ccache gcc" CXX="ccache g++" \
304
+ meson setup build --prefix=${RIXL_HOME} \
305
+ --force-fallback-for=abseil-cpp \
306
+ -Ducx_path=${UCX_HOME} \
307
+ -Drocm_path=${ROCM_PATH} && \
308
+ cd build && \
309
+ ninja -j$(nproc) && \
310
+ ninja install
311
+
312
+# Generate RIXL wheel
313
+# Exclude libcore and libpull from auditwheel: transitive dependencies
314
+# that are not shipped in the wheel and vary across base images.
315
+RUN cd /opt/rixl && \
316
+ sed -i "s/--exclude 'libamdhip64\*'/--exclude 'libamdhip64*' --exclude 'libcore*' --exclude 'libpull*'/" \
317
+ contrib/build-wheel.sh && \
318
+ # The wheel build re-runs meson via meson-python; force the bundled abseil
319
+ sed -i 's|setup = \["-Dinstall_headers=false"\]|setup = ["-Dinstall_headers=false", "--force-fallback-for=abseil-cpp"]|' \
320
+ pyproject.toml && \
321
+ grep -q 'force-fallback-for' pyproject.toml && \
322
+ mkdir -p /app/install && \
323
+ _ucx_install_dir=${UCX_HOME} \
324
+ ./contrib/build-wheel.sh \
325
+ --output-dir /app/install \
326
+ --rocm-dir ${ROCM_PATH} \
327
+ --ucx-plugins-dir ${UCX_HOME}/lib/ucx \
328
+ --nixl-plugins-dir ${RIXL_HOME}/lib/x86_64-linux-gnu/plugins
329
+
330
+# ROCShmem build stage - split from DeepEP so changing DEEPEP_BRANCH does not
331
+# invalidate the slow ROCShmem build.
332
+FROM base AS build_rocshmem
333
+ARG ROCSHMEM_BRANCH="f0acb0c6"
334
+ARG ROCSHMEM_REPO="https://github.com/ROCm/rocm-systems.git"
335
+# DeepEP only supports gfx942 and gfx950; build ROCShmem for the same set so
336
+# it can be linked against DeepEP without arch mismatches.
337
+ARG DEEPEP_ROCM_ARCH="gfx942;gfx950"
338
+# ENV ROCM_PATH=/opt/rocm -> Correct rocm_path is set in base image
339
+ENV ROCSHMEM_DIR=/opt/rocshmem
340
+
341
+RUN --mount=type=cache,target=/root/.cache/ccache \
342
+ git clone --no-checkout --filter=blob:none ${ROCSHMEM_REPO} \
343
+ && cd rocm-systems \
344
+ && git sparse-checkout set --cone projects/rocshmem \
345
+ && git checkout ${ROCSHMEM_BRANCH} \
346
+ && mkdir -p projects/rocshmem/build \
347
+ && cd projects/rocshmem/build \
348
+ && CC="ccache gcc" CXX="ccache g++" INSTALL_PREFIX=${ROCSHMEM_DIR} \
349
+ bash ../scripts/build_configs/all_backends \
350
+ -DROCM_PATH=${ROCM_PATH} \
351
+ -DGPU_TARGETS="${DEEPEP_ROCM_ARCH}" \
352
+ -DUSE_EXTERNAL_MPI=OFF
353
+
354
+# DeepEP build stage - depends on ROCShmem, builds the HIP kernel wheel.
355
+FROM build_rocshmem AS build_deepep
356
+ARG DEEPEP_BRANCH="a9ea9774"
357
+ARG DEEPEP_REPO="https://github.com/ROCm/DeepEP.git"
358
+ARG DEEPEP_NIC="cx7"
359
+
360
+# Build DeepEP wheel. DeepEP looks for rocshmem at ROCSHMEM_DIR.
361
+# DeepEP only supports gfx942 and gfx950, so avoid gfx90a in the default list.
362
+RUN --mount=type=cache,target=/root/.cache/ccache \
363
+ export PYTORCH_ROCM_ARCH="gfx942;gfx950" \
364
+ && git clone ${DEEPEP_REPO} \
365
+ && cd DeepEP \
366
+ && git checkout ${DEEPEP_BRANCH} \
367
+ && LDFLAGS="-fuse-ld=mold" MAX_JOBS="${MAX_JOBS:-$(nproc)}" python3 setup.py --variant rocm --rocm-explicit-ctx --nic ${DEEPEP_NIC} bdist_wheel --dist-dir=/app/deep_install
368
+
369
+# MoRI runtime dependencies live in Dockerfile.rocm so NIC backend changes do
370
+# not force users to rebuild the long-lived Dockerfile.rocm_base image.
371
+FROM base AS mori_base
372
+ARG NIC_BACKEND
373
+ARG AINIC_VERSION
374
+ARG UBUNTU_CODENAME
375
+RUN /bin/bash -lc 'set -euo pipefail; \
376
+ \
377
+ install_ainic() { \
378
+ apt-get update && apt-get install -y --no-install-recommends ca-certificates curl gnupg apt-transport-https; \
379
+ rm -rf /var/lib/apt/lists/*; \
380
+ mkdir -p /etc/apt/keyrings; \
381
+ curl -fsSL https://repo.radeon.com/rocm/rocm.gpg.key | gpg --dearmor > /etc/apt/keyrings/amdainic.gpg; \
382
+ echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/amdainic.gpg] https://repo.radeon.com/amdainic/pensando/ubuntu/${AINIC_VERSION} ${UBUNTU_CODENAME} main" \
383
+ > /etc/apt/sources.list.d/amdainic.list; \
384
+ apt-get update && apt-get install -y --no-install-recommends \
385
+ libionic-dev \
386
+ ionic-common \
387
+ ; \
388
+ rm -rf /var/lib/apt/lists/*; \
389
+ }; \
390
+ \
391
+ # NOTE: requires FW 235.2.86.0 and kernel drivers on the host: \
392
+ # bnxt-en-dkms=1.10.3.235.2.86.0 bnxt-re-dkms=235.2.86.0 (from packages.broadcom.com PPA) \
393
+ install_bnxt() { \
394
+ install -m 0755 -d /etc/apt/keyrings; \
395
+ curl -fsSL https://packages.broadcom.com/artifactory/api/security/keypair/PackagesKey/public \
396
+ -o /etc/apt/keyrings/broadcom-nic.asc; \
397
+ chmod a+r /etc/apt/keyrings/broadcom-nic.asc; \
398
+ echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/broadcom-nic.asc] https://packages.broadcom.com/artifactory/ethernet-nic-debian-public jammy main" \
399
+ > /etc/apt/sources.list.d/broadcom-nic.list; \
400
+ apt-get update && apt-get install -y --no-install-recommends \
401
+ bnxt-rocelib=235.2.86.0 \
402
+ ; \
403
+ cp -a /usr/local/lib/x86_64-linux-gnu/libbnxt_re* /usr/local/lib/; \
404
+ ldconfig; \
405
+ rm -rf /var/lib/apt/lists/*; \
406
+ }; \
407
+ \
408
+ echo "[MORI] Install MoRI proxy deps"; \
409
+ pip install --quiet --ignore-installed blinker && \
410
+ pip install --quiet quart msgpack aiohttp pyzmq; \
411
+ echo "[MORI] NIC_BACKEND=${NIC_BACKEND}"; \
412
+ \
413
+ # NIC backend deps — mori auto-detects NIC at runtime (MORI_DEVICE_NIC env var override). \
414
+ # Only vendor packages are installed here for dlopen; no compile-time flags needed. \
415
+ case "${NIC_BACKEND}" in \
416
+ none) ;; \
417
+ all) install_ainic; install_bnxt ;; \
418
+ ainic) install_ainic ;; \
419
+ bnxt) install_bnxt ;; \
420
+ *) echo "ERROR: unknown NIC_BACKEND=${NIC_BACKEND}. Use one of: none, ainic, bnxt, all"; exit 2 ;; \
421
+ esac'
422
+
423
+# -----------------------
424
+# vLLM wheel release build stage (for building distributable wheels)
425
+# This stage pins dependencies to custom ROCm wheel versions and handles version detection
426
+FROM fetch_vllm AS build_vllm_wheel_release
427
+
428
+ARG COMMON_WORKDIR
429
+
430
+# Drop the pre-built Rust artifacts into the source tree. setup.py detects
431
+# them and ships them as-is, skipping the local Rust build.
432
+COPY --from=rust-build ${COMMON_WORKDIR}/vllm/vllm/vllm-rs ${COMMON_WORKDIR}/vllm/vllm/vllm-rs
433
+COPY --from=rust-build ${COMMON_WORKDIR}/vllm/vllm/_rust_*.so ${COMMON_WORKDIR}/vllm/vllm/
434
+
435
+# Create /install directory for custom wheels
436
+RUN mkdir -p /install
437
+
438
+# Copy custom ROCm wheels from docker/context if they exist
439
+# COPY ensures Docker cache is invalidated when wheels change
440
+# .keep file ensures directory always exists for COPY to work
441
+COPY docker/context/base-wheels/ /tmp/base-wheels/
442
+# This is how we know if we are building for a wheel release or not.
443
+# If there are not wheels found there, we are not building for a wheel release.
444
+# So we exit with an error. To skip this stage.
445
+RUN if [ -n "$(ls /tmp/base-wheels/*.whl 2>/dev/null)" ]; then \
446
+ echo "Found custom wheels - copying to /install"; \
447
+ cp /tmp/base-wheels/*.whl /install/ && \
448
+ echo "Copied custom wheels:"; \
449
+ ls -lh /install/; \
450
+ else \
451
+ echo "ERROR: No custom wheels found in docker/context/base-wheels/"; \
452
+ echo "Wheel releases require pre-built ROCm wheels."; \
453
+ exit 1; \
454
+ fi
455
+
456
+# GIT_REPO_CHECK: Verify repo is clean and tags are available (for release builds)
457
+# This matches CUDA's Dockerfile behavior for proper version detection via setuptools_scm
458
+ARG GIT_REPO_CHECK=0
459
+RUN if [ "$GIT_REPO_CHECK" != "0" ]; then \
460
+ echo "Running repository checks..."; \
461
+ cd vllm && bash tools/check_repo.sh; \
462
+ fi
463
+
464
+# Extract version from git BEFORE any modifications (pin_rocm_dependencies.py modifies requirements/rocm.txt)
465
+# This ensures setuptools_scm sees clean repo state for version detection
466
+RUN --mount=type=bind,source=.git,target=vllm/.git \
467
+ --mount=type=cache,target=/root/.cache/uv \
468
+ cd vllm \
469
+ && uv pip install --system setuptools_scm regex \
470
+ && VLLM_VERSION=$(python3 -c "import setuptools_scm; print(setuptools_scm.get_version())") \
471
+ && echo "Detected vLLM version: ${VLLM_VERSION}" \
472
+ && echo "${VLLM_VERSION}" > /tmp/vllm_version.txt
473
+
474
+# Fail if git-based package dependencies are found in requirements files
475
+# (uv doesn't handle git+ URLs well, and packages should be distributed on PyPI)
476
+# Extra notes: pip install is able to handle git+ URLs, but uv doesn't.
477
+RUN echo "Checking for git-based packages in requirements files..." \
478
+ && echo "Checking common.txt for git-based packages:" \
479
+ && if grep -q 'git+' ${COMMON_WORKDIR}/vllm/requirements/common.txt; then \
480
+ echo "ERROR: Git-based packages found in common.txt:"; \
481
+ grep 'git+' ${COMMON_WORKDIR}/vllm/requirements/common.txt; \
482
+ echo "Please publish these packages to PyPI instead of using git dependencies."; \
483
+ exit 1; \
484
+ else \
485
+ echo " ✓ No git-based packages found in common.txt"; \
486
+ fi \
487
+ && echo "Checking rocm.txt for git-based packages:" \
488
+ && if grep -q 'git+' ${COMMON_WORKDIR}/vllm/requirements/rocm.txt; then \
489
+ echo "ERROR: Git-based packages found in rocm.txt:"; \
490
+ grep 'git+' ${COMMON_WORKDIR}/vllm/requirements/rocm.txt; \
491
+ echo "Please publish these packages to PyPI instead of using git dependencies."; \
492
+ exit 1; \
493
+ else \
494
+ echo " ✓ No git-based packages found in rocm.txt"; \
495
+ fi \
496
+ && echo "All requirements files are clean - no git-based packages found"
497
+
498
+# Pin vLLM dependencies to exact versions of custom ROCm wheels
499
+# This ensures 'pip install vllm' automatically installs correct torch/triton/torchvision/amdsmi
500
+COPY tools/vllm-rocm/pin_rocm_dependencies.py /tmp/pin_rocm_dependencies.py
501
+RUN echo "Pinning vLLM dependencies to custom wheel versions..." \
502
+ && python3 /tmp/pin_rocm_dependencies.py /install ${COMMON_WORKDIR}/vllm/requirements/rocm.txt
503
+
504
+# Install dependencies using custom wheels from /install
505
+RUN --mount=type=cache,target=/root/.cache/uv \
506
+ cd vllm \
507
+ && echo "Building vLLM with custom wheels from /install" \
508
+ && uv pip install --system --find-links /install -r requirements/rocm.txt
509
+
510
+# Build wheel using pre-extracted version to avoid dirty state from modified requirements/rocm.txt
511
+# (setup.py auto-detects ccache/sccache in PATH)
512
+RUN --mount=type=bind,source=.git,target=vllm/.git \
513
+ --mount=type=cache,id=vllm-rocm-ccache,target=/root/.cache/ccache \
514
+ cd vllm \
515
+ && export CCACHE_BASEDIR="$PWD" \
516
+ && export SETUPTOOLS_SCM_PRETEND_VERSION=$(cat /tmp/vllm_version.txt) \
517
+ && echo "Building wheel with version: ${SETUPTOOLS_SCM_PRETEND_VERSION}" \
518
+ && MAX_JOBS="${MAX_JOBS:-$(nproc)}" python3 setup.py bdist_wheel --dist-dir=dist
519
+
520
+FROM scratch AS export_vllm_wheel_release
521
+ARG COMMON_WORKDIR
522
+COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/dist/*.whl /
523
+COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/requirements /requirements
524
+COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/benchmarks /benchmarks
525
+COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/tests /tests
526
+COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/examples /examples
527
+COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/tools/install_torchcodec_rocm.sh /tools/install_torchcodec_rocm.sh
528
+COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/docker/Dockerfile.rocm /docker/
529
+COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/.buildkite /.buildkite
530
+COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/pyproject.toml /pyproject.toml
531
+COPY --from=build_vllm_wheel_release ${COMMON_WORKDIR}/vllm/vllm/v1 /vllm_v1
532
+
533
+# -----------------------
534
+# CI base image (Tier 1) - stable, rarely changing CI dependencies.
535
+# Per-PR test builds pull this as CI_BASE_IMAGE so the test stage only layers
536
+# in the vLLM artifacts for the current commit.
537
+FROM mori_base AS ci_base
538
+ARG COMMON_WORKDIR
539
+
540
+# Update rdma-core to support latest rocshmem.
541
+ARG DEEPEP_NIC
542
+RUN if [ "${DEEPEP_NIC}" = "cx7" ] || [ "${DEEPEP_NIC}" = "io" ]; then \
543
+ git clone --branch v62.0 --depth 1 https://github.com/linux-rdma/rdma-core.git /tmp/rdma-core && \
544
+ cd /tmp/rdma-core && \
545
+ mkdir -p build && cd build && \
546
+ cmake -GNinja -DCMAKE_INSTALL_PREFIX=/usr -DNO_MAN_PAGES=1 .. && \
547
+ ninja && ninja install && ldconfig && rm -rf /tmp/rdma-core; \
548
+fi
549
+
550
+# Install RIXL + DeepEP wheels.
551
+RUN --mount=type=bind,from=build_rixl,src=/app/install,target=/rixl_install \
552
+ --mount=type=bind,from=build_deepep,src=/app/deep_install,target=/deep_install \
553
+ uv pip install --system /rixl_install/*.whl /deep_install/*.whl
554
+
555
+# Copy ROCShmem runtime libraries.
556
+COPY --from=build_rocshmem /opt/rocshmem /opt/rocshmem
557
+
558
+# RDMA userspace libraries plus FFmpeg dev libs needed by torchcodec.
559
+RUN apt-get update -q -y && apt-get install -q -y --no-install-recommends \
560
+ librdmacm1 \
561
+ libibverbs1 \
562
+ ibverbs-providers \
563
+ ibverbs-utils \
564
+ pkg-config ffmpeg libavcodec-dev libavformat-dev libavutil-dev \
565
+ libswscale-dev libavdevice-dev libavfilter-dev libswresample-dev \
566
+ && rm -rf /var/lib/apt/lists/*
567
+
568
+# Install torchcodec from source for ROCm/torch ABI compatibility.
569
+COPY tools/install_torchcodec_rocm.sh /tmp/install_torchcodec.sh
570
+RUN --mount=type=cache,target=/root/.cache/uv \
571
+ --mount=type=cache,target=/root/.cache/pip \
572
+ --mount=type=cache,target=/root/.cache/torchcodec-wheels \
573
+ bash /tmp/install_torchcodec.sh \
574
+ && rm /tmp/install_torchcodec.sh \
575
+ && apt-get clean && rm -rf /var/lib/apt/lists/*
576
+
577
+# Pre-install shared ROCm runtime dependencies.
578
+COPY requirements/common.txt requirements/rocm.txt /tmp/ci-base-requirements/
579
+RUN --mount=type=cache,target=/root/.cache/uv \
580
+ uv pip install --system -r /tmp/ci-base-requirements/rocm.txt \
581
+ && rm -rf /tmp/ci-base-requirements
582
+
583
+# Enable fast and less brittle model downloads in tests.
584
+ENV HF_XET_HIGH_PERFORMANCE=1
585
+ENV HF_HUB_DOWNLOAD_TIMEOUT=60
586
+
587
+# Pre-install vLLM test dependencies.
588
+COPY requirements/test/rocm.txt /tmp/rocm-test-reqs.txt
589
+RUN --mount=type=cache,target=/root/.cache/uv \
590
+ uv pip install --system -r /tmp/rocm-test-reqs.txt
591
+
592
+# Rebuild fastsafetensors from source so its C++ extension is compiled with
593
+# USE_ROCM and can detect libamdhip64.so at runtime.
594
+RUN --mount=type=cache,target=/root/.cache/pip \
595
+ FASTSAFETENSORS_REQ="$(grep -E '^fastsafetensors(==| @ )' /tmp/rocm-test-reqs.txt | head -1)" \
596
+ && test -n "${FASTSAFETENSORS_REQ}" \
597
+ && python3 -m pip install --force-reinstall --no-deps \
598
+ --no-binary fastsafetensors "${FASTSAFETENSORS_REQ}" \
599
+ && rm /tmp/rocm-test-reqs.txt
600
+
601
+# Set MIOPEN ENVS to resolve performance regressions in MIOpen 3D convolution kernel.
602
+# See: https://github.com/pytorch/pytorch/issues/169857
603
+ENV MIOPEN_DEBUG_CONV_DIRECT=0
604
+ENV MIOPEN_DEBUG_CONV_GEMM=0
605
+
606
+# Use legacy IPC mode for HSA to avoid GPU memory pinning issues with UCX rocm_ipc.
607
+# See: https://github.com/ROCm/rocm-libraries/issues/6266
608
+ENV HSA_ENABLE_IPC_MODE_LEGACY=1
609
+
610
+# ROCm profiler limits workaround.
611
+RUN echo "ROCTRACER_MAX_EVENTS=10000000" > ${COMMON_WORKDIR}/libkineto.conf
612
+ENV KINETO_CONFIG="${COMMON_WORKDIR}/libkineto.conf"
613
+
614
+# Install vllm_test_utils in ci_base for ci_base + wheel parity.
615
+COPY tests/vllm_test_utils /tmp/vllm_test_utils
616
+RUN --mount=type=cache,target=/root/.cache/uv \
617
+ uv pip install --system /tmp/vllm_test_utils \
618
+ && rm -rf /tmp/vllm_test_utils
619
+
620
+# -----------------------
621
+# Test vLLM image (Tier 2) - vLLM-only layer on top of ci_base.
622
+FROM ${CI_BASE_IMAGE} AS test
623
+ARG COMMON_WORKDIR
624
+
625
+# Install the vLLM wheel (--no-deps: all deps already in ci_base).
626
+RUN --mount=type=bind,from=export_vllm,src=/,target=/install \
627
+ --mount=type=cache,target=/root/.cache/uv \
628
+ cd /install \
629
+ && uv pip install --system --no-deps *.whl
630
+
631
+# Store the vLLM wheel in the image for python-only install tests.
632
+COPY --from=export_vllm /*.whl /opt/vllm-wheels/
633
+
634
+WORKDIR /vllm-workspace
635
+COPY --from=build_vllm ${COMMON_WORKDIR}/vllm /vllm-workspace
636
+
637
+# Copy in the v1 package (for python-only install test group).
638
+COPY --from=export_vllm /vllm_v1 /usr/local/lib/python${PYTHON_VERSION}/dist-packages/vllm/v1
639
+
640
+# Hide source under src/ so it won't shadow the installed package in tests.
641
+RUN mkdir src && mv vllm src/vllm
642
+
643
+# -----------------------
644
+# Final vLLM image
645
+FROM mori_base AS final
646
+
647
+RUN python3 -m pip install --upgrade pip && rm -rf /var/lib/apt/lists/*
648
+
649
+# Clean up sccache from release image (not needed at runtime)
650
+# This removes the binary and wrappers that may have been installed during build
651
+RUN rm -f /usr/bin/sccache || true \
652
+ && rm -rf /opt/sccache-wrappers || true
653
+
654
+# Unset sccache environment variables for the release image
655
+# This prevents S3 bucket config from leaking into production images
656
+ENV SCCACHE_BUCKET=
657
+ENV SCCACHE_REGION=
658
+ENV SCCACHE_ENDPOINT=
659
+ENV SCCACHE_S3_NO_CREDENTIALS=
660
+ENV SCCACHE_IDLE_TIMEOUT=
661
+
662
+# Error related to odd state for numpy 1.20.3 where there is no METADATA etc, but an extra LICENSES_bundled.txt.
663
+# Manually remove it so that later steps of numpy upgrade can continue
664
+RUN case "$(which python3)" in \
665
+ *"/opt/conda/envs/py_3.9"*) \
666
+ rm -rf /opt/conda/envs/py_3.9/lib/python3.9/site-packages/numpy-1.20.3.dist-info/;; \
667
+ *) ;; esac
668
+
669
+RUN --mount=type=cache,target=/root/.cache/uv \
670
+ uv pip install --system --upgrade huggingface-hub[cli]
671
+
672
+# Install vLLM using uv (inherited from base stage)
673
+# Note: No -U flag to avoid upgrading PyTorch ROCm to CUDA version
674
+RUN --mount=type=bind,from=export_vllm,src=/,target=/install \
675
+ --mount=type=cache,target=/root/.cache/uv \
676
+ cd /install \
677
+ && uv pip install --system -r requirements/rocm.txt \
678
+ && pip uninstall -y vllm \
679
+ && uv pip install --system *.whl
680
+
681
+# Install RIXL wheel
682
+RUN --mount=type=bind,from=build_rixl,src=/app/install,target=/rixl_install \
683
+ uv pip install --system /rixl_install/*.whl
684
+
685
+ARG COMMON_WORKDIR
686
+ARG BASE_IMAGE
687
+ARG NIC_BACKEND
688
+ARG AINIC_VERSION
689
+
690
+# Copy over the benchmark scripts as well
691
+COPY --from=export_vllm /benchmarks ${COMMON_WORKDIR}/vllm/benchmarks
692
+COPY --from=export_vllm /examples ${COMMON_WORKDIR}/vllm/examples
693
+COPY --from=export_vllm /docker ${COMMON_WORKDIR}/vllm/docker
694
+
695
+# Use legacy IPC mode for HSA to avoid GPU memory pinning issues with UCX rocm_ipc
696
+# See: https://github.com/ROCm/rocm-libraries/issues/6266
697
+ENV HSA_ENABLE_IPC_MODE_LEGACY=1
698
+
699
+ENV TOKENIZERS_PARALLELISM=false
700
+
701
+# ENV that can improve safe tensor loading, and end-to-end time
702
+ENV SAFETENSORS_FAST_GPU=1
703
+
704
+# Performance environment variable.
705
+ENV HIP_FORCE_DEV_KERNARG=1
706
+
707
+# Workaround for ROCm profiler limits
708
+RUN echo "ROCTRACER_MAX_EVENTS=10000000" > ${COMMON_WORKDIR}/libkineto.conf
709
+ENV KINETO_CONFIG="${COMMON_WORKDIR}/libkineto.conf"
710
+RUN echo "VLLM_BASE_IMAGE=${BASE_IMAGE}" >> ${COMMON_WORKDIR}/versions.txt \
711
+ && echo "MORI_NIC_BACKEND=${NIC_BACKEND}" >> ${COMMON_WORKDIR}/versions.txt \
712
+ && echo "AINIC_VERSION=${AINIC_VERSION}" >> ${COMMON_WORKDIR}/versions.txt
713
+
714
+# Download bench scripts for gfx1250
715
+RUN curl -k -O https://raw.githubusercontent.com/ROCm/vllm/refs/heads/gfx1250_bench/vllm_smoketest.sh
716
+
717
+
718
+### Install triton from upstream for AITER Deps TODO: (JPVILLAM) If possible to get this on whls it would be better
719
+RUN pip3 uninstall -y triton && \
720
+ git clone https://github.com/triton-lang/triton.git && \
721
+ cd triton && \
722
+ git checkout c517f38c && \
723
+ TRITON_APPEND_CMAKE_ARGS="-DCMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH=FALSE" pip3 install .
724
+
725
+CMD ["/bin/bash"]
726
+
727
+#Set entrypoint for vllm-openai official images
728
+FROM final AS vllm-openai
729
+ENTRYPOINT ["vllm", "serve"]