xiejiahao 80e59b67d3 Honour vllm flags appended after the image, highest priority
Previously any arguments after the image in docker run were silently
dropped: entrypoint.sh never forwarded "$@", so
  docker run ... <image> --served-model-name mymodel
started fine but kept serving as llm with no warning.

- entrypoint.sh: forward "$@"; skip script-generated flags the user
  already provided so vllm never sees duplicate keys; strip those keys
  from EXTRA_ARGS when the command line also sets them
- precedence: command line > EXTRA_ARGS > same-name -e > detected default
- warn when --port / --served-model-name is overridden, since the host
  -p side and the client model field must change too
- README: document the three ways and their precedence
2026-10-28 14:46:32 +08:00

Llama 4 Scout / Maverick on Iluvatar BI-V150

在 16×Iluvatar BI-V150 32GB 上运行 Llama 4 Scout 与 Maverick 的统一 Docker 部署仓库。

本仓库合并自原先独立的 llama4-scout-deploy 和 llama4-maverick-deploy, 用一个镜像 + 自动模型检测替代两套重复的 Dockerfile 和手动 profile。

  • 基础镜像:registry.iluvatar.com.cn:10443/customer/sz/vllm0.17.0-4.4.0-x86:v7(vLLM 0.17.0+corex)
  • 一个镜像同时支持 Scout 和 Maverick;模型权重不打进镜像,运行时只读挂载
  • 两个模型共用 Llama 4 chunked-attention 补丁;Maverick 额外使用 FP8 量化 / FP8 MoE 补丁
  • CI 使用 ModelHub 标准 Gitea Actions:推送 v* 标签后构建、推送镜像并提交审核
模型 精度 自动选择 GPU 数 容器内端口
Llama-4-Scout-17B-16E-Instruct BF16 TP8 / PP1 8 80
Llama-4-Maverick-17B-128E-Instruct-FP8 FP8 TP8 / PP2 16 80

容器内固定监听 80,模型名固定 llm,宿主机端口由 -p 决定(默认 24396)。


1. 目录内容

llama4-bi150-deploy/
├── Dockerfile
├── entrypoint.sh
├── apply_patch.py              # 幂等应用全部 Llama 4 补丁
├── detect_model.py             # 从 config.json 判断 Scout / Maverick
├── verify.sh                   # 服务验证脚本
├── patches/
│   ├── 01_fp8_quant.patch      # Maverick FP8 量化
│   ├── 02_fp8_moe.patch        # Maverick FP8 MoE
│   ├── 03_llama4_chunked_attn.patch
│   └── corexx_fp8_moe.py       # 逐 expert 反量化 BF16 的 FP8 MoE 回退
├── run.sh                      # 自动识别模型 + 构建 + 启动 + 等 /health
├── docker-compose.yml          # 可选
├── .gitea/workflows/
│   ├── docker-build-push.yml
│   └── task_info.env
└── README.md

BI-150 上代码放在:

/root/xjh/llama4-bi150-deploy

该路径是 ugly_hopper 容器内的 /root/xjh,直通宿主机。


2. 快速开始

不需要传 scout / maverick 参数,run.sh 会读取模型目录里的 config.json 自动判断。

cd /root/xjh/llama4-bi150-deploy

# Scout
./run.sh /mnt/disk0/models/LLM-Research/Llama-4-Scout-17B-16E-Instruct

# Maverick
./run.sh /mnt/disk0/models/LLM-Research/Llama-4-Maverick-17B-128E-Instruct-FP8

# 也可以用环境变量
MODEL_HOST_DIR=/mnt/disk0/models/LLM-Research/Llama-4-Maverick-17B-128E-Instruct-FP8 ./run.sh

# 不传参数时,依次尝试两个默认模型目录
./run.sh

启动后会打印检测结果,例如:

==> detected maverick: Llama 4 Maverick 17B-128E Instruct FP8 (TP8+PP2, 16 GPUs)
    model : /mnt/disk0/models/LLM-Research/Llama-4-Maverick-17B-128E-Instruct-FP8
    TP/PP : 8/2 (16 GPUs)
    port  : 127.0.0.1:24396 -> container:80
    name  : llm
    GPUs  : 0,1,2,...,15

镜像本身不设置 ENTRYPOINT / CMD / ENV / WORKDIR / EXPOSE, 启动方式、模型路径、端口、TP/PP、GPU 和挂载全部由 run.sh 或 docker-compose.yml 传入。 如果直接 docker run,需要显式指定: --entrypoint /usr/local/bin/llama4-entrypoint.sh --workdir /opt/llama4。

2.1 自动检测规则

detect_model.py 读取 config.json:

  • model_type 必须是 llama4;
  • text_config.num_local_experts == 16 → Scout,TP8 / PP1;
  • text_config.num_local_experts == 128 → Maverick,TP8 / PP2;
  • 字段缺失时用目录名里的 scout / maverick 兜底;
  • 其他情况直接报错,不会用错误的 TP/PP 启动。

容器启动时 entrypoint.sh 也会再检测一次。也就是说:

  • 用 run.sh 启动:宿主侧先检测,决定 GPU 数、容器名、健康检查端口;
  • 直接 docker run 挂载模型:容器内也会自动检测,按对应 TP/PP 启动;
  • 显式设置的 TP / PP / SERVED_NAME 会覆盖自动检测;
  • 设置 AUTO_DETECT=0 可关闭容器内检测。

端口和模型名不再由检测决定:容器内端口恒为 80,模型名恒为 llm。 检测出的 port / served_name 只作为日志提示(hint 行)。

2.2 指定 GPU

默认使用前 TP*PP 张卡:Scout 用 0-7,Maverick 用 0-15。可以覆盖:

# Scout 使用 8-15
GPUS=8,9,10,11,12,13,14,15 \
  ./run.sh /mnt/disk0/models/LLM-Research/Llama-4-Scout-17B-16E-Instruct

# Maverick 使用 0-15(默认)
GPUS=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 \
  ./run.sh /mnt/disk0/models/LLM-Research/Llama-4-Maverick-17B-128E-Instruct-FP8

run.sh 会检查 GPU 数是否少于 TP*PP;少于时直接报错。

2.2.1 指定宿主机端口

容器内固定 80,宿主机端口默认 24396。串行部署时多个模型可以复用同一个端口:

# 默认用 24396
./run.sh /mnt/disk0/models/LLM-Research/Llama-4-Scout-17B-16E-Instruct

# 改端口
HOST_PORT=24397 ./run.sh /mnt/disk0/models/LLM-Research/Llama-4-Scout-17B-16E-Instruct

并行跑多个模型时必须给不同的 HOST_PORT,否则第二个容器 bind: address already in use。 不过 Maverick 占满 16 卡,实际和 Scout 无法并存。

2.3 额外挂载 / 额外 vLLM 参数

EXTRA_DOCKER_ARGS="-v /mnt/disk1:/data:ro" ./run.sh /path/to/model
EXTRA_ARGS="--max-model-len 8192" ./run.sh /path/to/model

# 已有镜像,不重新构建(把 <ci-image> 换成第 5.1 节的实际地址)
BUILD=0 IMAGE=<ci-image> ./run.sh /path/to/model

# 只打印 docker run 命令
DRY_RUN=1 ./run.sh /path/to/model

2.4 Docker Compose(可选)

Compose 使用单个 llama4 service,同样由 entrypoint 自动检测模型:

# Scout
MODEL_HOST_DIR=/mnt/disk0/models/LLM-Research/Llama-4-Scout-17B-16E-Instruct \
  docker compose up -d --build

# Maverick
MODEL_HOST_DIR=/mnt/disk0/models/LLM-Research/Llama-4-Maverick-17B-128E-Instruct-FP8 \
  docker compose up -d --build

# 指定 GPU / 端口 / 额外参数
MODEL_HOST_DIR=/mnt/disk0/models/... \
GPUS=8,9,10,11,12,13,14,15 HOST_PORT=24397 \
  docker compose up -d --build

3. 可配置项

变量 默认 说明
MODEL_HOST_DIR 自动尝试两个默认目录 宿主机模型目录
MODEL_MOUNT /models/llama4 容器内挂载点
IMAGE llama4-bi150:2026-10-26 镜像名
NAME llama4-<kind> 容器名
HOST_PORT 24396 宿主机端口(容器内固定 80)
PORT 24396 HOST_PORT 的兼容别名,推荐用 HOST_PORT
SERVED_NAME llm OpenAI API 模型名,固定
TP Scout 8 / Maverick 8 张量并行
PP Scout 1 / Maverick 2 流水线并行
GPUS 前 TP*PP 张卡 CUDA_VISIBLE_DEVICES
MAX_MODEL_LEN 4096 最大上下文
MAX_NUM_SEQS 1 最大并发
GPU_MEM_UTIL 0.90 显存利用率
ENFORCE_EAGER 1 是否 --enforce-eager
AUTO_DETECT 1 容器内是否按 config 自动检测
EXTRA_ARGS 空 额外 vLLM 参数
EXTRA_DOCKER_ARGS 空 额外 docker 参数,如 -v
BUILD 1 0 表示跳过构建
DRY_RUN 0 1 只打印命令

TP / PP / SERVED_NAME 显式设置时优先于自动检测。


4. 验证脚本

verify.sh 用于检查已经启动的服务:

./verify.sh

它会自动查找运行中的 llama4-bi150 容器,读取模型挂载、端口和 served name,然后检查:

  1. /health
  2. /v1/models
  3. /v1/chat/completions(中文问答)

常用用法:

# 指定模型目录(推荐,能准确判断 Scout/Maverick)
./verify.sh --model-dir /mnt/disk0/models/LLM-Research/Llama-4-Maverick-17B-128E-Instruct-FP8

# 指定容器
./verify.sh --container llama4-maverick

# 额外检查图片识别(Maverick)
./verify.sh --container llama4-maverick --with-image

# 额外检查简单推理(期望回答 27)
./verify.sh --container llama4-scout --with-reasoning

# 直接指定服务地址
./verify.sh --base-url http://127.0.0.1:24396 --served-name llm

主要参数:

参数 说明
--model-dir PATH 模型目录,用于自动判断 Scout/Maverick
--container NAME 容器名;默认自动查找
--port PORT 宿主机端口;默认从容器端口映射推断,兜底 24396
--served-name NAME API 模型名;默认从模型/容器推断
--base-url URL 直接指定服务地址
--timeout SEC 等待/请求超时,默认 180
--with-reasoning 额外跑推理题
--with-image 额外跑图片识别(仅 Maverick)
--skip-chat 只检查 health 和 models

脚本只依赖 bash、curl、python3;不需要 jq。返回码为 0 表示全部通过。

在 ugly_hopper 内运行、没有 docker CLI 时,verify.sh 会先探测 24396,再依次探测旧的 8091 / 8092;也可以用 --model-dir 或 --port 显式指定。

也可以直接查看模型检测结果:

python3 detect_model.py /mnt/disk0/models/LLM-Research/Llama-4-Maverick-17B-128E-Instruct-FP8 --json

5. CI / ModelHub 发布

仓库已包含 ModelHub 标准 CI:

.gitea/workflows/docker-build-push.yml
.gitea/workflows/task_info.env

触发方式:

git tag v0.1.3
git push origin v0.1.3

已发布:v0.1.0(取消)、v0.1.1(取消)、v0.1.2(run #3 成功)。

CI 会:

  1. 在 amd64-ubuntu-24.04 runner 上 clone 仓库;
  2. 校验 task_info.env;
  3. docker build;
  4. 推送 ${DOCKER_REGISTRY}/${DOCKER_USERNAME}/llama-4-bi150:<tag>;
  5. 调 ModelHub image-verify 接口提交审核。

5.1 已发布的 CI 镜像

标签 Digest 压缩大小 推送时间
v0.1.2 sha256:42dc1d3fe60ca9d311b4ceb3dc9d0d4eef3ff5cdad560e63635fe75c6121602f 10.39 GiB 2026-10-26 12:04 UTC
harbor.4pd.io/modelhubxc/xiejiahao/llama-4-bi150:v0.1.2

拉取(需要 Harbor 凭据 DOCKER_USERNAME / DOCKER_PASSWORD):

docker login harbor.4pd.io -u modelhubxc
docker pull harbor.4pd.io/modelhubxc/xiejiahao/llama-4-bi150:v0.1.2

5.2 用 CI 镜像启动服务

镜像不声明 ENTRYPOINT,--entrypoint 必须显式给。以下命令可直接粘贴。

Llama-4-Scout-17B-16E(TP8/PP1,8 卡,宿主 24396 → 容器 80)

docker run -d --name llama4-scout \
  --entrypoint /usr/local/bin/llama4-entrypoint.sh \
  --workdir /opt/llama4 \
  --privileged --pid host --ipc host \
  -v /dev:/dev \
  -v /mnt/disk0/models/LLM-Research/Llama-4-Scout-17B-16E-Instruct:/models/llama4:ro \
  --ulimit memlock=-1 --ulimit stack=67108864 \
  -p 24396:80 \
  -e CUDA_VISIBLE_DEVICES=8,9,10,11,12,13,14,15 \
  -e MODEL_PATH=/models/llama4 \
  -e PORT=80 \
  -e SERVED_NAME=llm \
  -e AUTO_DETECT=1 \
  -e PYTHONUNBUFFERED=1 \
  --restart unless-stopped \
  harbor.4pd.io/modelhubxc/xiejiahao/llama-4-bi150:v0.1.2

Llama-4-Maverick-17B-128E-Instruct-FP8(TP8/PP2,16 卡,宿主 24396 → 容器 80)

docker run -d --name llama4-maverick \
  --entrypoint /usr/local/bin/llama4-entrypoint.sh \
  --workdir /opt/llama4 \
  --privileged --pid host --ipc host \
  -v /dev:/dev \
  -v /mnt/disk0/models/LLM-Research/Llama-4-Maverick-17B-128E-Instruct-FP8:/models/llama4:ro \
  --ulimit memlock=-1 --ulimit stack=67108864 \
  -p 24396:80 \
  -e CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 \
  -e MODEL_PATH=/models/llama4 \
  -e PORT=80 \
  -e SERVED_NAME=llm \
  -e AUTO_DETECT=1 \
  -e PYTHONUNBUFFERED=1 \
  --restart unless-stopped \
  harbor.4pd.io/modelhubxc/xiejiahao/llama-4-bi150:v0.1.2

两个变体共用挂载点 /models/llama4,靠 config.json 的 num_local_experts 区分;TP/PP、端口、served name 不用传,入口脚本会自动判定(见 2.1 节)。

Maverick 占用全部 16 张卡,与其它模型互斥;Scout 只占 8 张,可以和其它小模型共存,此时需改 -e CUDA_VISIBLE_DEVICES 避免重叠。

注意:两个变体都映射到宿主 24396,串行部署没问题;并行时必须改 -p 左侧端口。 -e SERVED_NAME=llm 让 /v1/models 返回 llm,客户端不用为换模型改 model 字段。

5.2.1 覆盖参数:三种写法,优先级从高到低

优先级 写法 例子
1 在镜像后面直接跟 vllm 参数 ... llama-4-bi150:v0.1.2 --served-model-name mymodel
2 -e EXTRA_ARGS="..." -e EXTRA_ARGS="--max-model-len 8192"
3 同名 -e -e MAX_MODEL_LEN=8192 -e SERVED_NAME=mymodel
4 默认值 / config.json 检测 什么都不传

三种写法都能生效,不会重复传参。覆盖 --port / --served-model-name 时会打印 WARN, 因为宿主机 -p 右侧端口和客户端 model 字段也要同步改。

# 镜像后直接跟参数
docker run -d --name llama4-scout \
  --entrypoint /usr/local/bin/llama4-entrypoint.sh --workdir /opt/llama4 \
  --privileged --pid host --ipc host -v /dev:/dev \
  -v /mnt/disk0/models/LLM-Research/Llama-4-Scout-17B-16E-Instruct:/models/llama4:ro \
  --ulimit memlock=-1 --ulimit stack=67108864 \
  -p 24396:80 \
  -e CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 -e MODEL_PATH=/models/llama4 -e AUTO_DETECT=1 \
  harbor.4pd.io/modelhubxc/xiejiahao/llama-4-bi150:v0.1.2 \
  --served-model-name mymodel --max-model-len 8192

5.3 用 run.sh 启动 CI 镜像

BUILD=0 IMAGE=harbor.4pd.io/modelhubxc/xiejiahao/llama-4-bi150:v0.1.2 \
  ./run.sh /mnt/disk0/models/LLM-Research/Llama-4-Scout-17B-16E-Instruct

./verify.sh --model-dir /mnt/disk0/models/LLM-Research/Llama-4-Scout-17B-16E-Instruct

task_info.env:

FRAMEWORK=vllm_llama_4
GPU_TYPE=Iluvatar_bi-150
TASK_TYPE=text-generation

Maverick 支持图片输入;如果 ModelHub 要求把图文任务单独归类,请把 TASK_TYPE 改成平台支持的值。image-verify/validate 会在构建前校验,填错会直接失败。

Runner 需要在 Gitea 实例或仓库中注册,并带有 amd64-ubuntu-24.04 label。Runner 需要配置以下环境变量(不是仓库 secret):

DOCKER_REGISTRY
DOCKER_USERNAME
DOCKER_PASSWORD
FIXED_TOKEN

注意事项:

  • 推送代码不会自动构建;需要手动推送 v* 标签才会触发。
  • Runner 必须能拉取 registry.iluvatar.com.cn:10443 的基础镜像;如果该仓库需要登录,请在 runner 上预登录,或自行给 workflow 增加基础镜像 registry 的 login step。
  • CI 只负责构建和推送,不负责 GPU / 模型挂载;GPU 和挂载通过 run.sh 或 docker compose 设置。
  • CI 构建机不需要 GPU,但需要足够的磁盘空间。
  • 如果仓库改名,CI 生成的镜像名会跟着变。

6. 限制与注意事项

  • Scout 需要 8 张卡(TP8);Maverick 需要 16 张卡(TP8+PP2)。16 卡机器上两者不能同时运行。
  • 当前默认 MAX_MODEL_LEN=4096、MAX_NUM_SEQS=1,适合功能验证;生产并发需要先调整显存/上下文。
  • 补丁是针对当前精确基础镜像生成的。更换基础镜像后不要直接复用,需要重新生成 diff 并在目标环境验证。
  • --privileged --pid host -v /dev:/dev 是 Iluvatar 运行时要求;只给 /dev/iluvatar* 可能报 cudaGetDeviceCount() ... Error 1001。
  • 模型目录只读挂载,容器不会修改宿主机模型文件。
  • 统一镜像首次使用时,建议 Scout 和 Maverick 都各跑一次 verify.sh;尤其是 Scout,因为镜像里也包含 FP8 MoE 补丁,需要确认共享的 fused_moe.py 修改没有影响 BF16 路径。

7. 变更记录

日期 变更
2026-10-26 CI v0.1.2 发布成功(digest 42dc1d3f…,10.39 GiB)
2026-10-28 补录 CI 镜像 digest 与 Scout / Maverick 的完整 docker run 命令(§5.1–5.3);修正 README 中的示例镜像地址和标签
Description
Llama 4 Scout / Maverick unified Docker deployment on Iluvatar BI-V150
Readme 136 KiB
Languages
Shell 64.3%
Python 31.3%
Dockerfile 4.4%