|
| 1 | +# syntax=docker/dockerfile:1.7 |
| 2 | + |
| 3 | +# ─── Stage 1: builder ─────────────────────────────────────────────────────── |
| 4 | +# ROCm/HIP sibling of the CUDA Dockerfile. ROCM_VERSION / UBUNTU_VERSION / |
| 5 | +# DFLASH_HIP_ARCHES are build args so the same Dockerfile can be repinned. |
| 6 | +# • lucebox-hub:rocm — ROCm 6.4.x, gfx1151 (+ optional fat gfx list) |
| 7 | +# See docker-bake.hcl for the canonical invocation. |
| 8 | +# |
| 9 | +# NOTE: gfx1151 (Strix Halo / Ryzen AI MAX) needs ROCm >= 6.4.1. The default |
| 10 | +# stays on 6.4.1 because the 7.2.x stack has shown intermittent problems on |
| 11 | +# Strix Halo. The flip side: against a ROCm 7.x HOST driver the 6.4.x |
| 12 | +# userspace can segfault at model load (seen on gfx1151 + host ROCm 7.2.2: |
| 13 | +# SIGSEGV in backend creation, bogus 1.28 TB VRAM report) — in that case |
| 14 | +# rebuild with ROCM_VERSION=7.2.2 to match the host. Rule of thumb: keep the |
| 15 | +# base's major version aligned with the host driver. |
| 16 | +ARG ROCM_VERSION=6.4.1 |
| 17 | +ARG UBUNTU_VERSION=22.04 |
| 18 | +FROM rocm/dev-ubuntu-${UBUNTU_VERSION}:${ROCM_VERSION} AS builder |
| 19 | + |
| 20 | +ARG DEBIAN_FRONTEND=noninteractive |
| 21 | + |
| 22 | +# Fat-binary HIP arch list, semicolon-separated. Each gfx target adds build |
| 23 | +# time + kernel code the same way CUDA arches do, so narrow this to your host |
| 24 | +# for fast local builds: DFLASH_HIP_ARCHES=gfx1151 docker buildx bake rocm-local |
| 25 | +# dflash-supported gfx targets (all have the sm_75+ equivalent features dflash |
| 26 | +# assumes; pre-RDNA/CDNA1 parts are excluded): |
| 27 | +# gfx1151 Strix Halo / Ryzen AI MAX+ 395 (the lucebox appliance iGPU) |
| 28 | +# gfx1100 RDNA3 RX 7900 XTX / W7900 |
| 29 | +# gfx1200 RDNA4 RX 9070 |
| 30 | +# gfx942 CDNA3 MI300X / MI300A |
| 31 | +# gfx90a CDNA2 MI200 / MI250 |
| 32 | +ARG DFLASH_HIP_ARCHES="gfx1151" |
| 33 | + |
| 34 | +# ROCm toolchain on PATH (hipcc + amdclang). The rocm/dev-ubuntu base installs |
| 35 | +# ROCm at /opt/rocm; ROCM_PATH lets server/CMakeLists.txt resolve the HIP rpath |
| 36 | +# and rocwmma header roots (server/CMakeLists.txt:33-41). |
| 37 | +ENV ROCM_PATH=/opt/rocm |
| 38 | +ENV PATH=/opt/rocm/bin:/opt/rocm/lib/llvm/bin:${PATH} |
| 39 | + |
| 40 | +# Unlike the CUDA image there is NO driver-stub symlink step: the ROCm base |
| 41 | +# ships the real HIP runtime libs (libamdhip64.so etc.) and the host kernel |
| 42 | +# driver (/dev/kfd, /dev/dri) is wired in at run time via --device. |
| 43 | +# hipblas/rocblas: ggml's HIP backend hard-requires them |
| 44 | +# (deps/llama.cpp/ggml/src/ggml-hip/CMakeLists.txt does find_package(hipblas) |
| 45 | +# for its BLAS matmul path). The rocm/dev-ubuntu base ships the HIP toolchain |
| 46 | +# but NOT the math libs, so they are installed explicitly from the ROCm apt |
| 47 | +# repo the base image already configures. |
| 48 | +RUN apt-get update && apt-get install -y --no-install-recommends \ |
| 49 | + build-essential \ |
| 50 | + ca-certificates \ |
| 51 | + cmake \ |
| 52 | + curl \ |
| 53 | + git \ |
| 54 | + git-lfs \ |
| 55 | + hipblas-dev \ |
| 56 | + libcurl4-openssl-dev \ |
| 57 | + ninja-build \ |
| 58 | + pkg-config \ |
| 59 | + python3 \ |
| 60 | + rocblas-dev \ |
| 61 | + && rm -rf /var/lib/apt/lists/* |
| 62 | + |
| 63 | +WORKDIR /src |
| 64 | + |
| 65 | +# COPY ordering mirrors the CUDA Dockerfile: C++ build inputs first so the |
| 66 | +# (slow) HIP build layer stays cached across Python-only edits. |
| 67 | +COPY server/CMakeLists.txt /src/server/CMakeLists.txt |
| 68 | +COPY server/include /src/server/include |
| 69 | +COPY server/src /src/server/src |
| 70 | +COPY server/test /src/server/test |
| 71 | +COPY server/hip_compat /src/server/hip_compat |
| 72 | +COPY server/deps /src/server/deps |
| 73 | +# status.html: dflash_server's POST_BUILD copies server/share/status.html into |
| 74 | +# build/share/. Without this COPY the build links then dies on the missing file. |
| 75 | +COPY server/share /src/server/share |
| 76 | + |
| 77 | +# Submodules must be populated on the host before `docker build` (.git/ is |
| 78 | +# .dockerignore'd so they cannot be fetched inside the image). |
| 79 | +RUN test -f /src/server/deps/llama.cpp/ggml/CMakeLists.txt \ |
| 80 | + || (echo "ERROR: server/deps/llama.cpp submodule not initialised. Run on host:" >&2 \ |
| 81 | + && echo " git submodule update --init --recursive" >&2 \ |
| 82 | + && exit 1) |
| 83 | + |
| 84 | +# Configure + build for HIP. DFLASH27B_GPU_BACKEND=hip selects the ggml-hip |
| 85 | +# backend (server/CMakeLists.txt:70-78); DFLASH27B_HIP_ARCHITECTURES pins the |
| 86 | +# gfx list. Block-Sparse-Attention is a CUDA-only kernel set, so BSA is OFF for |
| 87 | +# HIP; FA_ALL_QUANTS OFF keeps the fattn build tractable (matches the lucebox |
| 88 | +# native HIP build). CMAKE_BUILD_WITH_INSTALL_RPATH bakes the $ORIGIN-relative |
| 89 | +# rpath (incl. ggml-hip + ROCm lib) so the binaries find their .so files after |
| 90 | +# the COPY into the runtime stage. |
| 91 | +RUN cmake -S /src/server -B /src/server/build \ |
| 92 | + -G Ninja \ |
| 93 | + -DCMAKE_BUILD_TYPE=Release \ |
| 94 | + -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \ |
| 95 | + -DDFLASH27B_GPU_BACKEND=hip \ |
| 96 | + -DDFLASH27B_HIP_ARCHITECTURES="${DFLASH_HIP_ARCHES}" \ |
| 97 | + -DDFLASH27B_FA_ALL_QUANTS=OFF \ |
| 98 | + -DDFLASH27B_ENABLE_BSA=OFF \ |
| 99 | + && cmake --build /src/server/build --target test_dflash dflash_server test_server_unit --parallel |
| 100 | + |
| 101 | +# Prune the build tree to only what the runtime stage needs: the native server, |
| 102 | +# test_dflash, test_server_unit, and the ggml shared libs their embedded rpath |
| 103 | +# ($ORIGIN/deps/...) looks up. |
| 104 | +RUN cd /src/server/build \ |
| 105 | + && find . -mindepth 1 -maxdepth 1 \ |
| 106 | + ! -name test_dflash ! -name dflash_server ! -name test_server_unit ! -name deps -exec rm -rf {} + \ |
| 107 | + && find deps -mindepth 1 -type f ! -name 'lib*.so*' -delete \ |
| 108 | + && find deps -depth -type d -empty -delete |
| 109 | + |
| 110 | +# Python sources, workspace manifests, lockfile, READMEs (same as CUDA stage). |
| 111 | +COPY pyproject.toml uv.lock README.md /src/ |
| 112 | +COPY server/pyproject.toml server/README.md /src/server/ |
| 113 | +COPY server/scripts /src/server/scripts |
| 114 | +COPY optimizations/pflash /src/optimizations/pflash |
| 115 | +COPY optimizations/megakernel /src/optimizations/megakernel |
| 116 | + |
| 117 | +# ─── Stage 2: runtime ─────────────────────────────────────────────────────── |
| 118 | +# Runtime reuses the ROCm base so the HIP runtime libs (libamdhip64, |
| 119 | +# libhsa-runtime64, librocm-core, …) the binaries link against are present and |
| 120 | +# version-matched to the builder. This makes a larger image than a minimal |
| 121 | +# runtime would; slimming to `ubuntu:${UBUNTU_VERSION}` + the AMD repo's |
| 122 | +# `rocm-language-runtime` meta-package is a follow-up optimisation (the build |
| 123 | +# stage is unaffected, so it can be done independently). |
| 124 | +FROM rocm/dev-ubuntu-${UBUNTU_VERSION}:${ROCM_VERSION} AS runtime |
| 125 | + |
| 126 | +ARG DEBIAN_FRONTEND=noninteractive |
| 127 | + |
| 128 | +# Image identity baked in for /props.build (git_sha / image_tag / build_time), |
| 129 | +# wired from docker-bake.hcl. Empty in non-bake builds → JSON null at /props. |
| 130 | +ARG GIT_SHA="" |
| 131 | +ARG IMAGE_TAG="" |
| 132 | +ARG BUILD_TIME="" |
| 133 | + |
| 134 | +ENV ROCM_PATH=/opt/rocm |
| 135 | +ENV PATH=/opt/rocm/bin:${PATH} |
| 136 | + |
| 137 | +# hipblas/rocblas runtime libs: the dflash binaries link ggml-hip against |
| 138 | +# them (see builder stage). Their .so files must be present at runtime for |
| 139 | +# the server to load. |
| 140 | +RUN apt-get update && apt-get install -y --no-install-recommends \ |
| 141 | + ca-certificates \ |
| 142 | + curl \ |
| 143 | + hipblas \ |
| 144 | + libgomp1 \ |
| 145 | + pciutils \ |
| 146 | + rocblas \ |
| 147 | + && rm -rf /var/lib/apt/lists/* |
| 148 | + |
| 149 | +# uv (pinned) manages Python 3.12 + resolves the lucebox-dflash + pflash |
| 150 | +# workspace. Copied from the official image rather than `curl | sh`, so the |
| 151 | +# version is fixed and no remote installer script runs at build time. |
| 152 | +COPY --from=ghcr.io/astral-sh/uv:0.11.2 /uv /uvx /usr/local/bin/ |
| 153 | + |
| 154 | +ENV UV_PYTHON_INSTALL_DIR=/opt/uv/python \ |
| 155 | + UV_TOOL_DIR=/opt/uv/tools |
| 156 | + |
| 157 | +WORKDIR /opt/lucebox-hub |
| 158 | + |
| 159 | +COPY --from=builder /src/pyproject.toml /src/uv.lock /src/README.md /opt/lucebox-hub/ |
| 160 | +COPY --from=builder /src/optimizations/pflash /opt/lucebox-hub/optimizations/pflash |
| 161 | +COPY --from=builder /src/optimizations/megakernel/pyproject.toml \ |
| 162 | + /src/optimizations/megakernel/README.md \ |
| 163 | + /opt/lucebox-hub/optimizations/megakernel/ |
| 164 | + |
| 165 | +COPY --from=builder /src/server/scripts /opt/lucebox-hub/server/scripts |
| 166 | +COPY --from=builder /src/server/pyproject.toml /src/server/README.md \ |
| 167 | + /opt/lucebox-hub/server/ |
| 168 | +COPY --from=builder /src/server/build /opt/lucebox-hub/server/build |
| 169 | + |
| 170 | +COPY share/model_cards /opt/lucebox-hub/share/model_cards |
| 171 | +RUN mkdir -p /opt/lucebox-hub/server/share \ |
| 172 | + && ln -s /opt/lucebox-hub/share/model_cards \ |
| 173 | + /opt/lucebox-hub/server/share/model_cards |
| 174 | + |
| 175 | +RUN test -x /opt/lucebox-hub/server/build/test_dflash \ |
| 176 | + && test -x /opt/lucebox-hub/server/build/dflash_server \ |
| 177 | + && test -x /opt/lucebox-hub/server/build/test_server_unit \ |
| 178 | + && test -f /opt/lucebox-hub/server/share/model_cards/qwen3.6-27b.json \ |
| 179 | + && chmod +x /opt/lucebox-hub/server/scripts/entrypoint.sh |
| 180 | + |
| 181 | +RUN printf '%s\n%s\n%s\n' "$GIT_SHA" "$IMAGE_TAG" "$BUILD_TIME" \ |
| 182 | + > /opt/lucebox-hub/IMAGE_INFO |
| 183 | + |
| 184 | +# Register the ggml lib dirs with ld.so. HIP names its backend lib dir |
| 185 | +# `ggml-hip` (server/CMakeLists.txt:74), where the CUDA image uses `ggml-cuda`. |
| 186 | +RUN printf '%s\n%s\n' \ |
| 187 | + /opt/lucebox-hub/server/build/deps/llama.cpp/ggml/src \ |
| 188 | + /opt/lucebox-hub/server/build/deps/llama.cpp/ggml/src/ggml-hip \ |
| 189 | + > /etc/ld.so.conf.d/lucebox-ggml.conf \ |
| 190 | + && ldconfig |
| 191 | + |
| 192 | +ENV UV_LINK_MODE=hardlink \ |
| 193 | + UV_NO_CACHE=1 |
| 194 | +RUN uv sync --no-dev --frozen --no-editable 2>/dev/null \ |
| 195 | + || uv sync --no-dev --frozen --no-editable |
| 196 | + |
| 197 | +RUN chmod -R a+rX /opt/lucebox-hub/.venv /opt/lucebox-hub /opt/uv |
| 198 | + |
| 199 | +# Models live in server/models/ — bind-mount or volume them in. |
| 200 | +# ROCm run example (note: AMD uses --device, not --gpus): |
| 201 | +# docker run --rm --device /dev/kfd --device /dev/dri \ |
| 202 | +# --group-add video --group-add render \ |
| 203 | +# --security-opt seccomp=unconfined -p 8080:8080 \ |
| 204 | +# -v "$PWD/server/models:/opt/lucebox-hub/server/models" \ |
| 205 | +# ghcr.io/luce-org/lucebox-hub:rocm |
| 206 | +VOLUME ["/opt/lucebox-hub/server/models"] |
| 207 | + |
| 208 | +ENV DFLASH_HOST=0.0.0.0 \ |
| 209 | + DFLASH_PORT=8080 \ |
| 210 | + DFLASH_BIN=/opt/lucebox-hub/server/build/test_dflash \ |
| 211 | + DFLASH_SERVER_BIN=/opt/lucebox-hub/server/build/dflash_server |
| 212 | + |
| 213 | +EXPOSE 8080 |
| 214 | + |
| 215 | +ENTRYPOINT ["/opt/lucebox-hub/server/scripts/entrypoint.sh"] |
0 commit comments