[CI/Build][Hardware][NVIDIA] Add opt-in Rubin Docker builds (#53443)

Signed-off-by: Shang Wang <samshang.wang@mail.utoronto.ca> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>

Shang Wang committed Aug 27, 2026 at 12:06 UTC 9650dc73e249688d9f4dac1f24a3f6f09e8c04a1
7 files changed +429 -24
docker/Dockerfile
+255 -22
@@ -25,6 +25,9 @@
25 ARG CUDA_VERSION=13.0.3
26 ARG PYTHON_VERSION=3.12
27 ARG UBUNTU_VERSION=24.04
28 +ARG INSTALL_RUBIN_PRERELEASE=false
29 +ARG TRITON_INSTALL_FROM_SOURCE_REPO=
30 +ARG TRITON_INSTALL_FROM_SOURCE_REVISION=
31 # DeepEPv2 requires NCCL >= 2.30.4 (GIN backend).
32 # This version is used for CUDA 12+ builds to keep the DeepEP build and
33 # runtime NCCL versions compatible.
@@ -94,6 +97,7 @@ ARG INSTALL_KV_CONNECTORS=false
97 FROM ${BUILD_BASE_IMAGE} AS base
98
99 ARG TARGETPLATFORM
100 +ARG INSTALL_RUBIN_PRERELEASE
101 ARG CUDA_VERSION
102 ARG PYTHON_VERSION
103 ARG USE_SCCACHE
@@ -205,7 +209,13 @@ COPY requirements/cuda.txt requirements/cuda.txt
209 COPY use_existing_torch.py use_existing_torch.py
210 COPY pyproject.toml pyproject.toml
211 RUN --mount=type=cache,target=/opt/uv/cache \
208 - if [ "$(echo $CUDA_VERSION | cut -d. -f1)" = "12" ]; then \
212 + --mount=type=bind,source=requirements,target=/tmp/vllm-requirements,ro \
213 + if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ] && \
214 + [ ! -f /tmp/vllm-requirements/rubin-prerelease.txt ]; then \
215 + echo "INSTALL_RUBIN_PRERELEASE=true requires requirements/rubin-prerelease.txt" >&2; \
216 + exit 1; \
217 + fi \
218 + && if [ "$(echo $CUDA_VERSION | cut -d. -f1)" = "12" ]; then \
219 sed -i 's/^nvidia-cutlass-dsl\[cu13\]/nvidia-cutlass-dsl/' requirements/cuda.txt; \
220 sed -i 's/^humming-kernels\[cu13\]/humming-kernels[cu12]/' requirements/cuda.txt; \
221 fi \
@@ -216,7 +226,16 @@ RUN --mount=type=cache,target=/opt/uv/cache \
226 printf 'cython<3.3\n' > /tmp/build-constraints.txt \
227 && export UV_BUILD_CONSTRAINT=/tmp/build-constraints.txt; \
228 fi \
219 - && if [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
229 + && if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
230 + echo "Installing Rubin prerelease requirements..." \
231 + && /opt/venv/bin/python3 use_existing_torch.py --prefix \
232 + && uv pip install --python /opt/venv/bin/python3 \
233 + -r /tmp/vllm-requirements/rubin-prerelease.txt \
234 + && uv pip install --python /opt/venv/bin/python3 \
235 + -r requirements/cuda.txt \
236 + && uv pip install --python /opt/venv/bin/python3 \
237 + -r /tmp/vllm-requirements/rubin-prerelease.txt; \
238 + elif [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
239 echo "Installing torch nightly..." \
240 && uv pip install --python /opt/venv/bin/python3 torch torchaudio torchvision --pre \
241 --index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/nightly/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.') \
@@ -229,6 +248,33 @@ RUN --mount=type=cache,target=/opt/uv/cache \
248 --extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
249 fi
250
251 +# CUDA 13.4 Rubin images need a compatibility link for the prerelease
252 +# PyTorch wheel's libcurand.so.11 dependency. CUDA 13.5 must use its native
253 +# libcurand.so.11 instead.
254 +RUN if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
255 + CUDA_MAJOR_MINOR=$(echo "${CUDA_VERSION}" | cut -d. -f1,2) \
256 + && if [ "${CUDA_MAJOR_MINOR}" = "13.4" ]; then \
257 + CURAND_LIBRARY=$(find -H /usr/local/cuda -name libcurand.so.10 \
258 + -print -quit) \
259 + && test -n "${CURAND_LIBRARY}" \
260 + && ln -sf "${CURAND_LIBRARY}" \
261 + /usr/local/cuda/lib64/libcurand.so.11; \
262 + elif [ "${CUDA_MAJOR_MINOR}" = "13.5" ]; then \
263 + CURAND_LIBRARY=$(find -H /usr/local/cuda -name libcurand.so.11 \
264 + -print -quit) \
265 + && test -n "${CURAND_LIBRARY}" \
266 + && ! readlink -f "${CURAND_LIBRARY}" | grep -q 'libcurand\.so\.10'; \
267 + else \
268 + echo "Unsupported Rubin CUDA version: ${CUDA_MAJOR_MINOR}" >&2; \
269 + exit 1; \
270 + fi \
271 + && printf '%s\n' \
272 + /opt/venv/lib \
273 + "/opt/venv/lib/python${PYTHON_VERSION}/site-packages/nvpl/lib" \
274 + > /etc/ld.so.conf.d/vllm-rubin-python.conf \
275 + && ldconfig; \
276 + fi
277 +
278 # Track PyTorch lib versions used during build and match in downstream instances.
279 # We do this for both nightly and release so we can strip dependencies/*.txt as needed.
280 # Otherwise library dependencies can upgrade/downgrade torch incorrectly.
@@ -237,9 +283,8 @@ RUN --mount=type=cache,target=/opt/uv/cache \
283 && TORCH_LIB_VERSIONS=$(cat torch_lib_versions.txt | xargs) \
284 && echo "Installed torch libs: ${TORCH_LIB_VERSIONS}"
285
240 -# CUDA arch list used by torch
241 -# Explicitly set the list to avoid issues with torch 2.2
242 -# See https://github.com/pytorch/pytorch/pull/123243
286 +# CUDA arch list used by torch. Keep this explicit so GPU-less container builds
287 +# do not depend on PyTorch's changing common-architecture fallback.
288 # From versions.json: .torch.cuda_arch_list
289 # Do not add +PTX here: vLLM filters torch's top-level PTX flag when it
290 # converts global gencode flags into per-kernel arch lists. If a specific
@@ -258,7 +303,7 @@ ARG USE_SCCACHE
303 ARG SCCACHE_ENDPOINT
304
305 # Install native tools needed only for Rust builds.
261 -RUN dnf install -y --setopt=install_weak_deps=False make \
306 +RUN dnf install -y --setopt=install_weak_deps=False make perl-core \
307 && dnf clean all \
308 && rm -rf /var/cache/dnf
309
@@ -310,6 +355,7 @@ RUN --mount=type=cache,target=/root/.cargo/registry,sharing=locked \
355 #################### CSRC BUILD IMAGE ####################
356 FROM base AS csrc-build
357
358 +ARG INSTALL_RUBIN_PRERELEASE
359 ARG PIP_INDEX_URL UV_INDEX_URL
360 ARG PIP_EXTRA_INDEX_URL UV_EXTRA_INDEX_URL
361 ARG PYTORCH_CUDA_INDEX_BASE_URL
@@ -330,7 +376,11 @@ ENV UV_INDEX_STRATEGY="unsafe-best-match"
376 ENV UV_LINK_MODE=copy
377
378 RUN --mount=type=cache,target=/opt/uv/cache \
333 - if [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
379 + if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
380 + echo "Installing build requirements with Rubin prerelease PyTorch..." \
381 + && python3 use_existing_torch.py --prefix \
382 + && uv pip install --python /opt/venv/bin/python3 -r requirements/build/cuda.txt; \
383 + elif [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
384 echo "Installing build requirements without torch..." \
385 && python3 use_existing_torch.py --prefix \
386 && uv pip install --python /opt/venv/bin/python3 -r requirements/build/cuda.txt \
@@ -370,9 +420,10 @@ ARG VLLM_MAIN_CUDA_VERSION=""
420 # Use dummy version for csrc-build wheel (only .so files are extracted, version doesn't matter)
421 ENV SETUPTOOLS_SCM_PRETEND_VERSION="0.0.0+csrc.build"
422
373 -# Use existing torch for nightly builds
423 +# Use existing torch for nightly and Rubin prerelease builds
424 RUN --mount=type=cache,target=/opt/uv/cache \
375 - if [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
425 + if [ "${PYTORCH_NIGHTLY}" = "1" ] || \
426 + [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
427 python3 use_existing_torch.py --prefix; \
428 fi
429
@@ -424,7 +475,12 @@ RUN --mount=type=cache,target=/root/.cache/ccache \
475 # Build DeepEP - runs in PARALLEL with csrc-build
476 # This stage is independent and doesn't affect csrc cache
477 FROM base AS extensions-build
478 +ARG TARGETARCH
479 ARG CUDA_VERSION
480 +ARG INSTALL_RUBIN_PRERELEASE
481 +ARG TRITON_INSTALL_FROM_SOURCE_REPO
482 +ARG TRITON_INSTALL_FROM_SOURCE_REVISION
483 +ARG max_jobs
484
485 # This timeout (in seconds) is necessary when installing some dependencies via uv since it's likely to time out
486 ENV UV_HTTP_TIMEOUT=500
@@ -441,6 +497,20 @@ ARG NVSHMEM_VER
497 ARG NCCL_VERSION
498 RUN --mount=type=cache,target=/opt/uv/cache \
499 mkdir -p /tmp/ep_kernels_workspace/dist && \
500 + if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
501 + # The Rubin CUDA builder provides NCCL in its architecture-specific \
502 + # toolkit directory rather than as a Python package. Give DeepEP a \
503 + # stable prefix that also exists in the Ubuntu runtime image. \
504 + NCCL_HEADER=$(find /usr/local/cuda/targets -name nccl.h -print -quit) \
505 + && test -n "${NCCL_HEADER}" \
506 + && NCCL_LIBRARY=$(find -H /usr/local/cuda/targets \
507 + -name libnccl.so.2 -print -quit) \
508 + && test -n "${NCCL_LIBRARY}" \
509 + && ln -sf "${NCCL_HEADER}" /usr/include/nccl.h \
510 + && ln -sf "${NCCL_LIBRARY}" /usr/lib/libnccl.so.2 \
511 + && ln -sf libnccl.so.2 /usr/lib/libnccl.so \
512 + && export EP_NCCL_ROOT_DIR=/usr; \
513 + fi && \
514 CUDA_MAJOR=$(echo $CUDA_VERSION | cut -d. -f1) && \
515 if [ -n "$NCCL_VERSION" ]; then \
516 echo "nvidia-nccl-cu${CUDA_MAJOR}==${NCCL_VERSION}" \
@@ -454,11 +524,56 @@ RUN --mount=type=cache,target=/opt/uv/cache \
524 ${DEEPEP_COMMIT_HASH:+--deepep-ref "$DEEPEP_COMMIT_HASH"} \
525 ${NVSHMEM_VER:+--nvshmem-ver "$NVSHMEM_VER"} && \
526 find /tmp/ep_kernels_workspace/nvshmem -name '*.a' -delete
527 +
528 +# Build Triton from source when a repository is configured. Triton 3.8 pins
529 +# ptxas-blackwell 13.3, which cannot assemble SM107. Rubin CUDA 13.4 and 13.5
530 +# builds use their SM107-capable system ptxas during the wheel build and at
531 +# runtime.
532 +COPY tools/build_triton_from_source.sh /tmp/build_triton_from_source.sh
533 +RUN --mount=type=cache,target=/opt/uv/cache \
534 + --mount=type=cache,id=triton-source-${TARGETARCH},target=/root/.triton,sharing=locked \
535 + --mount=type=cache,id=triton-source-ccache-${TARGETARCH},target=/root/.cache/ccache,sharing=locked \
536 + set -eux; \
537 + TRITON_WORKSPACE=/tmp/triton_from_source_workspace; \
538 + if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ] \
539 + && [ -z "${TRITON_INSTALL_FROM_SOURCE_REPO}" ]; then \
540 + echo "Rubin prerelease builds require TRITON_INSTALL_FROM_SOURCE_REPO" >&2; \
541 + exit 1; \
542 + elif [ -z "${TRITON_INSTALL_FROM_SOURCE_REPO}" ] \
543 + && [ -n "${TRITON_INSTALL_FROM_SOURCE_REVISION}" ]; then \
544 + echo "TRITON_INSTALL_FROM_SOURCE_REVISION requires TRITON_INSTALL_FROM_SOURCE_REPO" >&2; \
545 + exit 1; \
546 + elif [ -n "${TRITON_INSTALL_FROM_SOURCE_REPO}" ]; then \
547 + dnf install -y --setopt=install_weak_deps=False zlib-devel; \
548 + dnf clean all; \
549 + rm -rf /var/cache/dnf; \
550 + CUDA_MAJOR_MINOR=$(echo "${CUDA_VERSION}" | cut -d. -f1,2); \
551 + if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
552 + case "${CUDA_MAJOR_MINOR}" in \
553 + 13.4|13.5) \
554 + export TRITON_PTXAS_BLACKWELL_PATH=/usr/local/cuda/bin/ptxas \
555 + ;; \
556 + *) \
557 + echo "Unsupported Rubin CUDA version: ${CUDA_MAJOR_MINOR}" >&2; \
558 + exit 1 \
559 + ;; \
560 + esac; \
561 + fi; \
562 + TRITON_WORKSPACE="${TRITON_WORKSPACE}" \
563 + MAX_JOBS="${max_jobs:-}" \
564 + bash /tmp/build_triton_from_source.sh; \
565 + else \
566 + mkdir -p "${TRITON_WORKSPACE}/dist"; \
567 + printf '%s\n' disabled > "${TRITON_WORKSPACE}/dist/build-state"; \
568 + (cd "${TRITON_WORKSPACE}/dist" \
569 + && sha256sum build-state > wheel.sha256); \
570 + fi
571 #################### EXTENSIONS BUILD IMAGE ####################
572
573 #################### WHEEL BUILD IMAGE ####################
574 FROM base AS build
575 ARG TARGETPLATFORM
576 +ARG INSTALL_RUBIN_PRERELEASE
577
578 ARG PIP_INDEX_URL UV_INDEX_URL
579 ARG PIP_EXTRA_INDEX_URL UV_EXTRA_INDEX_URL
@@ -480,7 +595,11 @@ ENV UV_INDEX_STRATEGY="unsafe-best-match"
595 ENV UV_LINK_MODE=copy
596
597 RUN --mount=type=cache,target=/opt/uv/cache \
483 - if [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
598 + if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
599 + echo "Installing build requirements with Rubin prerelease PyTorch..." \
600 + && python3 use_existing_torch.py --prefix \
601 + && uv pip install --python /opt/venv/bin/python3 -r requirements/build/cuda.txt; \
602 + elif [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
603 echo "Installing build requirements without torch..." \
604 && python3 use_existing_torch.py --prefix \
605 && uv pip install --python /opt/venv/bin/python3 -r requirements/build/cuda.txt \
@@ -514,10 +633,15 @@ ENV VLLM_TARGET_DEVICE=${vllm_target_device}
633 # Skip adding +precompiled suffix to version (preserves git-derived version)
634 ENV VLLM_SKIP_PRECOMPILED_VERSION_SUFFIX=1
635
517 -# Use existing torch for nightly builds
636 +# Use existing torch for nightly and Rubin prerelease builds
637 RUN --mount=type=cache,target=/opt/uv/cache \
519 - if [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
638 + if [ "${PYTORCH_NIGHTLY}" = "1" ] || \
639 + [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
640 python3 use_existing_torch.py --prefix; \
641 + fi \
642 + && if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
643 + sed -Ei '/^[[:space:]]*(flashinfer-python|nvidia-cutlass-dsl\[cu13\])[[:space:]]*==/Id' \
644 + requirements/cuda.txt; \
645 fi
646
647 # Build the vLLM wheel
@@ -607,6 +731,7 @@ RUN --mount=type=cache,target=/opt/uv/cache \
731 # image with vLLM installed
732 FROM ${FINAL_BASE_IMAGE} AS vllm-runtime-base
733
734 +ARG INSTALL_RUBIN_PRERELEASE
735 ARG CUDA_VERSION
736 ARG PYTHON_VERSION
737 ARG NCCL_VERSION
@@ -614,6 +739,11 @@ ARG DEADSNAKES_MIRROR_URL
739 ARG DEADSNAKES_GPGKEY_URL
740 ARG GET_PIP_URL
741
742 +# Keep the output image's CUDA metadata aligned with the selected toolkit.
743 +# This also normalizes prerelease base images with four-component metadata for
744 +# OCI runtimes that evaluate NVIDIA's CUDA driver requirement.
745 +ENV CUDA_VERSION=${CUDA_VERSION}
746 +
747 ENV DEBIAN_FRONTEND=noninteractive
748 WORKDIR /vllm-workspace
749
@@ -676,6 +806,34 @@ RUN CUDA_VERSION_DASH=$(echo $CUDA_VERSION | cut -d. -f1,2 | tr '.' '-') && \
806 numactl && \
807 rm -rf /var/lib/apt/lists/*
808
809 +# Apply the CUDA 13.4-only libcurand compatibility link described in the build
810 +# stage. CUDA 13.5 uses its native libcurand.so.11. DeepEP expects NCCL directly
811 +# under its configured /usr prefix, while Ubuntu installs it in a multiarch
812 +# subdirectory.
813 +RUN if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
814 + CUDA_MAJOR_MINOR=$(echo "${CUDA_VERSION}" | cut -d. -f1,2) \
815 + && if [ "${CUDA_MAJOR_MINOR}" = "13.4" ]; then \
816 + CURAND_LIBRARY=$(find -H /usr/local/cuda -name libcurand.so.10 \
817 + -print -quit) \
818 + && test -n "${CURAND_LIBRARY}" \
819 + && ln -sf "${CURAND_LIBRARY}" \
820 + /usr/local/cuda/lib64/libcurand.so.11; \
821 + elif [ "${CUDA_MAJOR_MINOR}" = "13.5" ]; then \
822 + CURAND_LIBRARY=$(find -H /usr/local/cuda -name libcurand.so.11 \
823 + -print -quit) \
824 + && test -n "${CURAND_LIBRARY}" \
825 + && ! readlink -f "${CURAND_LIBRARY}" | grep -q 'libcurand\.so\.10'; \
826 + else \
827 + echo "Unsupported Rubin CUDA version: ${CUDA_MAJOR_MINOR}" >&2; \
828 + exit 1; \
829 + fi \
830 + && NCCL_LIBRARY=$(find /usr/lib -name libnccl.so.2 -print -quit) \
831 + && test -n "${NCCL_LIBRARY}" \
832 + && ln -sf "${NCCL_LIBRARY}" /usr/lib/libnccl.so.2 \
833 + && ln -sf libnccl.so.2 /usr/lib/libnccl.so \
834 + && ldconfig; \
835 + fi
836 +
837 # Install uv for faster pip installs
838 RUN python3 -m pip install uv
839
@@ -753,12 +911,33 @@ ARG PYTORCH_CUDA_INDEX_BASE_URL
911 COPY requirements/common.txt /tmp/common.txt
912 COPY requirements/cuda.txt /tmp/requirements-cuda.txt
913 RUN --mount=type=cache,target=/opt/uv/cache \
914 + --mount=type=bind,source=requirements,target=/tmp/vllm-requirements,ro \
915 + if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ] && \
916 + [ ! -f /tmp/vllm-requirements/rubin-prerelease.txt ]; then \
917 + echo "INSTALL_RUBIN_PRERELEASE=true requires requirements/rubin-prerelease.txt" >&2; \
918 + exit 1; \
919 + fi && \
920 if [ "$(echo $CUDA_VERSION | cut -d. -f1)" = "12" ]; then \
921 sed -i 's/^nvidia-cutlass-dsl\[cu13\]/nvidia-cutlass-dsl/' /tmp/requirements-cuda.txt; \
922 sed -i 's/^humming-kernels\[cu13\]/humming-kernels[cu12]/' /tmp/requirements-cuda.txt; \
923 fi && \
760 - uv pip install --system -r /tmp/requirements-cuda.txt \
761 - --extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.') && \
924 + if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
925 + uv pip install --system \
926 + -r /tmp/vllm-requirements/rubin-prerelease.txt \
927 + && sed -Ei '/^[[:space:]]*(torch|torchvision|torchaudio)[[:space:]]*==/Id' \
928 + /tmp/requirements-cuda.txt \
929 + && uv pip install --system -r /tmp/requirements-cuda.txt \
930 + && uv pip install --system \
931 + -r /tmp/vllm-requirements/rubin-prerelease.txt \
932 + && printf '%s\n' \
933 + "/usr/local/lib/python${PYTHON_VERSION}/dist-packages/nvpl/lib" \
934 + > /etc/ld.so.conf.d/vllm-rubin-python.conf \
935 + && ldconfig; \
936 + else \
937 + uv pip install --system \
938 + -r /tmp/requirements-cuda.txt \
939 + --extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
940 + fi && \
941 rm /tmp/requirements-cuda.txt /tmp/common.txt
942
943 # Install FlashInfer JIT cache (requires CUDA-version-specific index URL)
@@ -766,8 +945,10 @@ RUN --mount=type=cache,target=/opt/uv/cache \
945 # From versions.json: .flashinfer.version
946 ARG FLASHINFER_VERSION=0.6.17
947 RUN --mount=type=cache,target=/opt/uv/cache \
769 - uv pip install --system flashinfer-jit-cache==${FLASHINFER_VERSION} \
770 - --index-url https://flashinfer.ai/whl/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.')
948 + if [ "${INSTALL_RUBIN_PRERELEASE}" != "true" ]; then \
949 + uv pip install --system flashinfer-jit-cache==${FLASHINFER_VERSION} \
950 + --index-url https://flashinfer.ai/whl/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
951 + fi
952
953 # ============================================================
954 # OPENAI API SERVER DEPENDENCIES
@@ -781,12 +962,18 @@ ARG GDRCOPY_OS_VERSION=Ubuntu24_04
962 ARG TARGETPLATFORM
963 COPY tools/install_gdrcopy.sh /tmp/install_gdrcopy.sh
964 RUN set -eux; \
784 - case "${TARGETPLATFORM}" in \
785 - linux/arm64) UUARCH="aarch64" ;; \
786 - linux/amd64) UUARCH="x64" ;; \
787 - *) echo "Unsupported TARGETPLATFORM: ${TARGETPLATFORM}" >&2; exit 1 ;; \
788 - esac; \
789 - /tmp/install_gdrcopy.sh "${GDRCOPY_OS_VERSION}" "${GDRCOPY_CUDA_VERSION}" "${UUARCH}" && \
965 + if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
966 + # The Rubin CUDA image already provides GDRCopy. \
967 + ldconfig -p | grep -q 'libgdrapi\.so'; \
968 + else \
969 + case "${TARGETPLATFORM}" in \
970 + linux/arm64) UUARCH="aarch64" ;; \
971 + linux/amd64) UUARCH="x64" ;; \
972 + *) echo "Unsupported TARGETPLATFORM: ${TARGETPLATFORM}" >&2; exit 1 ;; \
973 + esac; \
974 + /tmp/install_gdrcopy.sh \
975 + "${GDRCOPY_OS_VERSION}" "${GDRCOPY_CUDA_VERSION}" "${UUARCH}"; \
976 + fi; \
977 rm /tmp/install_gdrcopy.sh
978
979 # Install vllm-openai dependencies (saves ~2.6s per build)
@@ -994,6 +1181,8 @@ RUN mv vllm src/vllm
1181 FROM vllm-base AS vllm-openai-base
1182 ARG TARGETPLATFORM
1183 ARG INSTALL_KV_CONNECTORS=false
1184 +ARG INSTALL_RUBIN_PRERELEASE
1185 +ARG TRITON_INSTALL_FROM_SOURCE_REPO
1186 ARG CUDA_VERSION
1187 ARG VLLM_BUILD_COMMIT
1188 ARG VLLM_BUILD_PIPELINE
@@ -1045,6 +1234,50 @@ RUN --mount=type=cache,target=/opt/uv/cache \
1234 # time; see docs/features/mooncake_connector_usage.md. Deliberately not an ENV
1235 # here so the image does not override mooncake's own default.
1236
1237 +# Install Rubin prerelease dependencies when explicitly requested. Keep this
1238 +# after the public vLLM and KV connector dependency pins installed above.
1239 +RUN --mount=type=cache,target=/opt/uv/cache \
1240 + --mount=type=bind,source=requirements,target=/tmp/vllm-requirements,ro \
1241 + if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
1242 + echo "Installing Rubin prerelease requirements..." \
1243 + && uv pip install --system \
1244 + -r /tmp/vllm-requirements/rubin-prerelease.txt; \
1245 + fi
1246 +
1247 +# Install source-built Triton last so dependency resolution cannot restore the
1248 +# previously installed version.
1249 +COPY --from=extensions-build \
1250 + /tmp/triton_from_source_workspace/dist/wheel.sha256 \
1251 + /tmp/triton-source-wheel.sha256
1252 +COPY tools/install_triton_from_source.sh /tmp/install_triton_from_source.sh
1253 +RUN --mount=type=cache,target=/opt/uv/cache \
1254 + --mount=type=bind,from=extensions-build,source=/tmp/triton_from_source_workspace/dist,target=/tmp/triton-source-dist,ro \
1255 + if [ -n "${TRITON_INSTALL_FROM_SOURCE_REPO}" ]; then \
1256 + CUDA_MAJOR_MINOR=$(echo "${CUDA_VERSION}" | cut -d. -f1,2); \
1257 + if [ "${INSTALL_RUBIN_PRERELEASE}" = "true" ]; then \
1258 + case "${CUDA_MAJOR_MINOR}" in \
1259 + 13.4|13.5) \
1260 + TRITON_SYSTEM_PTXAS_PATH=/usr/local/cuda/bin/ptxas \
1261 + TRITON_EXPECTED_PTXAS_VERSION="${CUDA_MAJOR_MINOR}" \
1262 + bash /tmp/install_triton_from_source.sh \
1263 + /tmp/triton-source-dist \
1264 + /tmp/triton-source-wheel.sha256 \
1265 + ;; \
1266 + *) \
1267 + echo "Unsupported Rubin CUDA version: ${CUDA_MAJOR_MINOR}" >&2; \
1268 + exit 1 \
1269 + ;; \
1270 + esac; \
1271 + else \
1272 + bash /tmp/install_triton_from_source.sh \
1273 + /tmp/triton-source-dist \
1274 + /tmp/triton-source-wheel.sha256; \
1275 + fi; \
1276 + fi \
1277 + && rm -f \
1278 + /tmp/install_triton_from_source.sh \
1279 + /tmp/triton-source-wheel.sha256
1280 +
1281 ENV VLLM_USAGE_SOURCE production-docker-image
1282 ENV VLLM_BUILD_COMMIT=${VLLM_BUILD_COMMIT:-unknown} \
1283 VLLM_BUILD_PIPELINE=${VLLM_BUILD_PIPELINE:-local} \
docker/versions.json
+3
@@ -10,6 +10,9 @@
10 "UBUNTU_VERSION": {
11 "default": "24.04"
12 },
13 + "INSTALL_RUBIN_PRERELEASE": {
14 + "default": "false"
15 + },
16 "NCCL_VERSION": {
17 "default": "2.30.7"
18 },
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
docs/contributing/dockerfile/dockerfile.md
+4
@@ -20,6 +20,10 @@ The edges of the build graph represent:
20 The `test-deps` stage branches from `vllm-runtime-base` so Git and the test
21 requirements remain cached independently of per-commit vLLM wheels and source.
22
23 +The `extensions-build` stage can also produce an optional source-built Triton
24 +wheel. `vllm-openai-base` installs that wheel after its other Python
25 +dependencies so dependency resolution cannot restore an older Triton version.
26 +
27 > <figure markdown="span">
28 > ![](../../assets/contributing/dockerfile-stages-dependency.png){ align="center" alt="query" width="100%" }
29 > </figure>
docs/getting_started/installation/gpu.cuda.inc.md
+83 -2
@@ -354,8 +354,9 @@ DOCKER_BUILDKIT=1 docker build . \
354
355 !!! note
356 By default vLLM will build for all GPU types for widest distribution. If you are just building for the
357 - current GPU type the machine is running on, you can add the argument `--build-arg torch_cuda_arch_list=""`
358 - for vLLM to find the current GPU type and build for that.
357 + current GPU type, you can add `--build-arg torch_cuda_arch_list=""` to delegate architecture selection
358 + to PyTorch. This requires the GPU to be visible to the container build; standard Docker BuildKit builds
359 + do not expose it and PyTorch instead falls back to its common architecture list.
360
361 If you are using Podman instead of Docker, you might need to disable SELinux labeling by
362 adding `--security-opt label=disable` when running `podman build` command to avoid certain [existing issues](https://github.com/containers/buildah/discussions/4184).
@@ -422,6 +423,86 @@ For (G)B300, we recommend using CUDA 13, as shown in the following command.
423
424 After setting up QEMU, you can use the `--platform "linux/arm64"` flag in your `docker build` command.
425
426 +#### [Preview] Building vLLM's Docker Image from Source for NVIDIA Rubin GPU Architecture
427 +
428 +At this time, the Rubin preview is available only to NVIDIA engineers and
429 +partners with access to NVIDIA's internal prerequisites. Set
430 +`INSTALL_RUBIN_PRERELEASE=true` to enable the Rubin build path. It requires a
431 +`requirements/rubin-prerelease.txt` file containing pointers to NVIDIA's
432 +internal prerelease packages, plus NVIDIA-internal CUDA 13.4 or CUDA 13.5
433 +development images for `BUILD_BASE_IMAGE` and `FINAL_BASE_IMAGE`.
434 +
435 +Triton must currently be installed from source for Rubin compatibility.
436 +Specify its repository with `TRITON_INSTALL_FROM_SOURCE_REPO`; an empty
437 +`TRITON_INSTALL_FROM_SOURCE_REVISION` selects the repository's latest `main`,
438 +while a commit, branch, or tag selects that revision. The tested revision
439 +lowers SM107 through LLVM's SM100 target and uses the final CUDA image's
440 +version-matched `ptxas` for SM107 assembly. This enables vLLM's default compiled
441 +mode on VR200 and R100.
442 +
443 +BuildKit does not automatically invalidate cached layers when a mutable Git
444 +ref changes. Use `--no-cache-filter extensions-build` to refresh an empty,
445 +branch, or tag revision.
446 +
447 +Use `ARCH=arm64` on VR200 or `ARCH=amd64` on R100:
448 +
449 +??? console "CUDA 13.4 command"
450 +
451 + ```bash
452 + ARCH=arm64
453 + docker buildx build --progress=plain --load \
454 + --file docker/Dockerfile \
455 + --target vllm-openai \
456 + --platform "linux/${ARCH}" \
457 + --tag "vllm/vllm-rubin-openai:prerelease-cu134-${ARCH}" \
458 + --build-arg max_jobs="$(nproc)" \
459 + --build-arg nvcc_threads=2 \
460 + --build-arg RUN_WHEEL_CHECK=false \
461 + --build-arg INSTALL_RUBIN_PRERELEASE=true \
462 + --build-arg TRITON_INSTALL_FROM_SOURCE_REPO=https://github.com/triton-lang/triton.git \
463 + --build-arg TRITON_INSTALL_FROM_SOURCE_REVISION=3f6e41132b5edf639bfb872ad73d4688765e08b8 \
464 + --build-arg CUDA_VERSION=13.4.1 \
465 + --build-arg BUILD_BASE_IMAGE="<cuda-13.4-manylinux-devel-image-${ARCH}>" \
466 + --build-arg FINAL_BASE_IMAGE="<cuda-13.4-ubuntu24.04-devel-image-${ARCH}>" \
467 + .
468 + ```
469 +
470 +??? console "CUDA 13.5 command"
471 +
472 + ```bash
473 + ARCH=arm64
474 + docker buildx build --progress=plain --load \
475 + --file docker/Dockerfile \
476 + --target vllm-openai \
477 + --platform "linux/${ARCH}" \
478 + --tag "vllm/vllm-rubin-openai:prerelease-cu135-${ARCH}" \
479 + --build-arg max_jobs="$(nproc)" \
480 + --build-arg nvcc_threads=2 \
481 + --build-arg RUN_WHEEL_CHECK=false \
482 + --build-arg INSTALL_RUBIN_PRERELEASE=true \
483 + --build-arg TRITON_INSTALL_FROM_SOURCE_REPO=https://github.com/triton-lang/triton.git \
484 + --build-arg TRITON_INSTALL_FROM_SOURCE_REVISION=3f6e41132b5edf639bfb872ad73d4688765e08b8 \
485 + --build-arg CUDA_VERSION=13.5.0 \
486 + --build-arg BUILD_BASE_IMAGE="<cuda-13.5-manylinux-devel-image-${ARCH}>" \
487 + --build-arg FINAL_BASE_IMAGE="<cuda-13.5-ubuntu24.04-devel-image-${ARCH}>" \
488 + .
489 + ```
490 +
491 +CUDA 13.5 compiled-mode qualification passed with NVIDIA driver versions
492 +615.62.03 and 620.05. Driver 610.47.04 failed the tested compiled CUDA 13.5
493 +kernel. Validate the exact driver version on the target system.
494 +
495 +!!! note
496 + Keep the default explicit `torch_cuda_arch_list`. GPU-less BuildKit builds
497 + cannot inspect the host GPU. R100 and VR200 report compute capability 10.7,
498 + for which the generic `10.0` target provides family-compatible kernels.
499 + The Ubuntu `devel` final image is also required: the corresponding `base`
500 + image lacks the CUDA runtime/JIT package closure used by vLLM and the
501 + prerelease PyTorch wheel.
502 +
503 + `RUN_WHEEL_CHECK=false` disables only the PyPI publication-size guard for
504 + this private staging image.
505 +
506 #### Use the custom-built vLLM Docker image**
507
508 To run vLLM with the custom-built Docker image:
tools/build_triton_from_source.sh new
+43
@@ -0,0 +1,43 @@
1 +#!/usr/bin/env bash
2 +set -euxo pipefail
3 +
4 +: "${TARGETARCH:?TARGETARCH must be set}"
5 +: "${TRITON_INSTALL_FROM_SOURCE_REPO:?TRITON_INSTALL_FROM_SOURCE_REPO must be set}"
6 +
7 +TRITON_REVISION="${TRITON_INSTALL_FROM_SOURCE_REVISION:-main}"
8 +TRITON_WORKSPACE="${TRITON_WORKSPACE:-/tmp/triton_from_source_workspace}"
9 +TRITON_SOURCE="${TRITON_WORKSPACE}/src"
10 +TRITON_DIST="${TRITON_WORKSPACE}/dist"
11 +TRITON_BUILD_JOBS="${MAX_JOBS:-$(nproc)}"
12 +
13 +case "${TARGETARCH}" in
14 + amd64) TRITON_LLVM_SYSTEM_SUFFIX=almalinux-x64 ;;
15 + arm64) TRITON_LLVM_SYSTEM_SUFFIX=almalinux-arm64 ;;
16 + *)
17 + echo "Unsupported Triton build architecture: ${TARGETARCH}" >&2
18 + exit 1
19 + ;;
20 +esac
21 +export TRITON_LLVM_SYSTEM_SUFFIX
22 +
23 +mkdir -p "${TRITON_DIST}"
24 +git init -q "${TRITON_SOURCE}"
25 +git -C "${TRITON_SOURCE}" remote add origin \
26 + "${TRITON_INSTALL_FROM_SOURCE_REPO}"
27 +git -C "${TRITON_SOURCE}" fetch --depth=1 origin "${TRITON_REVISION}"
28 +git -C "${TRITON_SOURCE}" checkout -q --detach FETCH_HEAD
29 +git -C "${TRITON_SOURCE}" rev-parse HEAD
30 +
31 +uv pip install --python /opt/venv/bin/python3 \
32 + -r "${TRITON_SOURCE}/python/requirements.txt"
33 +
34 +TRITON_BUILD_WITH_CCACHE=true \
35 +MAX_JOBS="${TRITON_BUILD_JOBS}" \
36 + uv build --python /opt/venv/bin/python3 \
37 + --wheel \
38 + --no-build-isolation \
39 + --out-dir "${TRITON_DIST}" \
40 + "${TRITON_SOURCE}"
41 +
42 +(cd "${TRITON_DIST}" && sha256sum triton-*.whl > wheel.sha256)
43 +rm -rf "${TRITON_SOURCE}"
tools/install_triton_from_source.sh new
+41
@@ -0,0 +1,41 @@
1 +#!/usr/bin/env bash
2 +set -euxo pipefail
3 +
4 +if [[ $# -ne 2 ]]; then
5 + echo "Usage: $0 <wheel-directory> <checksum-file>" >&2
6 + exit 1
7 +fi
8 +
9 +TRITON_DIST="$1"
10 +TRITON_CHECKSUM="$2"
11 +
12 +test -d "${TRITON_DIST}"
13 +test -f "${TRITON_CHECKSUM}"
14 +(cd "${TRITON_DIST}" && sha256sum -c "${TRITON_CHECKSUM}")
15 +
16 +shopt -s nullglob
17 +TRITON_WHEELS=("${TRITON_DIST}"/triton-*.whl)
18 +if [[ ${#TRITON_WHEELS[@]} -ne 1 ]]; then
19 + echo "Expected exactly one Triton wheel in ${TRITON_DIST}" >&2
20 + exit 1
21 +fi
22 +
23 +uv pip install --system --reinstall --no-deps "${TRITON_WHEELS[0]}"
24 +
25 +if [[ -n "${TRITON_SYSTEM_PTXAS_PATH:-}" \
26 + || -n "${TRITON_EXPECTED_PTXAS_VERSION:-}" ]]; then
27 + : "${TRITON_SYSTEM_PTXAS_PATH:?TRITON_SYSTEM_PTXAS_PATH must be set}"
28 + : "${TRITON_EXPECTED_PTXAS_VERSION:?TRITON_EXPECTED_PTXAS_VERSION must be set}"
29 + PTXAS_PATH="${TRITON_SYSTEM_PTXAS_PATH}"
30 + test -x "${PTXAS_PATH}"
31 + TRITON_NVIDIA_BIN=$(python3 -c \
32 + 'from pathlib import Path; import triton; print(Path(triton.__file__).parent / "backends" / "nvidia" / "bin")')
33 + mkdir -p "${TRITON_NVIDIA_BIN}"
34 + ln -sfn "${PTXAS_PATH}" \
35 + "${TRITON_NVIDIA_BIN}/ptxas-blackwell"
36 +
37 + env -u TRITON_PTXAS_BLACKWELL_PATH \
38 + TRITON_EXPECTED_PTXAS_PATH="${PTXAS_PATH}" \
39 + python3 -c \
40 + 'import os; from triton.backends.nvidia.compiler import get_ptxas; tool = get_ptxas(107); assert tool.version == os.environ["TRITON_EXPECTED_PTXAS_VERSION"]; assert os.path.samefile(tool.path, os.environ["TRITON_EXPECTED_PTXAS_PATH"])'
41 +fi