Bundle the release launcher in the source build stage, pin the CUDA 12.8 runtime dependency for SM70 wheels, and validate wheel metadata, ZIP paths, and native loader paths before publication. Assisted-by: OpenAI Codex Signed-off-by: yangzhuxinyzx <153831768+yangzhuxinyzx@users.noreply.github.com>
1092 lines
49 KiB
Docker
1092 lines
49 KiB
Docker
# The vLLM Dockerfile is used to construct vLLM image that can be directly used
|
|
# to run the OpenAI compatible server.
|
|
|
|
# Please update any changes made here to
|
|
# docs/contributing/dockerfile/dockerfile.md and
|
|
# docs/assets/contributing/dockerfile-stages-dependency.png
|
|
|
|
# =============================================================================
|
|
# VERSION MANAGEMENT
|
|
# =============================================================================
|
|
# ARG defaults in this Dockerfile are the source of truth for pinned versions.
|
|
# docker/versions.json is auto-generated for use with docker buildx bake.
|
|
#
|
|
# When updating versions:
|
|
# 1. Edit the ARG defaults below
|
|
# 2. Run: python tools/generate_versions_json.py
|
|
#
|
|
# To query versions programmatically:
|
|
# jq -r '.variable.CUDA_VERSION.default' docker/versions.json
|
|
#
|
|
# To build with bake:
|
|
# docker buildx bake -f docker/docker-bake.hcl -f docker/versions.json
|
|
# =============================================================================
|
|
|
|
ARG CUDA_VERSION=13.0.2
|
|
ARG PYTHON_VERSION=3.12
|
|
ARG UBUNTU_VERSION=22.04
|
|
|
|
# By parameterizing the base images, we allow third-party to use their own
|
|
# base images. One use case is hermetic builds with base images stored in
|
|
# private registries that use a different repository naming conventions.
|
|
#
|
|
# Example:
|
|
# docker build --build-arg BUILD_BASE_IMAGE=registry.acme.org/mirror/nvidia/cuda:${CUDA_VERSION}-devel-ubuntu20.04
|
|
|
|
# Important: We build with an old version of Ubuntu to maintain broad
|
|
# compatibility with other Linux OSes. The main reason for this is that the
|
|
# glibc version is baked into the distro, and binaries built with one glibc
|
|
# version are not backwards compatible with OSes that use an earlier version.
|
|
ARG BUILD_BASE_IMAGE=nvidia/cuda:${CUDA_VERSION}-devel-ubuntu22.04
|
|
# Using cuda base image with minimal dependencies necessary for JIT compilation (FlashInfer, DeepGEMM, EP kernels)
|
|
ARG FINAL_BASE_IMAGE=nvidia/cuda:${CUDA_VERSION}-base-ubuntu${UBUNTU_VERSION}
|
|
|
|
# OS family of BUILD_BASE_IMAGE. Controls package manager (apt vs dnf) and
|
|
# Python bootstrap. Set to "manylinux" alongside a manylinux build base such
|
|
# as pytorch/manylinux2_28-builder:cuda13.0 to produce wheels with a glibc
|
|
# 2.28 floor (matches PyTorch's own published wheels). Default stays on
|
|
# Ubuntu for backwards compatibility.
|
|
ARG BUILD_OS=ubuntu
|
|
|
|
# By parameterizing the Deadsnakes repository URL, we allow third-party to use
|
|
# their own mirror. When doing so, we don't benefit from the transparent
|
|
# installation of the GPG key of the PPA, as done by add-apt-repository, so we
|
|
# also need a URL for the GPG key.
|
|
ARG DEADSNAKES_MIRROR_URL
|
|
ARG DEADSNAKES_GPGKEY_URL
|
|
|
|
# The PyPA get-pip.py script is a self contained script+zip file, that provides
|
|
# both the installer script and the pip base85-encoded zip archive. This allows
|
|
# bootstrapping pip in environment where a distribution package does not exist.
|
|
#
|
|
# By parameterizing the URL for get-pip.py installation script, we allow
|
|
# third-party to use their own copy of the script stored in a private mirror.
|
|
# We set the default value to the PyPA owned get-pip.py script.
|
|
#
|
|
# Reference: https://pip.pypa.io/en/stable/installation/#get-pip-py
|
|
ARG GET_PIP_URL="https://bootstrap.pypa.io/get-pip.py"
|
|
|
|
# PIP supports fetching the packages from custom indexes, allowing third-party
|
|
# to host the packages in private mirrors. The PIP_INDEX_URL and
|
|
# PIP_EXTRA_INDEX_URL are standard PIP environment variables to override the
|
|
# default indexes. By letting them empty by default, PIP will use its default
|
|
# indexes if the build process doesn't override the indexes.
|
|
#
|
|
# Uv uses different variables. We set them by default to the same values as
|
|
# PIP, but they can be overridden.
|
|
ARG PIP_INDEX_URL
|
|
ARG PIP_EXTRA_INDEX_URL
|
|
ARG UV_INDEX_URL=${PIP_INDEX_URL}
|
|
ARG UV_EXTRA_INDEX_URL=${PIP_EXTRA_INDEX_URL}
|
|
|
|
# PyTorch provides its own indexes for standard and nightly builds
|
|
ARG PYTORCH_CUDA_INDEX_BASE_URL=https://download.pytorch.org/whl
|
|
|
|
# PIP supports multiple authentication schemes, including keyring
|
|
# By parameterizing the PIP_KEYRING_PROVIDER variable and setting it to
|
|
# disabled by default, we allow third-party to use keyring authentication for
|
|
# their private Python indexes, while not changing the default behavior which
|
|
# is no authentication.
|
|
#
|
|
# Reference: https://pip.pypa.io/en/stable/topics/authentication/#keyring-support
|
|
ARG PIP_KEYRING_PROVIDER=disabled
|
|
ARG UV_KEYRING_PROVIDER=${PIP_KEYRING_PROVIDER}
|
|
|
|
# Flag enables built-in KV-connector dependency libs into docker images
|
|
ARG INSTALL_KV_CONNECTORS=false
|
|
|
|
#################### BASE BUILD IMAGE ####################
|
|
# prepare basic build environment
|
|
FROM ${BUILD_BASE_IMAGE} AS base
|
|
|
|
ARG CUDA_VERSION
|
|
ARG PYTHON_VERSION
|
|
ARG BUILD_OS
|
|
|
|
ENV DEBIAN_FRONTEND=noninteractive
|
|
|
|
# Environment for uv
|
|
# Declared BEFORE the installer + `uv venv` invocations below so the uv
|
|
# binary, managed Python, download cache, and /opt/venv all land under
|
|
# /opt/uv instead of /root/.local/. Without this, the venv created at
|
|
# build time hardlinks back to /root/.local/share/uv/python and
|
|
# descendants of this stage (`build`, `dev`, `csrc-build`,
|
|
# `extensions-build`) inherit a root-owned, non-root-unreadable layout.
|
|
# See #15174, #15359, #31959. Child stages inherit these via Dockerfile
|
|
# `ENV` unless they override them explicitly.
|
|
ENV UV_HTTP_TIMEOUT=500
|
|
ENV UV_INDEX_STRATEGY="unsafe-best-match"
|
|
ENV UV_PYTHON_INSTALL_DIR=/opt/uv/python
|
|
ENV UV_CACHE_DIR=/opt/uv/cache
|
|
ENV UV_INSTALL_DIR=/opt/uv/bin
|
|
ENV PATH="/opt/venv/bin:/opt/uv/bin:$PATH"
|
|
ENV VIRTUAL_ENV="/opt/venv"
|
|
|
|
# Install system dependencies including build tools.
|
|
# The Ubuntu path uses apt + deadsnakes-via-uv for Python; the manylinux path
|
|
# (AlmaLinux 8, e.g. pytorch/manylinux2_28-builder) uses dnf and the Python
|
|
# interpreters pre-installed at /opt/python/cpXY-cpXY/.
|
|
RUN if [ "${BUILD_OS}" = "manylinux" ]; then \
|
|
# rdma-core-devel provides libibverbs headers; ccache lives in EPEL,
|
|
# which the pytorch manylinux image already enables. git/curl/sudo
|
|
# are typically pre-installed but listed defensively.
|
|
dnf install -y --setopt=install_weak_deps=False \
|
|
ccache \
|
|
git \
|
|
curl \
|
|
sudo \
|
|
rdma-core-devel \
|
|
&& dnf clean all \
|
|
&& rm -rf /var/cache/dnf; \
|
|
else \
|
|
apt-get update -y \
|
|
&& apt-get install -y --no-install-recommends \
|
|
ccache \
|
|
software-properties-common \
|
|
git \
|
|
curl \
|
|
sudo \
|
|
python3-pip \
|
|
libibverbs-dev \
|
|
# Upgrade to GCC 10 to avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92519
|
|
# as it was causing spam when compiling the CUTLASS kernels
|
|
gcc-10 \
|
|
g++-10 \
|
|
&& update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 110 --slave /usr/bin/g++ g++ /usr/bin/g++-10 \
|
|
# Install python dev headers if available (needed for cmake FindPython on Ubuntu 24.04
|
|
# which ships cmake 3.28 and requires Development.SABIModule; silently skipped on
|
|
# Ubuntu 20.04/22.04 where python3.x-dev is not available without a PPA)
|
|
&& (apt-get install -y --no-install-recommends python${PYTHON_VERSION}-dev 2>/dev/null || true) \
|
|
&& rm -rf /var/lib/apt/lists/*; \
|
|
fi
|
|
|
|
# Install uv and bootstrap /opt/venv. Both paths converge on /opt/venv so all
|
|
# downstream stages stay distro-agnostic.
|
|
RUN mkdir -p "${UV_PYTHON_INSTALL_DIR}" "${UV_CACHE_DIR}" "${UV_INSTALL_DIR}" \
|
|
&& chmod -R a+rX /opt/uv \
|
|
&& curl -LsSf https://astral.sh/uv/install.sh | sh \
|
|
# `--seed` installs pip/setuptools/wheel into the venv so `python3 -m
|
|
# pip` works regardless of how uv happens to link the venv back to the
|
|
# managed Python install (which, at a non-default UV_PYTHON_INSTALL_DIR,
|
|
# doesn't always expose ensurepip via the default venv layout).
|
|
&& if [ "${BUILD_OS}" = "manylinux" ]; then \
|
|
# manylinux images ship Python at /opt/python/cpXY-cpXY/; point uv
|
|
# at the matching interpreter rather than letting it fetch one.
|
|
PYV_NODOT=$(echo ${PYTHON_VERSION} | tr -d '.') \
|
|
&& MANYLINUX_PY=/opt/python/cp${PYV_NODOT}-cp${PYV_NODOT}/bin/python${PYTHON_VERSION} \
|
|
&& uv venv --seed /opt/venv --python "$MANYLINUX_PY"; \
|
|
else \
|
|
uv venv --seed /opt/venv --python ${PYTHON_VERSION}; \
|
|
fi \
|
|
&& rm -f /usr/bin/python3 /usr/bin/python3-config /usr/bin/pip \
|
|
&& ln -sf /opt/venv/bin/python3 /usr/bin/python3 \
|
|
&& ln -sf /opt/venv/bin/python3-config /usr/bin/python3-config \
|
|
&& ln -sf /opt/venv/bin/pip /usr/bin/pip \
|
|
&& python3 --version && python3 -m pip --version
|
|
|
|
# UV_LINK_MODE=copy applies to subsequent `uv pip install` RUNs (avoids
|
|
# hardlink failures with BuildKit cache mounts); it must not be set during
|
|
# `uv venv` above, which relies on hardlinking /opt/venv back to the
|
|
# managed Python source so ensurepip / `python3 -m pip` still resolve.
|
|
ENV UV_LINK_MODE=copy
|
|
|
|
# Verify GCC version
|
|
RUN gcc --version
|
|
|
|
# Enable CUDA forward compatibility by setting '-e VLLM_ENABLE_CUDA_COMPATIBILITY=1'
|
|
# Only needed for datacenter/professional GPUs with older drivers.
|
|
# See: https://docs.nvidia.com/deploy/cuda-compatibility/
|
|
ENV VLLM_ENABLE_CUDA_COMPATIBILITY=0
|
|
|
|
# ============================================================
|
|
# SLOW-CHANGING DEPENDENCIES BELOW
|
|
# These are the expensive layers that we want to cache
|
|
# ============================================================
|
|
|
|
# Install PyTorch and core CUDA dependencies
|
|
# This is ~2GB and rarely changes
|
|
ARG PYTORCH_CUDA_INDEX_BASE_URL
|
|
|
|
WORKDIR /workspace
|
|
|
|
# We can specify the standard or nightly build of PyTorch
|
|
ARG PYTORCH_NIGHTLY
|
|
|
|
# Install build and runtime dependencies, including PyTorch
|
|
# Check whether to install torch nightly instead of release for this build
|
|
COPY requirements/common.txt requirements/common.txt
|
|
COPY requirements/cuda.txt requirements/cuda.txt
|
|
COPY use_existing_torch.py use_existing_torch.py
|
|
COPY pyproject.toml pyproject.toml
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
if [ "$(echo $CUDA_VERSION | cut -d. -f1)" = "12" ]; then \
|
|
sed -i 's/^nvidia-cutlass-dsl\[cu13\]/nvidia-cutlass-dsl/' requirements/cuda.txt; \
|
|
sed -i 's/^humming-kernels\[cu13\]/humming-kernels[cu12]/' requirements/cuda.txt; \
|
|
fi \
|
|
&& if [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
|
|
echo "Installing torch nightly..." \
|
|
&& uv pip install --python /opt/venv/bin/python3 torch torchaudio torchvision --pre \
|
|
--index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/nightly/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.') \
|
|
&& echo "Installing other requirements..." \
|
|
&& /opt/venv/bin/python3 use_existing_torch.py --prefix \
|
|
&& uv pip install --python /opt/venv/bin/python3 -r requirements/cuda.txt \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/nightly/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
|
|
else \
|
|
uv pip install --python /opt/venv/bin/python3 -r requirements/cuda.txt \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
|
|
fi
|
|
|
|
# Track PyTorch lib versions used during build and match in downstream instances.
|
|
# We do this for both nightly and release so we can strip dependencies/*.txt as needed.
|
|
# Otherwise library dependencies can upgrade/downgrade torch incorrectly.
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
uv pip freeze | grep -i "^torch=\|^torchvision=\|^torchaudio=" > torch_lib_versions.txt \
|
|
&& TORCH_LIB_VERSIONS=$(cat torch_lib_versions.txt | xargs) \
|
|
&& echo "Installed torch libs: ${TORCH_LIB_VERSIONS}"
|
|
|
|
# CUDA arch list used by torch
|
|
# Explicitly set the list to avoid issues with torch 2.2
|
|
# See https://github.com/pytorch/pytorch/pull/123243
|
|
# From versions.json: .torch.cuda_arch_list
|
|
ARG torch_cuda_arch_list='7.5 8.0 8.6 8.9 9.0 10.0 11.0 12.0+PTX'
|
|
ENV TORCH_CUDA_ARCH_LIST=${torch_cuda_arch_list}
|
|
#################### BUILD BASE IMAGE ####################
|
|
|
|
#################### RUST BUILD IMAGE ####################
|
|
# Build the Rust frontend (`vllm-rs`) in a dedicated stage so the main wheel
|
|
# build stage doesn't need the rust toolchain, protoc, or the rust source.
|
|
# This stage runs in parallel with csrc-build/extensions-build.
|
|
FROM ${BUILD_BASE_IMAGE} AS rust-build
|
|
ARG BUILD_OS
|
|
|
|
ENV DEBIAN_FRONTEND=noninteractive
|
|
|
|
# Install a basic C toolchain (some rust crates compile C in their build.rs
|
|
# scripts) and unzip (used to extract the pinned protoc release below).
|
|
RUN if [ "${BUILD_OS}" = "manylinux" ]; then \
|
|
dnf install -y --setopt=install_weak_deps=False \
|
|
ca-certificates curl git gcc gcc-c++ make unzip \
|
|
&& dnf clean all && rm -rf /var/cache/dnf; \
|
|
else \
|
|
apt-get update -y \
|
|
&& apt-get install -y --no-install-recommends \
|
|
ca-certificates curl git build-essential unzip \
|
|
&& rm -rf /var/lib/apt/lists/*; \
|
|
fi
|
|
|
|
COPY tools/install_protoc.sh /tmp/install_protoc.sh
|
|
RUN /tmp/install_protoc.sh && rm /tmp/install_protoc.sh
|
|
|
|
# Install rustup; the toolchain itself is pinned by rust-toolchain.toml.
|
|
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
|
|
sh -s -- -y --profile minimal --default-toolchain none
|
|
ENV PATH="/root/.cargo/bin:${PATH}"
|
|
|
|
WORKDIR /workspace
|
|
|
|
# Copy only the rust workspace — the binary is the sole artifact we need.
|
|
COPY rust rust
|
|
COPY rust-toolchain.toml rust-toolchain.toml
|
|
COPY build_rust.sh build_rust.sh
|
|
|
|
# Cap cargo parallelism to avoid exhausting the CI host's open-file limit
|
|
# (rustc spawns enough concurrent processes to hit RLIMIT_NOFILE otherwise).
|
|
ENV CARGO_BUILD_JOBS=4
|
|
|
|
# Build the release binary. Cache cargo registry/git and target/, but copy the
|
|
# binary out of the target/ cache mount so it persists into the image layer
|
|
# for later COPY --from=rust-build.
|
|
RUN --mount=type=cache,target=/root/.cargo/registry \
|
|
--mount=type=cache,target=/root/.cargo/git \
|
|
--mount=type=cache,target=/workspace/rust/target \
|
|
VLLM_RS_TARGET_PATH=/workspace/vllm-rs bash build_rust.sh
|
|
#################### RUST BUILD IMAGE ####################
|
|
|
|
#################### CSRC BUILD IMAGE ####################
|
|
FROM base AS csrc-build
|
|
ARG TARGETPLATFORM
|
|
|
|
ARG PIP_INDEX_URL UV_INDEX_URL
|
|
ARG PIP_EXTRA_INDEX_URL UV_EXTRA_INDEX_URL
|
|
ARG PYTORCH_CUDA_INDEX_BASE_URL
|
|
|
|
# We can specify the standard or nightly build of PyTorch
|
|
ARG PYTORCH_NIGHTLY
|
|
|
|
# Install build dependencies
|
|
COPY requirements/build/cuda.txt requirements/build/cuda.txt
|
|
COPY use_existing_torch.py use_existing_torch.py
|
|
COPY --from=base /workspace/torch_lib_versions.txt torch_lib_versions.txt
|
|
|
|
# This timeout (in seconds) is necessary when installing some dependencies via uv since it's likely to time out
|
|
# Reference: https://github.com/astral-sh/uv/pull/1694
|
|
ENV UV_HTTP_TIMEOUT=500
|
|
ENV UV_INDEX_STRATEGY="unsafe-best-match"
|
|
# Use copy mode to avoid hardlink failures with Docker cache mounts
|
|
ENV UV_LINK_MODE=copy
|
|
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
if [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
|
|
echo "Installing build requirements without torch..." \
|
|
&& python3 use_existing_torch.py --prefix \
|
|
&& uv pip install --python /opt/venv/bin/python3 -r requirements/build/cuda.txt \
|
|
&& echo "Installing torch nightly..." \
|
|
&& uv pip install --python /opt/venv/bin/python3 $(cat torch_lib_versions.txt | grep -i "^torch=" | xargs) --pre \
|
|
--index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/nightly/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
|
|
else \
|
|
echo "Installing build requirements..." \
|
|
&& uv pip install --python /opt/venv/bin/python3 -r requirements/build/cuda.txt \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
|
|
fi
|
|
|
|
WORKDIR /workspace
|
|
|
|
COPY pyproject.toml setup.py CMakeLists.txt ./
|
|
COPY scripts/serve_qwen38_27b_nvfp4_v100.sh scripts/
|
|
COPY cmake cmake/
|
|
COPY csrc csrc/
|
|
COPY flash_qla flash_qla/
|
|
COPY flashinfer-sm70 flashinfer-sm70/
|
|
COPY flash-attention-v100 flash-attention-v100/
|
|
COPY vllm/envs.py vllm/envs.py
|
|
COPY vllm/__init__.py vllm/__init__.py
|
|
|
|
# max jobs used by Ninja to build extensions
|
|
ARG max_jobs=2
|
|
ENV MAX_JOBS=${max_jobs}
|
|
# number of threads used by nvcc
|
|
ARG nvcc_threads=8
|
|
ENV NVCC_THREADS=$nvcc_threads
|
|
|
|
ARG USE_SCCACHE
|
|
ARG SCCACHE_DOWNLOAD_URL
|
|
ARG SCCACHE_ENDPOINT
|
|
ARG SCCACHE_BUCKET_NAME=vllm-build-sccache
|
|
ARG SCCACHE_REGION_NAME=us-west-2
|
|
ARG SCCACHE_S3_NO_CREDENTIALS=0
|
|
|
|
# Flag to control whether to use pre-built vLLM wheels
|
|
ARG VLLM_USE_PRECOMPILED=""
|
|
ARG VLLM_MERGE_BASE_COMMIT=""
|
|
ARG VLLM_MAIN_CUDA_VERSION=""
|
|
|
|
# Use dummy version for csrc-build wheel (only .so files are extracted, version doesn't matter)
|
|
ENV SETUPTOOLS_SCM_PRETEND_VERSION="0.0.0+csrc.build"
|
|
|
|
# Use existing torch for nightly builds
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
if [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
|
|
python3 use_existing_torch.py --prefix; \
|
|
fi
|
|
|
|
# Provision one bare Python per `requires-python` entry; cmake reads
|
|
# DEEPGEMM_PYTHON_INTERPRETERS to build DeepGEMM `_C` for each. See
|
|
# cmake/external_projects/deepgemm.cmake for the full picture.
|
|
COPY tools/setup_deepgemm_pythons.sh tools/build_deepgemm_C.py tools/
|
|
ENV DEEPGEMM_VENV_PREFIX=/opt/dgenv
|
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
tools/setup_deepgemm_pythons.sh > /tmp/dg_pythons.txt
|
|
|
|
# Build the vLLM wheel
|
|
# if USE_SCCACHE is set, use sccache to speed up compilation
|
|
# AWS credentials mounted at ~/.aws/credentials for sccache S3 auth (optional)
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
--mount=type=secret,id=aws-credentials,target=/root/.aws/credentials,required=false \
|
|
if [ "$USE_SCCACHE" = "1" ]; then \
|
|
echo "Installing sccache..." \
|
|
&& case "${TARGETPLATFORM}" in \
|
|
linux/arm64) SCCACHE_ARCH="aarch64" ;; \
|
|
linux/amd64) SCCACHE_ARCH="x86_64" ;; \
|
|
*) echo "Unsupported TARGETPLATFORM for sccache: ${TARGETPLATFORM}" >&2; exit 1 ;; \
|
|
esac \
|
|
&& export SCCACHE_DOWNLOAD_URL="${SCCACHE_DOWNLOAD_URL:-https://github.com/mozilla/sccache/releases/download/v0.8.1/sccache-v0.8.1-${SCCACHE_ARCH}-unknown-linux-musl.tar.gz}" \
|
|
&& curl -L -o sccache.tar.gz ${SCCACHE_DOWNLOAD_URL} \
|
|
&& tar -xzf sccache.tar.gz \
|
|
&& sudo mv sccache-v0.8.1-${SCCACHE_ARCH}-unknown-linux-musl/sccache /usr/bin/sccache \
|
|
&& rm -rf sccache.tar.gz sccache-v0.8.1-${SCCACHE_ARCH}-unknown-linux-musl \
|
|
&& if [ ! -z ${SCCACHE_ENDPOINT} ] ; then export SCCACHE_ENDPOINT=${SCCACHE_ENDPOINT} ; fi \
|
|
&& export SCCACHE_BUCKET=${SCCACHE_BUCKET_NAME} \
|
|
&& export SCCACHE_REGION=${SCCACHE_REGION_NAME} \
|
|
&& export SCCACHE_S3_NO_CREDENTIALS=${SCCACHE_S3_NO_CREDENTIALS} \
|
|
&& export SCCACHE_IDLE_TIMEOUT=0 \
|
|
&& export CMAKE_BUILD_TYPE=Release \
|
|
&& export VLLM_USE_PRECOMPILED="${VLLM_USE_PRECOMPILED}" \
|
|
&& export VLLM_PRECOMPILED_WHEEL_COMMIT="${VLLM_MERGE_BASE_COMMIT}" \
|
|
&& export VLLM_MAIN_CUDA_VERSION="${VLLM_MAIN_CUDA_VERSION}" \
|
|
&& export VLLM_DOCKER_BUILD_CONTEXT=1 \
|
|
&& export DEEPGEMM_PYTHON_INTERPRETERS=$(cat /tmp/dg_pythons.txt) \
|
|
&& sccache --show-stats \
|
|
&& python3 setup.py bdist_wheel --dist-dir=dist --py-limited-api=cp38 \
|
|
&& sccache --show-stats; \
|
|
fi
|
|
|
|
ARG vllm_target_device="cuda"
|
|
ENV VLLM_TARGET_DEVICE=${vllm_target_device}
|
|
ENV CCACHE_DIR=/root/.cache/ccache
|
|
RUN --mount=type=cache,target=/root/.cache/ccache \
|
|
--mount=type=cache,target=/opt/uv/cache \
|
|
if [ "$USE_SCCACHE" != "1" ]; then \
|
|
# Clean any existing CMake artifacts
|
|
rm -rf .deps && \
|
|
mkdir -p .deps && \
|
|
export VLLM_USE_PRECOMPILED="${VLLM_USE_PRECOMPILED}" && \
|
|
export VLLM_PRECOMPILED_WHEEL_COMMIT="${VLLM_MERGE_BASE_COMMIT}" && \
|
|
export VLLM_DOCKER_BUILD_CONTEXT=1 && \
|
|
export DEEPGEMM_PYTHON_INTERPRETERS=$(cat /tmp/dg_pythons.txt) && \
|
|
python3 setup.py bdist_wheel --dist-dir=dist --py-limited-api=cp38; \
|
|
fi
|
|
|
|
#################### CSRC BUILD IMAGE ####################
|
|
|
|
#################### EXTENSIONS BUILD IMAGE ####################
|
|
# Build DeepEP - runs in PARALLEL with csrc-build
|
|
# This stage is independent and doesn't affect csrc cache
|
|
FROM base AS extensions-build
|
|
ARG CUDA_VERSION
|
|
|
|
# This timeout (in seconds) is necessary when installing some dependencies via uv since it's likely to time out
|
|
ENV UV_HTTP_TIMEOUT=500
|
|
ENV UV_INDEX_STRATEGY="unsafe-best-match"
|
|
ENV UV_LINK_MODE=copy
|
|
|
|
WORKDIR /workspace
|
|
|
|
# Build DeepEP wheels
|
|
COPY tools/ep_kernels/install_python_libraries.sh /tmp/install_python_libraries.sh
|
|
# Defaults moved here from tools/ep_kernels/install_python_libraries.sh for centralized version management
|
|
ARG DEEPEP_COMMIT_HASH=73b6ea4
|
|
ARG NVSHMEM_VER
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
mkdir -p /tmp/ep_kernels_workspace/dist && \
|
|
export TORCH_CUDA_ARCH_LIST='9.0a 10.0a' && \
|
|
/tmp/install_python_libraries.sh \
|
|
--workspace /tmp/ep_kernels_workspace \
|
|
--mode wheel \
|
|
${DEEPEP_COMMIT_HASH:+--deepep-ref "$DEEPEP_COMMIT_HASH"} \
|
|
${NVSHMEM_VER:+--nvshmem-ver "$NVSHMEM_VER"} && \
|
|
find /tmp/ep_kernels_workspace/nvshmem -name '*.a' -delete
|
|
#################### EXTENSIONS BUILD IMAGE ####################
|
|
|
|
#################### WHEEL BUILD IMAGE ####################
|
|
FROM base AS build
|
|
ARG TARGETPLATFORM
|
|
|
|
ARG PIP_INDEX_URL UV_INDEX_URL
|
|
ARG PIP_EXTRA_INDEX_URL UV_EXTRA_INDEX_URL
|
|
ARG PYTORCH_CUDA_INDEX_BASE_URL
|
|
|
|
# We can specify the standard or nightly build of PyTorch
|
|
ARG PYTORCH_NIGHTLY
|
|
|
|
# Install build dependencies
|
|
COPY requirements/build/cuda.txt requirements/build/cuda.txt
|
|
COPY use_existing_torch.py use_existing_torch.py
|
|
COPY --from=base /workspace/torch_lib_versions.txt torch_lib_versions.txt
|
|
|
|
# This timeout (in seconds) is necessary when installing some dependencies via uv since it's likely to time out
|
|
# Reference: https://github.com/astral-sh/uv/pull/1694
|
|
ENV UV_HTTP_TIMEOUT=500
|
|
ENV UV_INDEX_STRATEGY="unsafe-best-match"
|
|
# Use copy mode to avoid hardlink failures with Docker cache mounts
|
|
ENV UV_LINK_MODE=copy
|
|
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
if [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
|
|
echo "Installing build requirements without torch..." \
|
|
&& python3 use_existing_torch.py --prefix \
|
|
&& uv pip install --python /opt/venv/bin/python3 -r requirements/build/cuda.txt \
|
|
&& echo "Installing torch nightly..." \
|
|
&& uv pip install --python /opt/venv/bin/python3 $(cat torch_lib_versions.txt | grep -i "^torch=" | xargs) --pre \
|
|
--index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/nightly/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
|
|
else \
|
|
echo "Installing build requirements..." \
|
|
&& uv pip install --python /opt/venv/bin/python3 -r requirements/build/cuda.txt \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
|
|
fi
|
|
|
|
WORKDIR /workspace
|
|
|
|
# Copy pre-built csrc wheel directly
|
|
COPY --from=csrc-build /workspace/dist /precompiled-wheels
|
|
COPY . .
|
|
|
|
# Drop the pre-built rust frontend binary into the source tree. setup.py
|
|
# detects it and ships it as-is, skipping the local cargo build.
|
|
COPY --from=rust-build /workspace/vllm-rs vllm/vllm-rs
|
|
|
|
ARG GIT_REPO_CHECK=0
|
|
RUN --mount=type=bind,source=.git,target=.git \
|
|
if [ "$GIT_REPO_CHECK" != "0" ]; then bash tools/check_repo.sh ; fi
|
|
|
|
ARG vllm_target_device="cuda"
|
|
ENV VLLM_TARGET_DEVICE=${vllm_target_device}
|
|
|
|
# Skip adding +precompiled suffix to version (preserves git-derived version)
|
|
ENV VLLM_SKIP_PRECOMPILED_VERSION_SUFFIX=1
|
|
# A linked Git worktree's .git file points outside the Docker build context.
|
|
# Let callers provide the exact source version when SCM metadata is unavailable.
|
|
ARG SETUPTOOLS_SCM_PRETEND_VERSION=""
|
|
|
|
# Use existing torch for nightly builds
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
if [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
|
|
python3 use_existing_torch.py --prefix; \
|
|
fi
|
|
|
|
# Build the bundled SM70 FlashAttention wheel alongside vLLM. FLASH_ATTN_V100
|
|
# is an external Python/CUDA package, so the runtime image must install it
|
|
# explicitly instead of relying on the vLLM wheel to carry the extension.
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
cd flash-attention-v100 && \
|
|
python3 setup.py bdist_wheel --dist-dir=/workspace/flash-attn-v100-dist
|
|
|
|
# Build the vLLM wheel
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
--mount=type=bind,source=.git,target=.git \
|
|
if [ -n "${SETUPTOOLS_SCM_PRETEND_VERSION}" ]; then \
|
|
export SETUPTOOLS_SCM_PRETEND_VERSION; \
|
|
fi; \
|
|
if [ "${vllm_target_device}" = "cuda" ]; then \
|
|
export VLLM_USE_PRECOMPILED=1; \
|
|
export VLLM_PRECOMPILED_WHEEL_LOCATION=$(ls /precompiled-wheels/*.whl); \
|
|
fi && \
|
|
python3 setup.py bdist_wheel --dist-dir=dist --py-limited-api=cp38
|
|
|
|
# Copy extension wheels from extensions-build stage for later use
|
|
COPY --from=extensions-build /tmp/ep_kernels_workspace/dist /tmp/ep_kernels_workspace/dist
|
|
|
|
# Check the size of the wheel if RUN_WHEEL_CHECK is true
|
|
COPY .buildkite/check-wheel-size.py check-wheel-size.py
|
|
# sync the default value with .buildkite/check-wheel-size.py
|
|
ARG VLLM_MAX_SIZE_MB=500
|
|
ENV VLLM_MAX_SIZE_MB=$VLLM_MAX_SIZE_MB
|
|
ARG RUN_WHEEL_CHECK=true
|
|
RUN if [ "$RUN_WHEEL_CHECK" = "true" ]; then \
|
|
python3 check-wheel-size.py dist; \
|
|
else \
|
|
echo "Skipping wheel size check."; \
|
|
fi
|
|
|
|
#################### WHEEL BUILD IMAGE ####################
|
|
|
|
#################### DEV IMAGE ####################
|
|
FROM base AS dev
|
|
|
|
ARG PIP_INDEX_URL UV_INDEX_URL
|
|
ARG PIP_EXTRA_INDEX_URL UV_EXTRA_INDEX_URL
|
|
ARG PYTORCH_CUDA_INDEX_BASE_URL
|
|
ARG BUILD_OS
|
|
|
|
# This timeout (in seconds) is necessary when installing some dependencies via uv since it's likely to time out
|
|
# Reference: https://github.com/astral-sh/uv/pull/1694
|
|
ENV UV_HTTP_TIMEOUT=500
|
|
ENV UV_INDEX_STRATEGY="unsafe-best-match"
|
|
# Use copy mode to avoid hardlink failures with Docker cache mounts
|
|
ENV UV_LINK_MODE=copy
|
|
|
|
# Install libnuma-dev, required by fastsafetensors (fixes #20384)
|
|
RUN if [ "${BUILD_OS}" = "manylinux" ]; then \
|
|
dnf install -y numactl-devel && dnf clean all && rm -rf /var/cache/dnf; \
|
|
else \
|
|
apt-get update && apt-get install -y --no-install-recommends libnuma-dev && rm -rf /var/lib/apt/lists/*; \
|
|
fi
|
|
|
|
|
|
# We can specify the standard or nightly build of PyTorch
|
|
ARG PYTORCH_NIGHTLY
|
|
|
|
# Install development dependencies
|
|
COPY requirements/lint.txt requirements/lint.txt
|
|
COPY requirements/test/cuda.in requirements/test/cuda.in
|
|
COPY requirements/test/cuda.txt requirements/test/cuda.txt
|
|
COPY requirements/dev.txt requirements/dev.txt
|
|
COPY use_existing_torch.py use_existing_torch.py
|
|
COPY --from=base /workspace/torch_lib_versions.txt torch_lib_versions.txt
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
if [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
|
|
echo "Installing dev requirements plus torch nightly..." \
|
|
&& python3 use_existing_torch.py --prefix \
|
|
&& cat torch_lib_versions.txt >> requirements/test/cuda.in \
|
|
&& uv pip compile requirements/test/cuda.in -o requirements/test/cuda.txt --index-strategy unsafe-best-match \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/nightly/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.') \
|
|
&& uv pip install --python /opt/venv/bin/python3 $(cat torch_lib_versions.txt | xargs) --pre \
|
|
-r requirements/dev.txt \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/nightly/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
|
|
else \
|
|
echo "Installing dev requirements..." \
|
|
&& uv pip install --python /opt/venv/bin/python3 -r requirements/dev.txt \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
|
|
fi
|
|
|
|
#################### DEV IMAGE ####################
|
|
#################### vLLM installation IMAGE ####################
|
|
# image with vLLM installed
|
|
FROM ${FINAL_BASE_IMAGE} AS vllm-base
|
|
|
|
ARG CUDA_VERSION
|
|
ARG PYTHON_VERSION
|
|
ARG DEADSNAKES_MIRROR_URL
|
|
ARG DEADSNAKES_GPGKEY_URL
|
|
ARG GET_PIP_URL
|
|
|
|
ENV DEBIAN_FRONTEND=noninteractive
|
|
WORKDIR /vllm-workspace
|
|
|
|
|
|
# Python version string for paths (e.g., "312" for 3.12)
|
|
RUN PYTHON_VERSION_STR=$(echo ${PYTHON_VERSION} | sed 's/\.//g') && \
|
|
echo "export PYTHON_VERSION_STR=${PYTHON_VERSION_STR}" >> /etc/environment
|
|
|
|
# Install Python and system dependencies
|
|
RUN apt-get update -y \
|
|
&& apt-get install -y --no-install-recommends \
|
|
software-properties-common \
|
|
curl \
|
|
sudo \
|
|
ffmpeg \
|
|
libsm6 \
|
|
libxext6 \
|
|
libgl1 \
|
|
&& if [ ! -z ${DEADSNAKES_MIRROR_URL} ] ; then \
|
|
if [ ! -z "${DEADSNAKES_GPGKEY_URL}" ] ; then \
|
|
mkdir -p -m 0755 /etc/apt/keyrings ; \
|
|
curl -L ${DEADSNAKES_GPGKEY_URL} | gpg --dearmor > /etc/apt/keyrings/deadsnakes.gpg ; \
|
|
sudo chmod 644 /etc/apt/keyrings/deadsnakes.gpg ; \
|
|
echo "deb [signed-by=/etc/apt/keyrings/deadsnakes.gpg] ${DEADSNAKES_MIRROR_URL} $(lsb_release -cs) main" > /etc/apt/sources.list.d/deadsnakes.list ; \
|
|
fi ; \
|
|
else \
|
|
for i in 1 2 3; do \
|
|
add-apt-repository -y ppa:deadsnakes/ppa && break || \
|
|
{ echo "Attempt $i failed, retrying in 5s..."; sleep 5; }; \
|
|
done ; \
|
|
fi \
|
|
&& apt-get update -y \
|
|
&& apt-get install -y --no-install-recommends \
|
|
python${PYTHON_VERSION} \
|
|
python${PYTHON_VERSION}-dev \
|
|
python${PYTHON_VERSION}-venv \
|
|
libibverbs-dev \
|
|
&& rm -rf /var/lib/apt/lists/* \
|
|
&& update-alternatives --install /usr/bin/python3 python3 /usr/bin/python${PYTHON_VERSION} 1 \
|
|
&& update-alternatives --set python3 /usr/bin/python${PYTHON_VERSION} \
|
|
&& ln -sf /usr/bin/python${PYTHON_VERSION}-config /usr/bin/python3-config \
|
|
&& rm -f /usr/lib/python${PYTHON_VERSION}/EXTERNALLY-MANAGED \
|
|
&& curl -sS ${GET_PIP_URL} | python${PYTHON_VERSION} \
|
|
&& python3 --version && python3 -m pip --version
|
|
|
|
# Install CUDA development tools for runtime JIT compilation
|
|
# (FlashInfer, DeepGEMM, EP kernels all require compilation at runtime)
|
|
RUN CUDA_VERSION_DASH=$(echo $CUDA_VERSION | cut -d. -f1,2 | tr '.' '-') && \
|
|
CUDA_VERSION_SHORT=$(echo $CUDA_VERSION | cut -d. -f1,2) && \
|
|
apt-get update -y && \
|
|
apt-get install -y --no-install-recommends --allow-change-held-packages \
|
|
cuda-nvcc-${CUDA_VERSION_DASH} \
|
|
cuda-cudart-${CUDA_VERSION_DASH} \
|
|
cuda-nvrtc-${CUDA_VERSION_DASH} \
|
|
cuda-cuobjdump-${CUDA_VERSION_DASH} \
|
|
libcurand-dev-${CUDA_VERSION_DASH} \
|
|
libcublas-dev-${CUDA_VERSION_DASH} \
|
|
# Required by fastsafetensors (fixes #20384)
|
|
libnuma-dev \
|
|
# numactl CLI for NUMA binding at runtime
|
|
numactl && \
|
|
# Fixes nccl_allocator requiring nccl.h at runtime
|
|
# https://github.com/vllm-project/vllm/blob/1336a1ea244fa8bfd7e72751cabbdb5b68a0c11a/vllm/distributed/device_communicators/pynccl_allocator.py#L22
|
|
# NCCL packages don't use the cuda-MAJOR-MINOR naming convention,
|
|
# so we pin the version to match our CUDA version
|
|
NCCL_VER=$(apt-cache madison libnccl-dev | grep "+cuda${CUDA_VERSION_SHORT}" | head -1 | awk -F'|' '{gsub(/^ +| +$/, "", $2); print $2}') && \
|
|
apt-get install -y --no-install-recommends --allow-change-held-packages libnccl-dev=${NCCL_VER} libnccl2=${NCCL_VER} && \
|
|
rm -rf /var/lib/apt/lists/*
|
|
|
|
# Install uv for faster pip installs
|
|
RUN python3 -m pip install uv
|
|
|
|
# Environment for uv
|
|
# Redirect uv's managed Python and download cache out of /root/ so downstream
|
|
# images (`FROM vllm/vllm-openai` + `USER <uid>`) and direct non-root runs
|
|
# (`docker run --user <uid>:<gid>`) can read and execute them. See #15174,
|
|
# #15359, #31959.
|
|
ENV UV_HTTP_TIMEOUT=500
|
|
ENV UV_INDEX_STRATEGY="unsafe-best-match"
|
|
ENV UV_LINK_MODE=copy
|
|
ENV UV_PYTHON_INSTALL_DIR=/opt/uv/python
|
|
ENV UV_CACHE_DIR=/opt/uv/cache
|
|
RUN mkdir -p "${UV_PYTHON_INSTALL_DIR}" "${UV_CACHE_DIR}" \
|
|
&& chgrp -R 0 /opt/uv \
|
|
&& chmod -R g+rwX,a+rX /opt/uv
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Non-root support (opt-in)
|
|
# ----------------------------------------------------------------------
|
|
# Create a conventional `vllm` user (UID 2000, GID 0) so the image can be
|
|
# run under `--user 2000:0` or the opt-in `vllm-openai-nonroot` target.
|
|
#
|
|
# Design notes:
|
|
# * GID 0 + group-writable cache dirs follow the OpenShift arbitrary-UID
|
|
# pattern, so any UID that is a member of group 0 at runtime can write
|
|
# to /home/vllm and /opt/uv without additional chown work.
|
|
# * The default `vllm-openai` image keeps `USER root`, so every existing
|
|
# `docker run vllm/vllm-openai ...` / K8s manifest / `FROM vllm/vllm-openai`
|
|
# + `RUN uv pip install --system ...` flow is unchanged.
|
|
# * The entrypoint wrapper below is only used by `vllm-openai-nonroot`; it
|
|
# handles the OpenShift arbitrary-UID case (UID not in /etc/passwd).
|
|
# See #31959 and docs/deployment/docker.md.
|
|
RUN useradd --uid 2000 --gid 0 --create-home --home-dir /home/vllm \
|
|
--shell /bin/bash vllm \
|
|
&& mkdir -p /home/vllm/.cache /home/vllm/.config \
|
|
&& chown -R 2000:0 /home/vllm \
|
|
&& chmod -R g+rwX /home/vllm \
|
|
# Allow the entrypoint wrapper to append a /etc/passwd entry for an
|
|
# arbitrary runtime UID that shares GID 0. Without this, `whoami`, bash's
|
|
# `\u` prompt, `id -un`, and anything else that calls `getpwuid()`
|
|
# directly return "I have no name!" for OpenShift-style arbitrary UIDs.
|
|
# This matches the convention used by Red Hat UBI base images.
|
|
&& chgrp 0 /etc/passwd /etc/group \
|
|
&& chmod g=u /etc/passwd /etc/group
|
|
COPY docker/entrypoints/vllm-nonroot-entrypoint.sh \
|
|
/usr/local/bin/vllm-nonroot-entrypoint.sh
|
|
RUN chmod 0755 /usr/local/bin/vllm-nonroot-entrypoint.sh
|
|
|
|
# Enable CUDA forward compatibility by setting '-e VLLM_ENABLE_CUDA_COMPATIBILITY=1'
|
|
# Only needed for datacenter/professional GPUs with older drivers.
|
|
# See: https://docs.nvidia.com/deploy/cuda-compatibility/
|
|
ENV VLLM_ENABLE_CUDA_COMPATIBILITY=0
|
|
|
|
# ============================================================
|
|
# SLOW-CHANGING DEPENDENCIES BELOW
|
|
# These are the expensive layers that we want to cache
|
|
# ============================================================
|
|
|
|
# Install PyTorch and core CUDA dependencies
|
|
# This is ~2GB and rarely changes
|
|
ARG PYTORCH_CUDA_INDEX_BASE_URL
|
|
COPY requirements/common.txt /tmp/common.txt
|
|
COPY requirements/cuda.txt /tmp/requirements-cuda.txt
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
if [ "$(echo $CUDA_VERSION | cut -d. -f1)" = "12" ]; then \
|
|
sed -i 's/^nvidia-cutlass-dsl\[cu13\]/nvidia-cutlass-dsl/' /tmp/requirements-cuda.txt; \
|
|
sed -i 's/^humming-kernels\[cu13\]/humming-kernels[cu12]/' /tmp/requirements-cuda.txt; \
|
|
fi && \
|
|
uv pip install --system -r /tmp/requirements-cuda.txt \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.') && \
|
|
rm /tmp/requirements-cuda.txt /tmp/common.txt
|
|
|
|
# Install FlashInfer JIT cache (requires CUDA-version-specific index URL)
|
|
# https://docs.flashinfer.ai/installation.html
|
|
# From versions.json: .flashinfer.version
|
|
ARG FLASHINFER_VERSION=0.6.11.post2
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
uv pip install --system flashinfer-jit-cache==${FLASHINFER_VERSION} \
|
|
--extra-index-url https://flashinfer.ai/whl/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.')
|
|
|
|
# ============================================================
|
|
# OPENAI API SERVER DEPENDENCIES
|
|
# Pre-install these to avoid reinstalling on every vLLM wheel rebuild
|
|
# ============================================================
|
|
|
|
# Install gdrcopy (saves ~6s per build)
|
|
# TODO (huydhn): There is no prebuilt gdrcopy package on 12.9 at the moment
|
|
ARG GDRCOPY_CUDA_VERSION=12.8
|
|
ARG GDRCOPY_OS_VERSION=Ubuntu22_04
|
|
ARG TARGETPLATFORM
|
|
COPY tools/install_gdrcopy.sh /tmp/install_gdrcopy.sh
|
|
RUN set -eux; \
|
|
case "${TARGETPLATFORM}" in \
|
|
linux/arm64) UUARCH="aarch64" ;; \
|
|
linux/amd64) UUARCH="x64" ;; \
|
|
*) echo "Unsupported TARGETPLATFORM: ${TARGETPLATFORM}" >&2; exit 1 ;; \
|
|
esac; \
|
|
/tmp/install_gdrcopy.sh "${GDRCOPY_OS_VERSION}" "${GDRCOPY_CUDA_VERSION}" "${UUARCH}" && \
|
|
rm /tmp/install_gdrcopy.sh
|
|
|
|
# Install vllm-openai dependencies (saves ~2.6s per build)
|
|
# These are stable packages that don't depend on vLLM itself
|
|
# From versions.json: .bitsandbytes.x86_64, .bitsandbytes.arm64
|
|
# From versions.json: .openai_server_extras.timm, .openai_server_extras.runai_model_streamer
|
|
ARG BITSANDBYTES_VERSION_X86=0.46.1
|
|
ARG BITSANDBYTES_VERSION_ARM64=0.42.0
|
|
ARG TIMM_VERSION=">=1.0.17"
|
|
ARG RUNAI_MODEL_STREAMER_VERSION=">=0.15.7"
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
|
|
BITSANDBYTES_VERSION="${BITSANDBYTES_VERSION_ARM64}"; \
|
|
else \
|
|
BITSANDBYTES_VERSION="${BITSANDBYTES_VERSION_X86}"; \
|
|
fi; \
|
|
uv pip install --system accelerate modelscope \
|
|
"bitsandbytes>=${BITSANDBYTES_VERSION}" "timm${TIMM_VERSION}" "runai-model-streamer[s3,gcs,azure]${RUNAI_MODEL_STREAMER_VERSION}"
|
|
|
|
# ============================================================
|
|
# VLLM INSTALLATION (depends on build stage)
|
|
# ============================================================
|
|
|
|
ARG PIP_INDEX_URL UV_INDEX_URL
|
|
ARG PIP_EXTRA_INDEX_URL UV_EXTRA_INDEX_URL
|
|
ARG PYTORCH_CUDA_INDEX_BASE_URL
|
|
ARG PIP_KEYRING_PROVIDER UV_KEYRING_PROVIDER
|
|
|
|
# We can specify the standard or nightly build of PyTorch
|
|
ARG PYTORCH_NIGHTLY
|
|
|
|
# Install vLLM wheel first, so that torch etc will be installed.
|
|
# Check whether to install torch nightly instead of release for this build.
|
|
COPY --from=base /workspace/torch_lib_versions.txt torch_lib_versions.txt
|
|
RUN --mount=type=bind,from=build,src=/workspace/dist,target=/vllm-workspace/dist \
|
|
--mount=type=bind,from=build,src=/workspace/flash-attn-v100-dist,target=/vllm-workspace/flash-attn-v100-dist \
|
|
--mount=type=cache,target=/opt/uv/cache \
|
|
if [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
|
|
echo "Installing torch nightly..." \
|
|
&& uv pip install --system $(cat torch_lib_versions.txt | xargs) --pre \
|
|
--index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/nightly/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.') \
|
|
&& echo "Installing vLLM..." \
|
|
&& uv pip install --system flash-attn-v100-dist/*.whl dist/*.whl --verbose \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/nightly/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
|
|
else \
|
|
echo "Installing vLLM..." \
|
|
&& uv pip install --system flash-attn-v100-dist/*.whl dist/*.whl --verbose \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
|
|
fi
|
|
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
. /etc/environment && \
|
|
uv pip list
|
|
|
|
# Pytorch now installs NVSHMEM, setting LD_LIBRARY_PATH
|
|
ENV LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
|
|
|
|
# Install EP kernels wheels (DeepEP) that have been built in the `build` stage
|
|
RUN --mount=type=bind,from=build,src=/tmp/ep_kernels_workspace/dist,target=/vllm-workspace/ep_kernels/dist \
|
|
--mount=type=cache,target=/opt/uv/cache \
|
|
uv pip install --system ep_kernels/dist/*.whl --verbose \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.')
|
|
|
|
# Download FlashInfer precompiled cubins AFTER all pip installs are done.
|
|
# This must run after the vLLM wheel and EP kernels installs above, because
|
|
# those can reinstall/touch flashinfer packages. Downloading cubins earlier
|
|
# (in the flashinfer-jit-cache layer) causes ~2.5 GB of layer duplication
|
|
# when a later pip install overwrites flashinfer package files.
|
|
RUN flashinfer show-config && flashinfer download-cubin
|
|
|
|
# CUDA image changed from /usr/local/nvidia to /usr/local/cuda in 12.8 but will
|
|
# return to /usr/local/nvidia in 13.0 to allow container providers to mount drivers
|
|
# consistently from the host (see https://github.com/vllm-project/vllm/issues/18859).
|
|
# Until then, add /usr/local/nvidia/lib64 before the image cuda path to allow override.
|
|
ENV LD_LIBRARY_PATH=/usr/local/nvidia/lib64:${LD_LIBRARY_PATH}
|
|
|
|
# 1Cat SM70/V100 runtime defaults. Keep model-specific choices such as
|
|
# CUDA_VISIBLE_DEVICES, tensor parallel size, quantization, and model path in the
|
|
# run command, but make the validated baseline environment the image default.
|
|
ENV CUDA_DEVICE_ORDER=PCI_BUS_ID \
|
|
VLLM_SM70_FLASH_ATTN_V100=1 \
|
|
VLLM_SM70_FLASH_V100_0DOT3_COMPILE_GRAPH=1 \
|
|
VLLM_SM70_QWEN_GDN_FULL_FORWARD=0 \
|
|
VLLM_SM70_QWEN_GDN_DISABLE_FULL_FORWARD=0 \
|
|
VLLM_SM70_QWEN_GDN_SPEC_CORE_OP=0 \
|
|
TORCHINDUCTOR_CACHE_DIR=/tmp/torchinductor_vllm \
|
|
TORCHINDUCTOR_COMPILE_THREADS=1 \
|
|
TRITON_CACHE_AUTOTUNING=1 \
|
|
TILELANG_CLEANUP_TEMP_FILES=1 \
|
|
TOKENIZERS_PARALLELISM=false
|
|
|
|
# Copy examples and benchmarks at the end to minimize cache invalidation
|
|
COPY examples examples
|
|
COPY benchmarks benchmarks
|
|
COPY ./vllm/collect_env.py .
|
|
#################### vLLM installation IMAGE ####################
|
|
#################### TEST IMAGE ####################
|
|
# image to run unit testing suite
|
|
# note that this uses vllm installed by `pip`
|
|
FROM vllm-base AS test
|
|
|
|
ADD . /vllm-workspace/
|
|
|
|
ARG PYTHON_VERSION
|
|
ARG TARGETPLATFORM
|
|
|
|
ARG PIP_INDEX_URL UV_INDEX_URL
|
|
ARG PIP_EXTRA_INDEX_URL UV_EXTRA_INDEX_URL
|
|
ARG PYTORCH_CUDA_INDEX_BASE_URL
|
|
|
|
# This timeout (in seconds) is necessary when installing some dependencies via uv since it's likely to time out
|
|
# Reference: https://github.com/astral-sh/uv/pull/1694
|
|
ENV UV_HTTP_TIMEOUT=500
|
|
ENV UV_INDEX_STRATEGY="unsafe-best-match"
|
|
# Use copy mode to avoid hardlink failures with Docker cache mounts
|
|
ENV UV_LINK_MODE=copy
|
|
|
|
RUN apt-get update -y \
|
|
&& apt-get install -y git
|
|
|
|
# We can specify the standard or nightly build of PyTorch
|
|
ARG PYTORCH_NIGHTLY
|
|
|
|
# Install development dependencies (for testing)
|
|
COPY requirements/lint.txt requirements/lint.txt
|
|
COPY requirements/test/cuda.in requirements/test/cuda.in
|
|
COPY requirements/test/cuda.txt requirements/test/cuda.txt
|
|
COPY requirements/dev.txt requirements/dev.txt
|
|
COPY use_existing_torch.py use_existing_torch.py
|
|
COPY --from=base /workspace/torch_lib_versions.txt torch_lib_versions.txt
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
CUDA_MAJOR="${CUDA_VERSION%%.*}"; \
|
|
if [ "$CUDA_MAJOR" -ge 12 ]; then \
|
|
if [ "${PYTORCH_NIGHTLY}" = "1" ]; then \
|
|
echo "Installing dev requirements plus torch nightly..." \
|
|
&& python3 use_existing_torch.py --prefix \
|
|
&& cat torch_lib_versions.txt >> requirements/test/cuda.in \
|
|
&& uv pip compile requirements/test/cuda.in -o requirements/test/cuda.txt --index-strategy unsafe-best-match \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/nightly/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.') \
|
|
&& uv pip install --system $(cat torch_lib_versions.txt | xargs) --pre \
|
|
-r requirements/dev.txt \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/nightly/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
|
|
else \
|
|
echo "Installing dev requirements..." \
|
|
&& if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
|
|
echo "Recompiling test requirements for arm64..." \
|
|
&& uv pip compile requirements/test/cuda.in -o requirements/test/cuda.txt --index-strategy unsafe-best-match \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
|
|
fi \
|
|
&& uv pip install --system -r requirements/dev.txt \
|
|
--extra-index-url ${PYTORCH_CUDA_INDEX_BASE_URL}/cu$(echo $CUDA_VERSION | cut -d. -f1,2 | tr -d '.'); \
|
|
fi \
|
|
fi
|
|
|
|
# install development dependencies (for testing)
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
uv pip install --system -e tests/vllm_test_utils
|
|
|
|
# enable fast downloads from hf (for testing)
|
|
ENV HF_XET_HIGH_PERFORMANCE 1
|
|
|
|
# increase timeout for hf downloads (for testing)
|
|
ENV HF_HUB_DOWNLOAD_TIMEOUT 60
|
|
|
|
# Copy in the v1 package for testing (it isn't distributed yet)
|
|
COPY vllm/v1 /usr/local/lib/python${PYTHON_VERSION}/dist-packages/vllm/v1
|
|
|
|
# Source code is used in the `python_only_compile.sh` test
|
|
# We hide it inside `src/` so that this source code
|
|
# will not be imported by other tests
|
|
RUN mkdir src
|
|
RUN mv vllm src/vllm
|
|
#################### TEST IMAGE ####################
|
|
|
|
#################### OPENAI API SERVER ####################
|
|
# base openai image with additional requirements, for any subsequent openai-style images
|
|
FROM vllm-base AS vllm-openai-base
|
|
ARG TARGETPLATFORM
|
|
ARG INSTALL_KV_CONNECTORS=false
|
|
ARG CUDA_VERSION
|
|
ARG VLLM_BUILD_COMMIT
|
|
ARG VLLM_BUILD_PIPELINE
|
|
ARG VLLM_BUILD_URL
|
|
ARG VLLM_IMAGE_TAG
|
|
|
|
ARG PIP_INDEX_URL UV_INDEX_URL
|
|
ARG PIP_EXTRA_INDEX_URL UV_EXTRA_INDEX_URL
|
|
|
|
# This timeout (in seconds) is necessary when installing some dependencies via uv since it's likely to time out
|
|
# Reference: https://github.com/astral-sh/uv/pull/1694
|
|
ENV UV_HTTP_TIMEOUT=500
|
|
|
|
# install kv_connectors if requested
|
|
ARG torch_cuda_arch_list='7.5 8.0 8.6 8.9 9.0 10.0 11.0 12.0+PTX'
|
|
ENV TORCH_CUDA_ARCH_LIST=${torch_cuda_arch_list}
|
|
RUN --mount=type=cache,target=/opt/uv/cache \
|
|
--mount=type=bind,source=requirements/kv_connectors.txt,target=/tmp/kv_connectors.txt,ro \
|
|
CUDA_MAJOR="${CUDA_VERSION%%.*}"; \
|
|
CUDA_VERSION_DASH=$(echo $CUDA_VERSION | cut -d. -f1,2 | tr '.' '-'); \
|
|
CUDA_HOME=/usr/local/cuda; \
|
|
# lmcache requires explicit specifying CUDA_HOME
|
|
BUILD_PKGS="libcusparse-dev-${CUDA_VERSION_DASH} \
|
|
libcublas-dev-${CUDA_VERSION_DASH} \
|
|
libcusolver-dev-${CUDA_VERSION_DASH}"; \
|
|
if [ "$INSTALL_KV_CONNECTORS" = "true" ]; then \
|
|
uv pip install --system -r /tmp/kv_connectors.txt --no-build || ( \
|
|
# if the above fails, install from source
|
|
apt-get update -y && \
|
|
apt-get install -y --no-install-recommends --allow-change-held-packages ${BUILD_PKGS} && \
|
|
uv pip install --system -r /tmp/kv_connectors.txt --no-build-isolation && \
|
|
apt-get purge -y ${BUILD_PKGS} && \
|
|
# clean up -dev packages, keep runtime libraries
|
|
rm -rf /var/lib/apt/lists/* \
|
|
); \
|
|
# Force-reinstall the matching CUDA wheel so the correct nixl_ep_cpp.so is installed.
|
|
uv pip install --system --force-reinstall --no-deps nixl-cu${CUDA_MAJOR}; \
|
|
fi
|
|
|
|
# Optional override: install mooncake-transfer-engine from a URL instead of the
|
|
# PyPI release pulled in above. Use this for wheels built with non-default CMake
|
|
# flags (e.g. `STORE_USE_ETCD=ON` for master HA). The URL's manylinux glibc
|
|
# floor must be <= the FINAL_BASE_IMAGE's glibc.
|
|
ARG MOONCAKE_WHEEL_AARCH64
|
|
ARG MOONCAKE_WHEEL_X86_64
|
|
RUN if [ "$INSTALL_KV_CONNECTORS" = "true" ]; then \
|
|
if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
|
|
WHEEL="${MOONCAKE_WHEEL_AARCH64}"; \
|
|
else \
|
|
WHEEL="${MOONCAKE_WHEEL_X86_64}"; \
|
|
fi && \
|
|
if [ -n "${WHEEL}" ]; then \
|
|
uv pip install --system "${WHEEL}" && \
|
|
CUDA_MAJOR="${CUDA_VERSION%%.*}" && \
|
|
if [ ! -f /usr/local/cuda/lib64/libcudart.so ] && \
|
|
[ -f "/usr/local/cuda/lib64/libcudart.so.${CUDA_MAJOR}" ]; then \
|
|
ln -s "libcudart.so.${CUDA_MAJOR}" /usr/local/cuda/lib64/libcudart.so; \
|
|
fi; \
|
|
fi; \
|
|
fi
|
|
|
|
ENV VLLM_USAGE_SOURCE production-docker-image
|
|
ENV VLLM_BUILD_COMMIT=${VLLM_BUILD_COMMIT:-unknown} \
|
|
VLLM_BUILD_PIPELINE=${VLLM_BUILD_PIPELINE:-local} \
|
|
VLLM_BUILD_URL=${VLLM_BUILD_URL:-} \
|
|
VLLM_IMAGE_TAG=${VLLM_IMAGE_TAG:-local/vllm-openai:dev}
|
|
LABEL org.opencontainers.image.source="https://github.com/vllm-project/vllm" \
|
|
org.opencontainers.image.revision="${VLLM_BUILD_COMMIT}" \
|
|
org.opencontainers.image.version="${VLLM_IMAGE_TAG}" \
|
|
org.opencontainers.image.url="${VLLM_BUILD_URL}" \
|
|
ai.vllm.build.commit="${VLLM_BUILD_COMMIT}" \
|
|
ai.vllm.build.pipeline="${VLLM_BUILD_PIPELINE}" \
|
|
ai.vllm.build.url="${VLLM_BUILD_URL}" \
|
|
ai.vllm.image.tag="${VLLM_IMAGE_TAG}"
|
|
|
|
# define sagemaker first, so it is not default from `docker build`
|
|
FROM vllm-openai-base AS vllm-sagemaker
|
|
|
|
COPY examples/deployment/sagemaker-entrypoint.sh .
|
|
RUN chmod +x sagemaker-entrypoint.sh
|
|
ENTRYPOINT ["./sagemaker-entrypoint.sh"]
|
|
|
|
FROM vllm-openai-base AS vllm-openai
|
|
|
|
# To run the image as non-root, either build the `vllm-openai-nonroot` target
|
|
# below, or in a derived Dockerfile uncomment the following line and ensure
|
|
# any additional layers chgrp-0 / chmod-g+rwX paths they write to. The `vllm`
|
|
# user (UID 2000, GID 0) is already created in the `vllm-base` stage.
|
|
# See docs/deployment/docker.md.
|
|
# USER vllm
|
|
ENTRYPOINT ["vllm", "serve"]
|
|
#################### OPENAI API SERVER ####################
|
|
|
|
#################### OPENAI API SERVER (NON-ROOT, OPT-IN) ####################
|
|
# Non-root-ready variant of `vllm-openai`. Built via:
|
|
# docker build --target vllm-openai-nonroot -t vllm:openai-nonroot \
|
|
# -f docker/Dockerfile .
|
|
#
|
|
# Runtime behavior:
|
|
# * Default USER is `vllm` (UID 2000, GID 0) created in `vllm-base`.
|
|
# * HOME is /home/vllm, pre-created group-0-writable so arbitrary UIDs in
|
|
# group 0 (OpenShift / `--user <uid>:0`) can also use the image.
|
|
# * Entrypoint wrapper handles the "UID not in /etc/passwd" case for truly
|
|
# arbitrary UIDs by falling back HOME/USER to sane writable defaults.
|
|
# * All cache/config envs (HF_HOME, VLLM_CACHE_ROOT, TRITON_CACHE_DIR, ...)
|
|
# remain unset so their library defaults resolve to $HOME/.cache/... ,
|
|
# which is writable.
|
|
FROM vllm-openai AS vllm-openai-nonroot
|
|
|
|
USER vllm
|
|
WORKDIR /home/vllm
|
|
ENTRYPOINT ["/usr/local/bin/vllm-nonroot-entrypoint.sh"]
|
|
#################### OPENAI API SERVER (NON-ROOT, OPT-IN) ####################
|