Dockerfile 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. # syntax=docker/dockerfile:1.7
  2. # karmic-kraken (local-inference-lab vLLM fork, dev/karmic-kraken) — GB10/Spark build.
  3. #
  4. # Clone-at-pin build, NO staged tarballs: the Dockerfile clones every source
  5. # at the pins in versions.env and gates each one (HEAD commit + tree hash).
  6. # A fresh clone of this repo + `bash build.sh` reproduces this image end to
  7. # end. Current tip: vLLM 636afde9 (2026-10-08), which takes B12X from
  8. # FlashInfer 0.7.1 (the standalone b12x repo is archived — no separate wheel).
  9. #
  10. # Runtime: CUDA 13.4.2 devel aarch64 base + torch 2.13.0 cu130 + flashinfer
  11. # 0.7.1 (carries B12X as flashinfer/experimental/b12x + the top-level `b12x`
  12. # import package). GB10 sm_121 fixes baked in (patch_cuda_sm12x.py, eugr
  13. # patch set).
  14. #
  15. # Build: cd docker-images/karmic-kraken && TAG=... bash build.sh
  16. ARG CUDA_BASE_IMAGE
  17. ARG CUDA_BASE_DIGEST
  18. ARG UV_VERSION
  19. FROM ${CUDA_BASE_IMAGE}@${CUDA_BASE_DIGEST} AS apt-base
  20. ARG PYPI_INDEX_URL
  21. ARG APT_SOURCE
  22. ENV DEBIAN_FRONTEND=noninteractive \
  23. PIP_BREAK_SYSTEM_PACKAGES=1 \
  24. UV_SYSTEM_PYTHON=1 UV_BREAK_SYSTEM_PACKAGES=1 UV_LINK_MODE=copy
  25. COPY locks/apt-sources.list /tmp/apt-sources-snapshot.list
  26. COPY locks/apt-packages.txt /tmp/apt-packages.txt
  27. COPY locks/python-bootstrap.txt /tmp/python-bootstrap.txt
  28. COPY locks/deps.lock /tmp/deps.lock
  29. # APT_SOURCE (versions.env):
  30. # snapshot (default, historical behavior): the pinned point-in-time mirror
  31. # + exact package versions — strictly reproducible, but
  32. # snapshot.ubuntu.com is slow (~30 kB/s) and intermittently 503s
  33. # (12-min apt stall, 2026-09-08).
  34. # current: the live archive.ubuntu.com — fast and reliable; installs the
  35. # pinned package names unversioned. Acceptable: the engine stack is
  36. # pinned by the vLLM/B12X/LMCache source pins, not by apt.
  37. RUN set -eux; \
  38. if [ "${APT_SOURCE:-snapshot}" = "current" ]; then \
  39. printf '%s\n' \
  40. "deb http://ports.ubuntu.com/ubuntu-ports/ noble main restricted universe multiverse" \
  41. "deb http://ports.ubuntu.com/ubuntu-ports/ noble-updates main restricted universe multiverse" \
  42. "deb http://ports.ubuntu.com/ubuntu-ports/ noble-security main restricted universe multiverse" \
  43. > /etc/apt/sources.list; \
  44. PKGS="$(grep -vE '^\s*(#|$)' /tmp/apt-packages.txt | cut -d= -f1)"; \
  45. else \
  46. cp /tmp/apt-sources-snapshot.list /etc/apt/sources.list; \
  47. PKGS="$(grep -vE '^\s*(#|$)' /tmp/apt-packages.txt)"; \
  48. fi; \
  49. rm -f /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources; \
  50. apt-get update; \
  51. apt-get install -y --no-install-recommends ${PKGS}; \
  52. rm -rf /var/lib/apt/lists/*; \
  53. python3 -m pip install --no-cache-dir --no-deps \
  54. -r /tmp/python-bootstrap.txt --index-url "${PYPI_INDEX_URL}"
  55. FROM apt-base AS torch-base
  56. ARG PYPI_INDEX_URL
  57. ARG PYTORCH_INDEX_URL
  58. ARG TORCH_VERSION TORCHVISION_VERSION TORCHAUDIO_VERSION
  59. ARG FLASHINFER_VERSION
  60. RUN --mount=type=cache,id=uv-cache,target=/root/.cache/uv \
  61. uv pip install \
  62. --index-url ${PYPI_INDEX_URL} \
  63. --extra-index-url ${PYTORCH_INDEX_URL} \
  64. --index-strategy unsafe-best-match \
  65. "torch==${TORCH_VERSION}" \
  66. "torchvision==${TORCHVISION_VERSION}" \
  67. "torchaudio==${TORCHAUDIO_VERSION}" \
  68. "flashinfer-python==${FLASHINFER_VERSION}"
  69. # DeepGEMM: cloned in-build (proven to work on the nodes via git; pins are
  70. # gated again in fetch-deps.sh against the vLLM tree's own declaration).
  71. FROM torch-base AS deepgemm-builder
  72. ARG DEEPGEMM_REPO DEEPGEMM_BRANCH DEEPGEMM_REF
  73. RUN set -eux; \
  74. git config --global protocol.version 0; \
  75. git clone --branch ${DEEPGEMM_BRANCH} ${DEEPGEMM_REPO} /deps/deepgemm; \
  76. cd /deps/deepgemm; \
  77. git checkout ${DEEPGEMM_REF}; \
  78. git submodule update --init --depth 1 -- third-party/cutlass third-party/fmt
  79. # ---- vLLM @ r27 integration branch, gated by commit + tree hash ----
  80. FROM torch-base AS vllm-clone
  81. ARG VLLM_REPO VLLM_PIN VLLM_BRANCH
  82. RUN set -eux; \
  83. git config --global protocol.version 0; \
  84. git init -q /workspace/vllm; \
  85. git -C /workspace/vllm fetch -q --depth 1 ${VLLM_REPO} ${VLLM_PIN}; \
  86. git -C /workspace/vllm checkout -q FETCH_HEAD; \
  87. cd /workspace/vllm; \
  88. test "$(git rev-parse HEAD)" = "${VLLM_PIN}"; \
  89. echo "vllm at $(git rev-parse HEAD) (branch ${VLLM_BRANCH})"; \
  90. git config --global --add safe.directory /workspace/vllm
  91. # ---- All build sub-deps, cloned at pins the r27 tree itself declares ----
  92. # REGEN_LOCK=1: fetch-deps.sh rewrites /tmp/deps.lock from the staged state
  93. # (pin cuts) instead of verifying against it — export the stage to harvest
  94. # the new lock, then commit it.
  95. FROM vllm-clone AS deps-fetched
  96. ARG REGEN_LOCK=""
  97. COPY fetch-deps.sh /tmp/fetch-deps.sh
  98. RUN if [ -n "$REGEN_LOCK" ]; then bash /tmp/fetch-deps.sh --regen-lock /tmp/deps.lock; else bash /tmp/fetch-deps.sh; fi
  99. FROM deps-fetched AS vllm-builder
  100. WORKDIR /workspace/vllm
  101. # Hard-declared (do NOT rely on stage-inherited ENVs): the buildkit build
  102. # has no GPU, so torch's device-capability autodetect is unavailable and
  103. # the wheel must be told the target arch explicitly (the r27 slip: kernels
  104. # came out sm120-only -> cudaErrorNoKernelImageForDevice at boot).
  105. ENV TORCH_CUDA_ARCH_LIST=12.1a GIT_PROTOCOL=0
  106. ARG DEEPGEMM_REF
  107. ARG VLLM_PRETEND_VERSION
  108. ARG SOURCE_DATE_EPOCH
  109. ARG BUILD_JOBS
  110. # Empty default overrides (profile `FLASH_KDA_SRC_DIR=`) make the vLLM tree
  111. # fall back to its own pinned FlashKDA + in-tree packed-checkpoints patch
  112. # (required by the r28.1+ flashkda.cmake API gate); the default keeps the
  113. # r27-style shared /deps2 checkout for the older trees.
  114. ARG FLASH_KDA_SRC_DIR=
  115. # eugr/spark-vllm-docker build-time patches (main, 2026-09-02): all are
  116. # source-aware/idempotent (skip when the vulnerable pattern is absent), so
  117. # running the full set is safe on the r27 tree. Env gates are opt-in and ON
  118. # for this build (sm_121a + b12x):
  119. # - preserve_sm12x_target: keep 12.1a in CUDA_SUPPORTED_ARCHS (their
  120. # standard CUDA build collapses 12.1a -> 12.0)
  121. # - sm120_cooperative_topk: keep SM90-only (Spark fix)
  122. # - mrv2_speculator_cudagraph_pool / spark_kv_cache_cleanup (UMA snapshot
  123. # flow) / b12x c128a alignment / flashinfer b12x swigluoai / routed
  124. # expert weight shape / topk_softplus_sqrt / others: see each script.
  125. COPY patches-eugr/patch_vllm_*.py /tmp/eugr-patches/
  126. COPY --from=deepgemm-builder /deps/deepgemm /deps/deepgemm
  127. RUN VLLM_PRESERVE_SM12X_TARGET=1 \
  128. VLLM_PATCH_B12X_C128A_ALIGNMENT=1 \
  129. python3 /tmp/eugr-patches/patch_vllm_mrv2_speculator_cudagraph_pool.py . \
  130. && python3 /tmp/eugr-patches/patch_vllm_b12x_c128a_topk_alignment.py . \
  131. && python3 /tmp/eugr-patches/patch_vllm_flashinfer_b12x_swigluoai.py . \
  132. && python3 /tmp/eugr-patches/patch_vllm_topk_softplus_sqrt_control_flow.py . \
  133. && python3 /tmp/eugr-patches/patch_vllm_preserve_sm12x_target.py . \
  134. && python3 /tmp/eugr-patches/patch_vllm_diffusion_tensor_causal.py . \
  135. && python3 /tmp/eugr-patches/patch_vllm_gemma4_mtp_embedding_share.py . \
  136. && python3 /tmp/eugr-patches/patch_vllm_sm120_cooperative_topk.py . \
  137. && python3 /tmp/eugr-patches/patch_vllm_autogptq_symmetric_moe_qzeros.py . \
  138. && python3 /tmp/eugr-patches/patch_vllm_disable_minimax_qk_rmsnorm_ipc.py . \
  139. && python3 /tmp/eugr-patches/patch_vllm_routed_experts_weight_shape.py . \
  140. && python3 /tmp/eugr-patches/patch_vllm_spark_kv_cache_cleanup.py .
  141. RUN --mount=type=cache,id=uv-cache,target=/root/.cache/uv \
  142. --mount=type=cache,id=ccache,target=/root/.ccache \
  143. --mount=type=cache,id=cargo-registry,target=/root/.cargo/registry \
  144. --mount=type=cache,id=rust-target,target=/workspace/vllm/vllm/target \
  145. git config --global protocol.version 0 \
  146. && uv pip install setuptools-rust setuptools-scm \
  147. && (command -v cargo >/dev/null 2>&1 || curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --no-modify-path) \
  148. && export PATH=/root/.cargo/bin:$PATH \
  149. && (command -v protoc >/dev/null 2>&1 || (apt-get update -qq && apt-get install -y --no-install-recommends protobuf-compiler libprotobuf-dev >/dev/null && rm -rf /var/lib/apt/lists/*)) \
  150. && _j="${BUILD_JOBS:-$(nproc)}" \
  151. && export GIT_PROTOCOL=0 MAX_JOBS="${_j}" CMAKE_BUILD_PARALLEL_LEVEL="${_j}" \
  152. VLLM_REQUIRE_RUST_FRONTEND=1 CARGO_BUILD_JOBS="${_j}" \
  153. SETUPTOOLS_SCM_PRETEND_VERSION="${VLLM_PRETEND_VERSION}" \
  154. TRITON_KERNELS_SRC_DIR=/deps2/triton_kernels \
  155. FMHA_SM100_SRC_DIR=/deps2/MSA \
  156. FLASH_MLA_SRC_DIR=/deps2/FlashMLA \
  157. FLASH_KDA_SRC_DIR="${FLASH_KDA_SRC_DIR}" \
  158. VLLM_FLASH_ATTN_SRC_DIR=/deps2/flash-attention \
  159. QUTLASS_SRC_DIR=/deps2/qutlass \
  160. TML_FA4_SRC_DIR=/deps2/tml-fa4 \
  161. VLLM_CUTLASS_SRC_DIR=/deps2/cutlass \
  162. CUTLASS_INCLUDE_DIR_PRE=/deps2/cutlass/include \
  163. && python3 use_existing_torch.py \
  164. && uv build --no-build-isolation --wheel . --out-dir=/wheels -v
  165. # ---- B12X: now ships inside flashinfer-python 0.7.1 (installed in torch-base) ----
  166. # The standalone lukealonso/b12x repo is archived; its code continues in
  167. # FlashInfer, whose wheel installs the top-level `b12x` package that vLLM
  168. # imports. No separate b12x wheel is built or installed (a standalone b12x
  169. # package must not sit next to flashinfer 0.7.1 — same namespace).
  170. # ---- Runner: flattened GB10 serving image ----
  171. FROM torch-base AS runner
  172. ARG PYPI_INDEX_URL
  173. COPY checksums/tiktoken.sha256 /tmp/tiktoken.sha256
  174. COPY patch_cuda_sm12x.py /tmp/patch_cuda_sm12x.py
  175. WORKDIR /workspace
  176. RUN mkdir -p tiktoken_encodings \
  177. && wget -O tiktoken_encodings/o200k_base.tiktoken https://openaipublic.blob.core.windows.net/encodings/o200k_base.tiktoken \
  178. && wget -O tiktoken_encodings/cl100k_base.tiktoken https://openaipublic.blob.core.windows.net/encodings/cl100k_base.tiktoken \
  179. && cd tiktoken_encodings && sha256sum -c /tmp/tiktoken.sha256
  180. ENV TIKTOKEN_ENCODINGS_BASE=/workspace/tiktoken_encodings
  181. RUN --mount=type=bind,from=vllm-builder,source=/wheels,target=/vllm-wheels \
  182. --mount=type=cache,id=uv-cache,target=/root/.cache/uv \
  183. pip install --no-cache-dir --no-build-isolation /vllm-wheels/*.whl \
  184. && python3 /tmp/patch_cuda_sm12x.py \
  185. && find /usr/local/lib/python3.12/dist-packages/vllm \
  186. -name "__pycache__" -type d -prune -exec rm -rf {} + 2>/dev/null || true
  187. # b12x loader allocation patch (discord, 2026-09-07): pinned_wc -> managed
  188. # in b12x/integration/vllm/loader.py — two occurrences (the weight_pool call
  189. # and the matching audit label). Reported prefill 1350 -> ~2000 tok/s. No
  190. # recompiles; hard-gated: any pinned_wc left behind fails the build.
  191. #
  192. # Conditional since the r38 cut (2026-09-19): b12x master 0f3a8cbf replaced
  193. # the hardcoded allocation with weight_allocation() in b12x/loader/_pool.py
  194. # (auto-selects "managed" on GB10: pageable_memory_access + host_page_tables
  195. # caps), so the legacy pinned_wc strings are gone and the sed is a no-op.
  196. # Legacy pins (r27..r37 b12x) still carry the pattern and take the gated path.
  197. RUN set -eux; \
  198. F=/usr/local/lib/python3.12/dist-packages/b12x/integration/vllm/loader.py; \
  199. if grep -q 'pinned_wc' "$F" 2>/dev/null; then \
  200. sed -i 's/allocation="pinned_wc"/allocation="managed"/; \
  201. s/"allocation": "pinned_wc"/"allocation": "managed"/' "$F"; \
  202. test "$(grep -c 'allocation="managed"' "$F")" = "1"; \
  203. grep -Fq '"allocation": "managed"' "$F"; \
  204. ! grep -q 'pinned_wc' "$F"; \
  205. else \
  206. echo "b12x loader carries no pinned_wc (new auto-allocation b12x) — patch skipped"; \
  207. test -f "$F"; \
  208. fi
  209. # Build gate: the r27 stack must import with the GB10 patches in place and
  210. # carry the qualified package trees (marker spot-checks from the source lock).
  211. RUN set -eux; \
  212. python3 -c "import vllm; print('vllm', vllm.__version__)"; \
  213. python3 -c "import b12x; print('b12x', getattr(b12x,'__version__','(bundled in flashinfer 0.7.1)'))"; \
  214. python3 -c "import vllm._flashkda_C; print('flashkda_C ok')"; \
  215. python3 -c "from vllm.config.attention import AttentionBackendEnum as E; \
  216. assert E.B12X.value and 'b12x' in E.B12X.value.lower(); print('B12X enum ok')"; \
  217. grep -q "AttentionBackendEnum.B12X," /usr/local/lib/python3.12/dist-packages/vllm/platforms/cuda.py; \
  218. grep -Fq 'def apply_top_k_top_p_probs' /usr/local/lib/python3.12/dist-packages/vllm/v1/sample/ops/topk_topp_sampler.py; \
  219. grep -Fq '_PREPARED_ONESHOT_LAUNCHERS' /usr/local/lib/python3.12/dist-packages/b12x/comm/pcie/_oneshot_cute.py
  220. ENTRYPOINT []
  221. CMD ["bash"]