Skip to content
Merged
3 changes: 1 addition & 2 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ on:
- cu13-x86
- cu13-aarch64
- cu12-x86
- rocm700-mi35x
- rocm700-mi30x
- rocm720-mi35x
- rocm10-mi35x
image_tag:
description: 'Tag mode: latest, dev (rolling + timestamped), or custom'
required: true
Expand Down
38 changes: 16 additions & 22 deletions docker/Dockerfile.rocm
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
# doc-dev: docs/ci/02-docker-build.md
# Multi-arch ROCm image for Miles (built on a prebuilt sglang base):
# ROCm / gfx950 image for Miles (built on a prebuilt sglang base):
#
# 1. rocm700-mi35x (gfx950, ROCm 7.0 / MI350 / MI355X)
# build-arg:SGLANG_IMAGE_REPO=rocm/sgl-dev SGLANG_IMAGE_TAG=v0.5.14-rocm700-mi35x-20260627
#
# 2. rocm700-mi30x (gfx942, ROCm 7.0 / MI300 / MI325)
# build-arg:GPU_ARCH=gfx942 SGLANG_IMAGE_TAG=v0.5.10-rocm700-mi30x
#
# 3. rocm720-mi35x (gfx950, ROCm 7.2 / MI350 / MI355X)
# 1. rocm720-mi35x (gfx950, ROCm 7.2 / MI350 / MI355X, Python 3.10 base)
# build-arg:SGLANG_IMAGE_REPO=rocm/sgl-dev SGLANG_IMAGE_TAG=v0.5.16-rocm720-mi35x-20260730
# WHEELS_TAG_ROCM=rocm720-gfx950-v0.5.16 TE_USE_WHEEL=1 APPLY_ROCR_VMMFIX=1
#
# 2. rocm10-mi35x (gfx950, ROCm 10 / MI350 / MI355X, Python 3.12 base)
# build-arg:SGLANG_IMAGE_REPO=rocm/sgl-dev SGLANG_IMAGE_TAG=v0.5.18-rocm10-mi35x-20260831
# WHEELS_TAG_ROCM=rocm10-gfx950-v0.5.18 TE_USE_WHEEL=1 (cp312 shelf)

ARG SGLANG_IMAGE_REPO=lmsysorg/sglang
ARG SGLANG_IMAGE_TAG=v0.5.10-rocm700-mi35x
ARG SGLANG_IMAGE_REPO=rocm/sgl-dev
ARG SGLANG_IMAGE_TAG=v0.5.16-rocm720-mi35x-20260730
FROM ${SGLANG_IMAGE_REPO}:${SGLANG_IMAGE_TAG} AS sglang

SHELL ["/bin/bash", "-ceuxo", "pipefail"]
Expand All @@ -26,9 +25,8 @@ ARG MEGATRON_BRANCH=miles-main
ARG MILES_COMMIT=main

ARG GPU_ARCH=gfx950
# 1 on ROCm 7.2 to bake the ROCr VMM-pause fix; ROCm 7.0 has no such regression, leave 0.
# 1 bakes the rebuilt ROCr with the VMM-pause fix (ROCm 7.2 needs it; ROCm 10 has it upstream).
ARG APPLY_ROCR_VMMFIX=0
ARG SGLANG_USE_ROCM700A=0
ARG WHEELS_REPO=XinyuJiangCMU/miles-wheels-rocm
ARG WHEELS_TAG_ROCM=rocm720-gfx950-v0.5.16
ARG MAX_JOBS=128
Expand All @@ -48,13 +46,13 @@ WORKDIR /root/

ENV MAX_JOBS=${MAX_JOBS}

# Build configuration for the selected arch (gfx942 / gfx950).
# Build configuration for the target arch.
ENV GPU_ARCH=${GPU_ARCH}
ENV PYTORCH_ROCM_ARCH=${GPU_ARCH}
ENV GPU_ARCH_LIST=${GPU_ARCH}
ENV AMDGPU_TARGET=${GPU_ARCH}

# Transformer Engine build knobs for the v2.8_rocm branch.
# Transformer Engine build knobs (consumed by the TE_USE_WHEEL=0 source build).
ENV NVTE_FRAMEWORK=pytorch
ENV NVTE_ROCM_ARCH=${GPU_ARCH}
ENV NVTE_USE_HIPBLASLT=1
Expand Down Expand Up @@ -89,7 +87,7 @@ RUN mkdir -p /tmp/wheels && \
curl -fsSL "https://api.github.com/repos/${WHEELS_REPO}/releases/tags/${WHEELS_TAG_ROCM}" \
| python3 -c "import sys,json,subprocess,os; w='/tmp/wheels'; [subprocess.run(['curl','-fsSL','-o',os.path.join(w,a['name']),a['browser_download_url']],check=True) for a in json.load(sys.stdin).get('assets',[]) if a['name'].endswith(('.whl','.tar.gz'))]" && \
ls -lh /tmp/wheels/
# Transformer Engine: prebuilt fp8 wheel
# Transformer Engine: prebuilt wheel from the variant's wheels shelf, or source build
ARG TE_USE_WHEEL=0
RUN pip uninstall -y transformer-engine transformer_engine transformer_engine_torch || true; \
if [ "${TE_USE_WHEEL}" = "1" ]; then \
Expand All @@ -113,7 +111,7 @@ RUN pip install flash-linear-attention==0.5.2
# and fix TileLang's HIP fp8->float conversion to use ROCm device intrinsics instead of the SDK host-only operator.
# Drop these patches once the corresponding tilelang/tile_kernels fixes land in the base image.
RUN pip install --no-deps tile_kernels==1.0.0 && \
patch -p1 -d /opt/venv/lib/python3.10/site-packages < /tmp/amd_patch/tile_kernels.patch && \
patch -p1 -d "$(python3 -c 'import site; print(site.getsitepackages()[0])')" < /tmp/amd_patch/tile_kernels.patch && \
patch -p1 -d /opt/tilelang/src/tl_templates/hip < /tmp/amd_patch/tilelang_hip_fp8.patch

RUN rm -rf /root/Megatron-LM && \
Expand All @@ -136,7 +134,7 @@ RUN pip install "numba==0.65.1"

RUN python -c "import sglang; import sgl_kernel; print('SGLang + sgl_kernel: OK')"

RUN pip install git+https://github.com/fzyzcjy/torch_memory_saver.git@f05a8754daf68238d54e4cf31cb3ba866684bbaf --no-cache-dir --force-reinstall
RUN pip install git+https://github.com/fzyzcjy/torch_memory_saver.git@f05a8754daf68238d54e4cf31cb3ba866684bbaf --no-cache-dir --force-reinstall --no-build-isolation

# Fix the ROCm 7.2 ROCr VMM-pause leak.
RUN if [ "$APPLY_ROCR_VMMFIX" = "1" ]; then \
Expand All @@ -151,7 +149,7 @@ RUN if [ "$APPLY_ROCR_VMMFIX" = "1" ]; then \
install -m0644 "/tmp/$asset" "$dst" && rm -f "/tmp/$asset" && \
echo "[vmmfix] installed patched ROCr at $dst"; \
else \
echo "[vmmfix] skipped (APPLY_ROCR_VMMFIX=$APPLY_ROCR_VMMFIX; ROCm 7.0 has no VMM-pause regression)"; \
echo "[vmmfix] skipped (APPLY_ROCR_VMMFIX=$APPLY_ROCR_VMMFIX; ROCm 10 has the fix upstream)"; \
fi
RUN pip install git+https://github.com/radixark/Megatron-Bridge.git@bridge --no-deps --no-build-isolation
RUN pip install megatron-energon --no-deps
Expand All @@ -170,9 +168,6 @@ RUN rm -rf /usr/lib/python3/dist-packages/jwt /usr/lib/python3/dist-packages/PyJ
# Pin the CLI stack (typer/click) for huggingface_hub / Ray compatibility.
RUN pip install "typer==0.25.1" "click==8.2.1"

# Pin numpy 1.x for Megatron compatibility.
RUN pip install "numpy<2"

COPY docker/install-kube-tools.sh /tmp/install-kube-tools.sh
RUN bash /tmp/install-kube-tools.sh "${TARGETARCH}" && rm -f /tmp/install-kube-tools.sh

Expand Down Expand Up @@ -226,7 +221,6 @@ ENV SGLANG_ALLOW_OVERWRITE_LONGER_CONTEXT_LEN=1
ENV SGLANG_MOE_PADDING=1
ENV SGLANG_SET_CPU_AFFINITY=1
ENV SGLANG_ROCM_FUSED_DECODE_MLA=1
ENV SGLANG_USE_ROCM700A=${SGLANG_USE_ROCM700A}
ENV NCCL_MIN_NCHANNELS=112
ENV TORCHINDUCTOR_MAX_AUTOTUNE=1
ENV TORCHINDUCTOR_MAX_AUTOTUNE_POINTWISE=1
Expand Down
32 changes: 11 additions & 21 deletions docker/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,39 +50,30 @@
"WHEELS_TAG_X86": "cu129-x86_64",
},
},
"rocm700-mi35x": {
"rocm720-mi35x": {
"image": "rocm/sgl-dev",
"tag_postfix": "-rocm700-mi35x",
"tag_postfix": "-rocm720-mi35x",
"tag_prefix": "miles",
"dockerfile": "docker/Dockerfile.rocm",
"build_args": {
"GPU_ARCH": "gfx950",
"SGLANG_IMAGE_REPO": "rocm/sgl-dev",
"SGLANG_IMAGE_TAG": "v0.5.14-rocm700-mi35x-20260627",
"SGLANG_USE_ROCM700A": "1",
},
},
"rocm700-mi30x": {
"image": "rocm/sgl-dev",
"tag_postfix": "-rocm700-mi30x",
"tag_prefix": "miles",
"dockerfile": "docker/Dockerfile.rocm",
"build_args": {
"GPU_ARCH": "gfx942",
"SGLANG_IMAGE_TAG": "v0.5.10-rocm700-mi30x",
"SGLANG_USE_ROCM700A": "1",
"SGLANG_IMAGE_TAG": "v0.5.16-rocm720-mi35x-20260730",
"WHEELS_TAG_ROCM": "rocm720-gfx950-v0.5.16",
"APPLY_ROCR_VMMFIX": "1",
"TE_USE_WHEEL": "1",
},
},
"rocm720-mi35x": {
"rocm10-mi35x": {
"image": "rocm/sgl-dev",
"tag_postfix": "-rocm720-mi35x",
"tag_postfix": "-rocm10-mi35x",
"tag_prefix": "miles",
"dockerfile": "docker/Dockerfile.rocm",
"build_args": {
"GPU_ARCH": "gfx950",
"SGLANG_IMAGE_REPO": "rocm/sgl-dev",
"SGLANG_IMAGE_TAG": "v0.5.16-rocm720-mi35x-20260730",
"APPLY_ROCR_VMMFIX": "1",
"SGLANG_IMAGE_TAG": "v0.5.18-rocm10-mi35x-20260831",
"WHEELS_TAG_ROCM": "rocm10-gfx950-v0.5.18",
"TE_USE_WHEEL": "1",
},
},
Expand Down Expand Up @@ -176,9 +167,8 @@ class Variant(str, Enum):
cu13_x86 = "cu13-x86"
cu13_aarch64 = "cu13-aarch64"
cu12_x86 = "cu12-x86"
rocm700_mi35x = "rocm700-mi35x"
rocm700_mi30x = "rocm700-mi30x"
rocm720_mi35x = "rocm720-mi35x"
rocm10_mi35x = "rocm10-mi35x"


class ImageTag(str, Enum):
Expand Down
13 changes: 6 additions & 7 deletions docs/ci/02-docker-build.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ GPU CI runs inside `radixark/miles`. This doc maps which Dockerfiles exist, the
| Path | Builds | Wired into |
| ------------------------ | ------------------------ | -------------------------------------- |
| `docker/Dockerfile` | `radixark/miles` (CUDA) | `docker-build.yml`, `release-docker.yml` |
| `docker/Dockerfile.rocm` | AMD ROCm (MI30x / MI35x) | `docker-build.yml` (`rocm7xx-mi3xx` variants) |
| `docker/Dockerfile.rocm` | AMD ROCm (MI35x) | `docker-build.yml` (`rocm*-mi35x` variants) |


### `docker/Dockerfile` — inputs & output
Expand All @@ -31,7 +31,7 @@ The Dockerfile is the build recipe: it provides the cu13 defaults and emits one

**Output** — one `radixark/miles` image for the platform buildx targets: the SGLang base, then the Python dependencies declared in `requirements.txt`, Megatron-LM at its branch default or caller-pinned commit, Miles, and the prebuilt wheels (`sgl-router` among them). A multi-arch build is one `buildx` run executed once per platform — `TARGETARCH` differs each time, so each arch installs its own wheels — and buildx pushes the two as a single manifest.

`docker/Dockerfile.rocm` is the ROCm counterpart (build-args `GPU_ARCH` + a ROCm `SGLANG_IMAGE_TAG`; the 7.2 variants also set `APPLY_ROCR_VMMFIX=1`, which downloads the ROCr VMM-pause fix `.so` from the `WHEELS_TAG_ROCM` release and installs it — ROCm 7.0 has no such regression and leaves it off).
`docker/Dockerfile.rocm` is the ROCm counterpart (build-args `GPU_ARCH` + a ROCm `SGLANG_IMAGE_TAG`). `rocm720-mi35x` sets `APPLY_ROCR_VMMFIX=1` to install the rebuilt ROCr with the VMM-pause fix from its wheels release; ROCm 10 has the fix upstream. `rocm10-mi35x` uses its own cp312 wheels release (`rocm10-gfx950-v0.5.18`).

## Build script

Expand All @@ -44,9 +44,8 @@ The Dockerfile is the build recipe: it provides the cu13 defaults and emits one
| `cu13-x86` | `radixark/miles:dev` | `linux/amd64` | x86-only build of the same image |
| `cu13-aarch64` | `radixark/miles:dev` | `linux/arm64` | arm64-only build of the same image |
| `cu12-x86` | `radixark/miles:dev-cu12` | `linux/amd64` | CUDA 12.9 legacy |
| `rocm700-mi30x` | `rocm/sgl-dev:miles-rocm700-mi30x` | native | AMD MI30x (`gfx942`, ROCm 7.0) — `docker/Dockerfile.rocm` |
| `rocm700-mi35x` | `rocm/sgl-dev:miles-rocm700-mi35x` | native | AMD MI35x (`gfx950`, ROCm 7.0) — `docker/Dockerfile.rocm` |
| `rocm720-mi35x` | `rocm/sgl-dev:miles-rocm720-mi35x` | native | AMD MI35x (`gfx950`, ROCm 7.2) — `docker/Dockerfile.rocm` |
| `rocm10-mi35x` | `rocm/sgl-dev:miles-rocm10-mi35x` | native | AMD MI35x (`gfx950`, ROCm 10, py3.12 base, ROCm SDK as pip wheels) — `docker/Dockerfile.rocm` |


The cu13 variants share one multi-arch CUDA base image and differ only in platforms. `cu13` runs a single `buildx --platform linux/amd64,linux/arm64` — buildx builds both arches and pushes them as one manifest in a single shot, with the Dockerfile picking each layer's wheels by `TARGETARCH` (see Dockerfile inputs), so `docker pull` auto-selects by host arch.
Expand Down Expand Up @@ -86,7 +85,7 @@ This workflow owns the rolling `dev` and `latest` image families. It has two job
### Triggers: automatic vs manual

- **Automatic** (no human) — the **schedule** (cron 00:00 / 12:00 UTC, gated by `check-upstream`) and any **push to `main` that touches `docker/Dockerfile`, `docker/install-kube-tools.sh`, `docker/verify_transformer_engine.py`, or `requirements.txt`**. Both leave `--variant` empty and build **two images**: `cu13` → `radixark/miles` (multi-arch) and `cu12-x86` → `radixark/miles:dev-cu12`.
- **Manual** — `workflow_dispatch` (pick one variant — see Trigger a build yourself below) or running `docker/build.py` locally. Only the `rocm7xx-mi3xx` images have **no automatic path** (`cu13-x86` / `cu13-aarch64` just rebuild the same `dev` image single-arch).
- **Manual** — `workflow_dispatch` (pick one variant — see Trigger a build yourself below) or running `docker/build.py` locally. Only the `rocm*-mi35x` images have **no automatic path in this repo** (their nightlies live in sgl-project/sglang) (`cu13-x86` / `cu13-aarch64` just rebuild the same `dev` image single-arch).

`docker/build.py` and `docker/patch/**` participate in PR image validation but are not `main`-push triggers; [Release a Version](/ci/04-release) treats them as manual preflight cases.

Expand All @@ -107,7 +106,7 @@ All images push to **Docker Hub**. CUDA variants → `radixark/miles`; ROCm vari
| --- | --- | --- |
| `cu13` / `cu13-x86` / `cu13-aarch64` | `radixark/miles:dev` + `radixark/miles:dev-<YYYYMMDDHHMM>` | `radixark/miles:latest` |
| `cu12-x86` | `radixark/miles:dev-cu12` (+ timestamped sibling) | `radixark/miles:latest-cu12` |
| `rocm700-mi30x` / `rocm700-mi35x` / `rocm720-mi35x` | `rocm/sgl-dev:miles-rocm7xx-mi3xx` (+ timestamped sibling) | `rocm/sgl-dev:latest-rocm7xx-mi3xx` |
| `rocm720-mi35x` / `rocm10-mi35x` | `rocm/sgl-dev:miles-rocm*-mi3xx` (+ timestamped sibling) | `rocm/sgl-dev:latest-rocm*-mi3xx` |

What **moves a shared tag**: `--image-tag dev` overwrites `:dev` (or `:dev-cu12`) and adds a timestamped sibling; on a **scheduled** run `latest`→`dev` *and* `latest-cu12`→`dev-cu12` both advance; pruning likewise runs **only on schedule**, keeping the newest 20 of **each** series — `dev-<ts>` and `dev-cu12-<ts>` independently. Any `workflow_dispatch` — **including** `simulate_schedule` — writes its own tag(s) but never moves `latest` or prunes; only the real cron mutates published tags. See the trigger table above.

Expand All @@ -126,7 +125,7 @@ gh workflow run docker-build.yml -f variant=cu13-x86 -f image_tag=custom -f cust

| input | required | values / default |
| ----- | -------- | ---------------- |
| `variant` | yes | `cu13` / `cu13-x86` / `cu13-aarch64` / `cu12-x86` / `rocm700-mi30x` / `rocm700-mi35x` / `rocm720-mi35x` |
| `variant` | yes | `cu13` / `cu13-x86` / `cu13-aarch64` / `cu12-x86` / `rocm720-mi35x` / `rocm10-mi35x` |
| `image_tag` | yes | `dev` / `latest` / `custom` |
| `custom_tag` | no | tag name; required when `image_tag=custom` |
| `dockerfile` | no | path to Dockerfile (default `docker/Dockerfile`) |
Expand Down
2 changes: 1 addition & 1 deletion docs/developer/versions.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ fleet's image is.
| `cu13` | `radixark/miles:dev` | `linux/amd64` + `linux/arm64`, one manifest. This is the daily image |
| `cu13-x86` / `cu13-aarch64` | `radixark/miles:dev` | Single-arch rebuilds of the same image |
| `cu12-x86` | `radixark/miles:dev-cu12` | `linux/amd64`, CUDA 12.9 legacy |
| `rocm700-mi30x` / `rocm700-mi35x` / `rocm720-mi35x` | `rocm/sgl-dev:miles-rocm7xx-mi3xx` | Native |
| `rocm720-mi35x` / `rocm10-mi35x` | `rocm/sgl-dev:miles-rocm*-mi3xx` | Native |

`--image-tag dev` also publishes a timestamped sibling. Scheduled retention and manual tag behavior are documented in [Docker build](/ci/02-docker-build).

Expand Down
Loading