2026-10-27 14:19:51 +08:00
|
|
|
|
# gemma4-bi150 — Gemma 4 家族统一部署(Iluvatar BI-V150)
|
|
|
|
|
|
|
|
|
|
|
|
一个镜像同时支持两个 Gemma 4 家族模型,启动时读模型 `config.json` 自动选择运行参数:
|
|
|
|
|
|
|
2026-10-28 14:19:42 +08:00
|
|
|
|
| 模型 | 类型 | 权重 | TP | 卡数 | eager | 显存 | seqs |
|
|
|
|
|
|
|---|---|---:|---:|---:|---:|---:|---:|
|
|
|
|
|
|
| `gemma-4-31B-it` | dense,60 层 | 58.25 GiB | **4** | 4 | 0 | 0.90 | 4 |
|
|
|
|
|
|
| `GEV-26B-Decide` | MoE,30 层 / 128 experts | 48.07 GiB | **2** | 2 | 1 | 0.95 | 2 |
|
|
|
|
|
|
|
|
|
|
|
|
两个变体共用:容器内端口 **80**、模型名 **`llm`**、宿主端口 **24396**(由 `-p` 决定)。
|
2026-10-27 14:19:51 +08:00
|
|
|
|
|
2026-10-28 11:47:19 +08:00
|
|
|
|
> 本仓库由原先各自独立的 `gemma4-31b-deploy` 和 `gev-26b-decide-deploy` 两套目录合并而来,
|
|
|
|
|
|
> 合并依据见文末「为什么可以合并」。
|
2026-10-27 14:19:51 +08:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 目录结构
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
gemma4-bi150-deploy/
|
|
|
|
|
|
├── Dockerfile # 只放基础镜像 + 补丁 + 脚本,不写 ENV/EXPOSE/ENTRYPOINT
|
|
|
|
|
|
├── entrypoint.sh # 容器入口:打补丁 → detect → exec vllm
|
|
|
|
|
|
├── detect_model.py # 从 config.json 判断 dense / MoE,并校验 TP 可行性
|
|
|
|
|
|
├── apply_patch.py # 幂等应用两个 CoreX vLLM 补丁
|
|
|
|
|
|
├── run.sh # 构建 + 启动 + 健康检查
|
|
|
|
|
|
├── verify.sh # health / models / chat / 可选推理 / 可选图片
|
|
|
|
|
|
├── docker-compose.yml
|
|
|
|
|
|
├── .dockerignore
|
|
|
|
|
|
├── .gitignore
|
|
|
|
|
|
├── .gitea/workflows/
|
|
|
|
|
|
│ ├── docker-build-push.yml
|
|
|
|
|
|
│ └── task_info.env
|
|
|
|
|
|
└── README.md
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 快速开始
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cd gemma4-bi150-deploy
|
|
|
|
|
|
|
|
|
|
|
|
# Gemma-4-31B(4 卡,默认用 15,14,13,12)
|
|
|
|
|
|
./run.sh /mnt/disk0/models/google/gemma-4-31B-it
|
|
|
|
|
|
|
|
|
|
|
|
# GEV-26B-Decide(2 卡,默认用 14,15)
|
|
|
|
|
|
./run.sh /mnt/disk0/models/autotrust/GEV-26B-Decide
|
|
|
|
|
|
|
|
|
|
|
|
# 验证
|
|
|
|
|
|
./verify.sh --model-dir /mnt/disk0/models/google/gemma-4-31B-it
|
|
|
|
|
|
./verify.sh --model-dir /mnt/disk0/models/autotrust/GEV-26B-Decide --with-image
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
模型类型不需要手写参数,`run.sh` 会调用 `detect_model.py` 读 `config.json` 判断。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1 不传模型目录
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
./run.sh
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
按顺序尝试:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
/mnt/disk0/models/google/gemma-4-31B-it
|
|
|
|
|
|
/mnt/disk0/models/autotrust/GEV-26B-Decide
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2.2 Compose
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
MODEL_HOST_DIR=/mnt/disk0/models/google/gemma-4-31B-it docker compose up -d --build
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Compose 里 TP / PORT / SERVED_NAME / MAX_NUM_SEQS / GPU_MEM_UTIL / ENFORCE_EAGER
|
|
|
|
|
|
都默认留空,由容器内 `entrypoint.sh` 检测后填充。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 自动识别逻辑
|
|
|
|
|
|
|
|
|
|
|
|
### 3.1 判断变体
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
arch = config["architectures"][0] # 必须以 Gemma4 开头
|
|
|
|
|
|
text = config.get("text_config", config)
|
|
|
|
|
|
experts = num_experts / num_local_experts / n_routed_experts
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
| 条件 | 变体 | 运行参数 |
|
|
|
|
|
|
|---|---|---|
|
2026-10-28 14:19:42 +08:00
|
|
|
|
| `experts > 1` | GEV-26B-Decide(MoE) | TP2 / eager1 / 0.95 / 2 seqs |
|
|
|
|
|
|
| `experts` 缺失或 `== 1` | Gemma-4-31B(dense) | TP4 / eager0 / 0.90 / 4 seqs |
|
2026-10-27 14:19:51 +08:00
|
|
|
|
| 无 experts 且目录名含 `gev` | GEV | 同上 |
|
|
|
|
|
|
| 无 experts 且目录名含 `gemma` | Gemma-4-31B | 同上 |
|
|
|
|
|
|
| 其它 / 架构不是 Gemma4 | 直接报错 | 不启动 |
|
|
|
|
|
|
|
|
|
|
|
|
`num_experts=1` 按 dense 处理,因为部分 dense 配置用 1 表示"没有专家"。
|
|
|
|
|
|
|
|
|
|
|
|
### 3.2 顺便校验 TP 可行性(这是合并后的额外收益)
|
|
|
|
|
|
|
|
|
|
|
|
两个变体都有硬性 TP 上限,`detect_model.py` 会拿 `config.json` 反查:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
dense: num_global_key_value_heads % TP == 0
|
|
|
|
|
|
Gemma-4-31B 的 4 个 global KV head,TP8 会切成 0.5 → 拒绝启动
|
|
|
|
|
|
MoE: (moe_intermediate_size / TP) % 32 == 0
|
|
|
|
|
|
CoreX ixfops.moe_w16a16_group_gemm 要求 k % 32 == 0
|
|
|
|
|
|
GEV 704/2=352 ✅,704/4=176 ❌
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
所以下面这些都会被提前拦住,而不是等 vLLM 跑到一半才崩:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
TP=8 ./run.sh .../gemma-4-31B-it # num_global_key_value_heads=4 % 8 != 0
|
|
|
|
|
|
TP=4 ./run.sh .../GEV-26B-Decide # 704/4=176,k % 32 != 0
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
确实需要强跑时用 `GEMMA4_SKIP_TP_CHECK=1` 降级为警告。
|
|
|
|
|
|
|
|
|
|
|
|
### 3.3 检测输出
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
$ python3 detect_model.py /mnt/disk0/models/autotrust/GEV-26B-Decide
|
|
|
|
|
|
DETECTED_MODEL_KIND=gev-26b-decide
|
|
|
|
|
|
DETECTED_TP=2
|
2026-10-28 14:19:42 +08:00
|
|
|
|
DETECTED_PORT=8094 # 仅提示,不决定实际端口
|
|
|
|
|
|
DETECTED_SERVED_NAME=GEV-26B-Decide # 仅提示,模型名固定 llm
|
2026-10-27 14:19:51 +08:00
|
|
|
|
DETECTED_GPU_COUNT=2
|
|
|
|
|
|
DETECTED_MAX_NUM_SEQS=2
|
|
|
|
|
|
DETECTED_GPU_MEM_UTIL=0.95
|
|
|
|
|
|
DETECTED_ENFORCE_EAGER=1
|
|
|
|
|
|
DETECTED_DESCRIPTION='AutoTrust GEV-26B-Decide MoE (BF16, TP2, 2 GPUs)'
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 detect_model.py <dir> --json # verify.sh 用
|
|
|
|
|
|
python3 detect_model.py <dir> --tp 4 # 按 TP4 校验可行性
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 覆盖启动参数
|
|
|
|
|
|
|
|
|
|
|
|
显式环境变量优先于检测结果。
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 换卡
|
|
|
|
|
|
GPUS=12,13,14,15 ./run.sh /mnt/disk0/models/google/gemma-4-31B-it
|
|
|
|
|
|
|
|
|
|
|
|
# 换端口和模型名
|
2026-10-28 14:19:42 +08:00
|
|
|
|
HOST_PORT=24397 ./run.sh /mnt/disk0/models/google/gemma-4-31B-it # 换宿主端口
|
2026-10-27 14:19:51 +08:00
|
|
|
|
|
|
|
|
|
|
# 加 vLLM 参数
|
|
|
|
|
|
EXTRA_ARGS="--max-model-len 16384" ./run.sh /mnt/disk0/models/google/gemma-4-31B-it
|
|
|
|
|
|
|
|
|
|
|
|
# 加 docker 参数
|
|
|
|
|
|
EXTRA_DOCKER_ARGS="-v /mnt/disk1:/data:ro" ./run.sh /mnt/disk0/models/google/gemma-4-31B-it
|
|
|
|
|
|
|
|
|
|
|
|
# 用已有镜像(CI 产物)不重新 build
|
|
|
|
|
|
BUILD=0 IMAGE=harbor.4pd.io/modelhubxc/xiejiahao/gemma4-bi150:v0.1.0 \
|
|
|
|
|
|
./run.sh /mnt/disk0/models/google/gemma-4-31B-it
|
|
|
|
|
|
|
|
|
|
|
|
# 只打印命令
|
|
|
|
|
|
DRY_RUN=1 ./run.sh /mnt/disk0/models/google/gemma-4-31B-it
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
常用环境变量:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
IMAGE NAME MODEL_HOST_DIR MODEL_MOUNT PORT SERVED_NAME TP GPUS
|
|
|
|
|
|
MAX_MODEL_LEN MAX_NUM_SEQS GPU_MEM_UTIL MAX_IMAGES ENFORCE_EAGER
|
|
|
|
|
|
AUTO_DETECT HEALTH_TIMEOUT EXTRA_ARGS EXTRA_DOCKER_ARGS BUILD DRY_RUN
|
|
|
|
|
|
GEMMA4_SKIP_TP_CHECK
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`AUTO_DETECT=0` 可关闭容器内检测,全部手动给值。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 为什么 Dockerfile 里没有 ENV / EXPOSE / ENTRYPOINT
|
|
|
|
|
|
|
|
|
|
|
|
镜像必须能同时服务 dense 和 MoE 两个变体,而这些参数在两个变体之间不同:
|
|
|
|
|
|
|
|
|
|
|
|
| 参数 | Gemma-4-31B | GEV-26B-Decide |
|
|
|
|
|
|
|---|---:|---:|
|
|
|
|
|
|
| TP | 4 | 2 |
|
|
|
|
|
|
| eager | 0 | 1 |
|
|
|
|
|
|
| 显存 | 0.90 | 0.95 |
|
|
|
|
|
|
| seqs | 4 | 2 |
|
|
|
|
|
|
|
|
|
|
|
|
写进镜像就只能二选一,或者做两个镜像,违背"一个家族一个镜像"的目标。
|
|
|
|
|
|
所以启动方式统一由 `run.sh` / `docker-compose.yml` 传入:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker run ... \
|
|
|
|
|
|
--entrypoint /usr/local/bin/gemma4-entrypoint.sh \
|
|
|
|
|
|
--workdir /opt/gemma4 \
|
2026-10-28 14:19:42 +08:00
|
|
|
|
-p 24396:80 \
|
2026-10-27 14:19:51 +08:00
|
|
|
|
-e MODEL_PATH=/models/gemma4 \
|
2026-10-28 14:19:42 +08:00
|
|
|
|
-e PORT=80 \
|
|
|
|
|
|
-e SERVED_NAME=llm \
|
2026-10-27 14:19:51 +08:00
|
|
|
|
-e AUTO_DETECT=1 \
|
|
|
|
|
|
<image>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 补丁
|
|
|
|
|
|
|
|
|
|
|
|
`apply_patch.py` 应用两个补丁,构建镜像时和容器启动时都会幂等执行一次。
|
|
|
|
|
|
|
|
|
|
|
|
| 补丁 | 目标文件 | 不打的后果 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| `MultiModalDataDict` 导入路径 | `vllm/model_executor/models/gemma4_mm.py` | `ImportError`,模型检查阶段就失败(**两个变体都需要**) |
|
|
|
|
|
|
| decode fast path 的 attention metadata 判断 | `vllm/model_executor/layers/fused_moe/fused_moe.py` | GEV 的 CUDA graph capture 报 `AttributeError: no attribute 'num_decodes'` |
|
|
|
|
|
|
|
|
|
|
|
|
第二个补丁对 dense 的 Gemma-4-31B 通常用不到,但保持幂等一起打,避免同一镜像换模型后失效。
|
|
|
|
|
|
|
|
|
|
|
|
补丁是针对这个精确基础镜像生成的,换镜像需要重新生成:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
registry.iluvatar.com.cn:10443/customer/sz/vllm0.17.0-4.4.0-x86:v7
|
|
|
|
|
|
vLLM 0.17.0+corex.20260612070235
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 7. 验证
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 自动找运行中的容器
|
|
|
|
|
|
./verify.sh
|
|
|
|
|
|
|
|
|
|
|
|
# 指定模型目录(推荐,能顺带校验变体)
|
|
|
|
|
|
./verify.sh --model-dir /mnt/disk0/models/google/gemma-4-31B-it
|
|
|
|
|
|
|
|
|
|
|
|
# 指定容器
|
|
|
|
|
|
./verify.sh --container gemma4-31b
|
|
|
|
|
|
|
|
|
|
|
|
# 额外图片识别
|
|
|
|
|
|
./verify.sh --model-dir /mnt/disk0/models/autotrust/GEV-26B-Decide --with-image
|
|
|
|
|
|
|
|
|
|
|
|
# 额外推理题(期望 27)
|
|
|
|
|
|
./verify.sh --model-dir /mnt/disk0/models/google/gemma-4-31B-it --with-reasoning
|
|
|
|
|
|
|
|
|
|
|
|
# 直接指定服务地址
|
2026-10-28 14:19:42 +08:00
|
|
|
|
./verify.sh --base-url http://127.0.0.1:24396 --served-name llm
|
2026-10-27 14:19:51 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
检查项:`/health`、`/v1/models`、`/v1/chat/completions`,可选推理题和图片识别。
|
|
|
|
|
|
只依赖 `bash`、`curl`、`python3`。全部通过返回 0。
|
|
|
|
|
|
|
|
|
|
|
|
> `/health` 只看 `curl` 退出码,不看 body——vLLM 会返回 200 但 body 为空。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 8. 关键参数的理由
|
|
|
|
|
|
|
|
|
|
|
|
### 8.1 Gemma-4-31B 为什么是 TP4
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
Gemma4ForConditionalGeneration
|
|
|
|
|
|
num_attention_heads = 32
|
|
|
|
|
|
num_key_value_heads = 16 # sliding attention
|
|
|
|
|
|
num_global_key_value_heads = 4 # full attention
|
|
|
|
|
|
head_dim / global_head_dim = 256 / 512
|
|
|
|
|
|
num_hidden_layers = 60
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`num_global_key_value_heads=4` 是最紧的约束:TP8 会切成 0.5,当前 vLLM 不支持。
|
|
|
|
|
|
TP4 下 4/4=1,权重 58.25 GiB / 4 ≈ 14.6 GiB/卡,实测加载后 15.89 GiB/卡。
|
|
|
|
|
|
|
|
|
|
|
|
### 8.2 GEV-26B-Decide 为什么是 TP2
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
Gemma4ForConditionalGeneration
|
|
|
|
|
|
hidden_size = 2816
|
|
|
|
|
|
num_hidden_layers = 30
|
|
|
|
|
|
num_attention_heads = 16
|
|
|
|
|
|
num_key_value_heads = 8
|
|
|
|
|
|
moe_intermediate_size = 704
|
|
|
|
|
|
num_experts = 128
|
|
|
|
|
|
top_k_experts = 8
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
CoreX `ixfops.moe_w16a16_group_gemm` 要求分组 GEMM 的 K 维能被 32 整除,
|
|
|
|
|
|
`704 / TP` 的结果:TP8→88 ❌、TP4→176 ❌、TP2→352 ✅。
|
|
|
|
|
|
TP1 显存不够,所以只有 TP2。
|
|
|
|
|
|
|
|
|
|
|
|
### 8.3 GEV 为什么开 `--enforce-eager`
|
|
|
|
|
|
|
|
|
|
|
|
MoE + CoreX 的 CUDA graph 路径不稳定,实测开 eager 才能稳定启动;
|
|
|
|
|
|
dense 的 Gemma-4-31B 不需要,关掉可以拿到更好的吞吐。
|
|
|
|
|
|
|
|
|
|
|
|
### 8.4 GEV 为什么用 0.95 显存
|
|
|
|
|
|
|
|
|
|
|
|
权重 48.07 GiB / 2 ≈ 24.99 GiB/卡,0.95 下 KV 约 4.9 GiB,适合低并发。
|
|
|
|
|
|
`max-num-seqs` 同时降到 2,避免 KV 被并发打爆。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 9. GPU 选择
|
|
|
|
|
|
|
|
|
|
|
|
`run.sh` 默认优先序号大的卡,避免和 16 卡大模型抢 0-11:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
Gemma-4-31B → 15,14,13,12
|
|
|
|
|
|
GEV-26B-Decide → 14,15
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
卡数不足会直接报错,卡数多余只警告(vLLM 只用前 TP 张):
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
GPUS=12,13 ./run.sh .../gemma-4-31B-it # 报错:需要 4 张
|
|
|
|
|
|
GPUS=0,1,2,3,4,5 ./run.sh .../GEV-26B-Decide # 警告:只用其中 2 张
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
查看空闲卡:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
/usr/local/corex/bin/ixsmi
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 10. 常见问题
|
|
|
|
|
|
|
|
|
|
|
|
| 现象 | 原因 | 处理 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| `ImportError: cannot import name 'MultiModalDataDict'` | 补丁没打上 | 确认 `apply_patch.py` 执行过 |
|
|
|
|
|
|
| `AttributeError: 'TritonAttentionMetadata' object has no attribute 'num_decodes'` | MoE 补丁没打上 | 同上 |
|
|
|
|
|
|
| `Expected k % 32 == 0 to be true` | GEV 用了 TP4/TP8 | 回到 TP2;`detect_model.py` 会提前拦住 |
|
|
|
|
|
|
| KV head 无法切分 / head 数不整除 | dense 用了 TP8 | 回到 TP4 |
|
|
|
|
|
|
| `cudaGetDeviceCount() ... Error 1001` | 少了 `--privileged -v /dev:/dev` | 用 `run.sh`,不要手写简化版 `docker run` |
|
|
|
|
|
|
| 启动 10 分钟还没 ready | 冷读 49–59 GB 权重 | 默认给 900s;`docker logs -f` 看 `Loading weights` |
|
|
|
|
|
|
| `/health` 超时但容器在跑 | 还在加载权重 | 以 `Loading weights took` 和 `/v1/models` 为准 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 11. CI 与发布
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 首次
|
|
|
|
|
|
git tag v0.1.0 && git push origin v0.1.0
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-10-28 13:34:58 +08:00
|
|
|
|
已发布:`v0.1.0`(CI run #1 成功)。
|
|
|
|
|
|
|
2026-10-27 14:19:51 +08:00
|
|
|
|
- 只有推送 `v*` 标签才触发;
|
|
|
|
|
|
- runner label:`amd64-ubuntu-24.04`,需要 `DOCKER_*` / `FIXED_TOKEN`;
|
|
|
|
|
|
- `task_info.env`:`FRAMEWORK=vllm_gemma_4`(必须独特,不要用泛化的 `vllm`);
|
|
|
|
|
|
- CI 被取消后**不要复用标签**,直接 bump patch;
|
2026-10-28 13:34:58 +08:00
|
|
|
|
- CI 构建 vLLM 基础镜像较久,首次推送约 1.5 小时量级;后续改动若层缓存命中会快很多(本次 71 秒)。
|
|
|
|
|
|
|
|
|
|
|
|
### 11.1 已发布的 CI 镜像
|
|
|
|
|
|
|
|
|
|
|
|
| 标签 | Digest | 压缩大小 | 推送时间 |
|
|
|
|
|
|
|---|---|---:|---|
|
|
|
|
|
|
| `v0.1.0` | `sha256:0f6eb25cc2a536529368ac32e0b622f5e4da84c90d63ccf036752c587e45c6c9` | 10.39 GiB | 2026-10-27 06:01 UTC |
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
harbor.4pd.io/modelhubxc/xiejiahao/gemma4-bi150:v0.1.0
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
拉取(需要 Harbor 凭据 `DOCKER_USERNAME` / `DOCKER_PASSWORD`):
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker login harbor.4pd.io -u modelhubxc
|
|
|
|
|
|
docker pull harbor.4pd.io/modelhubxc/xiejiahao/gemma4-bi150:v0.1.0
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
CI 的 `naming to` 行与本表 digest 一致,可作为复核依据。
|
|
|
|
|
|
|
|
|
|
|
|
### 11.2 用 CI 镜像启动服务
|
|
|
|
|
|
|
|
|
|
|
|
镜像不声明 `ENTRYPOINT`,`--entrypoint` 必须显式给。以下命令可直接粘贴。
|
|
|
|
|
|
|
2026-10-28 14:19:42 +08:00
|
|
|
|
**Gemma-4-31B-it(TP4,4 卡,宿主 24396 → 容器 80)**
|
2026-10-28 13:34:58 +08:00
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker run -d --name gemma4-31b \
|
|
|
|
|
|
--entrypoint /usr/local/bin/gemma4-entrypoint.sh \
|
|
|
|
|
|
--workdir /opt/gemma4 \
|
2026-10-28 14:19:42 +08:00
|
|
|
|
--privileged --pid host --ipc host \
|
2026-10-28 13:34:58 +08:00
|
|
|
|
-v /dev:/dev \
|
|
|
|
|
|
-v /mnt/disk0/models/google/gemma-4-31B-it:/models/gemma4:ro \
|
|
|
|
|
|
--ulimit memlock=-1 --ulimit stack=67108864 \
|
2026-10-28 14:19:42 +08:00
|
|
|
|
-p 24396:80 \
|
2026-10-28 13:34:58 +08:00
|
|
|
|
-e CUDA_VISIBLE_DEVICES=15,14,13,12 \
|
|
|
|
|
|
-e MODEL_PATH=/models/gemma4 \
|
2026-10-28 14:19:42 +08:00
|
|
|
|
-e PORT=80 \
|
|
|
|
|
|
-e SERVED_NAME=llm \
|
2026-10-28 13:34:58 +08:00
|
|
|
|
-e AUTO_DETECT=1 \
|
|
|
|
|
|
-e PYTHONUNBUFFERED=1 \
|
|
|
|
|
|
--restart unless-stopped \
|
|
|
|
|
|
harbor.4pd.io/modelhubxc/xiejiahao/gemma4-bi150:v0.1.0
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-10-28 14:19:42 +08:00
|
|
|
|
**GEV-26B-Decide(TP2,2 卡,宿主 24396 → 容器 80)**
|
2026-10-28 13:34:58 +08:00
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker run -d --name gev-26b-decide \
|
|
|
|
|
|
--entrypoint /usr/local/bin/gemma4-entrypoint.sh \
|
|
|
|
|
|
--workdir /opt/gemma4 \
|
2026-10-28 14:19:42 +08:00
|
|
|
|
--privileged --pid host --ipc host \
|
2026-10-28 13:34:58 +08:00
|
|
|
|
-v /dev:/dev \
|
|
|
|
|
|
-v /mnt/disk0/models/autotrust/GEV-26B-Decide:/models/gemma4:ro \
|
|
|
|
|
|
--ulimit memlock=-1 --ulimit stack=67108864 \
|
2026-10-28 14:19:42 +08:00
|
|
|
|
-p 24396:80 \
|
2026-10-28 13:34:58 +08:00
|
|
|
|
-e CUDA_VISIBLE_DEVICES=14,15 \
|
|
|
|
|
|
-e MODEL_PATH=/models/gemma4 \
|
2026-10-28 14:19:42 +08:00
|
|
|
|
-e PORT=80 \
|
|
|
|
|
|
-e SERVED_NAME=llm \
|
2026-10-28 13:34:58 +08:00
|
|
|
|
-e AUTO_DETECT=1 \
|
|
|
|
|
|
-e PYTHONUNBUFFERED=1 \
|
|
|
|
|
|
--restart unless-stopped \
|
|
|
|
|
|
harbor.4pd.io/modelhubxc/xiejiahao/gemma4-bi150:v0.1.0
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-10-28 14:19:42 +08:00
|
|
|
|
两个变体共用挂载点 `/models/gemma4`,靠 `config.json` 区分;TP / eager / 显存 / 并发数都不用传,入口脚本会自动判定(见第 3 节)。
|
2026-10-28 13:34:58 +08:00
|
|
|
|
|
2026-10-28 14:19:42 +08:00
|
|
|
|
容器内端口恒为 80、模型名恒为 `llm`,所以两个变体可以复用同一个宿主端口 24396,串行切换时客户端不用改地址也不用改 `model` 字段。
|
2026-10-28 14:46:32 +08:00
|
|
|
|
### 覆盖参数:三种写法,优先级从高到低
|
|
|
|
|
|
|
|
|
|
|
|
| 优先级 | 写法 | 例子 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| 1 | 在镜像后面直接跟 vllm 参数 | `... gemma4-bi150:v0.1.0 --served-model-name mymodel` |
|
|
|
|
|
|
| 2 | `-e EXTRA_ARGS="..."` | `-e EXTRA_ARGS="--max-model-len 16384"` |
|
|
|
|
|
|
| 3 | 同名 `-e` | `-e MAX_MODEL_LEN=16384 -e SERVED_NAME=mymodel` |
|
|
|
|
|
|
| 4 | 默认值 / config.json 检测 | 什么都不传 |
|
|
|
|
|
|
|
|
|
|
|
|
三种写法都能生效,不会重复传参(脚本会跳过自己已经不需要传的项)。
|
|
|
|
|
|
注意覆盖 `--port` 或 `--served-model-name` 时会打印 WARN,因为宿主机 `-p` 的右侧端口和客户端 `model` 字段也要同步改。
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 写法 1:镜像后直接跟参数(最符合 vllm 习惯)
|
|
|
|
|
|
docker run -d --name gemma4-31b \
|
|
|
|
|
|
--entrypoint /usr/local/bin/gemma4-entrypoint.sh --workdir /opt/gemma4 \
|
|
|
|
|
|
--privileged --pid host --ipc host -v /dev:/dev \
|
|
|
|
|
|
-v /mnt/disk0/models/google/gemma-4-31B-it:/models/gemma4:ro \
|
|
|
|
|
|
--ulimit memlock=-1 --ulimit stack=67108864 \
|
|
|
|
|
|
-p 24396:80 \
|
|
|
|
|
|
-e CUDA_VISIBLE_DEVICES=15,14,13,12 -e MODEL_PATH=/models/gemma4 -e AUTO_DETECT=1 \
|
|
|
|
|
|
harbor.4pd.io/modelhubxc/xiejiahao/gemma4-bi150:v0.1.0 \
|
|
|
|
|
|
--served-model-name mymodel --max-model-len 16384
|
|
|
|
|
|
```
|
2026-10-28 13:34:58 +08:00
|
|
|
|
|
2026-10-28 14:19:42 +08:00
|
|
|
|
**注意**:并行跑两个变体时必须给不同的 `-p` 左侧端口,例如 `-p 24397:80`。
|
2026-10-27 14:19:51 +08:00
|
|
|
|
|
2026-10-28 13:34:58 +08:00
|
|
|
|
### 11.3 用 run.sh 启动 CI 镜像
|
2026-10-27 14:19:51 +08:00
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-10-28 13:34:58 +08:00
|
|
|
|
BUILD=0 IMAGE=harbor.4pd.io/modelhubxc/xiejiahao/gemma4-bi150:v0.1.0 \
|
|
|
|
|
|
./run.sh /mnt/disk0/models/google/gemma-4-31B-it
|
|
|
|
|
|
|
|
|
|
|
|
./verify.sh --model-dir /mnt/disk0/models/google/gemma-4-31B-it
|
2026-10-27 14:19:51 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 12. 为什么可以合并
|
|
|
|
|
|
|
|
|
|
|
|
合并前是 `gemma4-31b-deploy/` 和 `gev-26b-decide-deploy/` 两套目录。逐项对比:
|
|
|
|
|
|
|
|
|
|
|
|
| 项 | Gemma-4-31B | GEV-26B-Decide | 能否 detect |
|
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
| 基础镜像 | 同一个 | 同一个 | — |
|
|
|
|
|
|
| 架构 | `Gemma4ForConditionalGeneration` | 同一个 | 不需要 |
|
|
|
|
|
|
| vLLM 补丁 | 两个 | 同样两个 | 不需要 |
|
|
|
|
|
|
| docker run 参数 | 相同 | 相同 | — |
|
|
|
|
|
|
| TP | 4 | 2 | ✅ config 可判 |
|
|
|
|
|
|
| eager | 0 | 1 | ✅ config 可判 |
|
|
|
|
|
|
| 显存 / seqs | 0.90 / 4 | 0.95 / 2 | ✅ config 可判 |
|
2026-10-28 14:19:42 +08:00
|
|
|
|
| 端口 | 80 | 80 | 统一,无需判定 |
|
|
|
|
|
|
| served name | `llm` | `llm` | 统一,无需判定 |
|
2026-10-27 14:19:51 +08:00
|
|
|
|
|
|
|
|
|
|
差异项全部可由 `config.json` 推断,和 Llama 4 用 `num_local_experts` 分 Scout/Maverick 是同一形态,
|
|
|
|
|
|
因此按"一个模型家族一个仓库"的原则合并。
|
|
|
|
|
|
|
|
|
|
|
|
顺带解决的问题:
|
|
|
|
|
|
|
|
|
|
|
|
1. 两份 `apply_patch.py` 原本只差注释,现在只有一份;
|
|
|
|
|
|
2. 两个 Dockerfile 原本都写死了 `ENV/EXPOSE/ENTRYPOINT`,现在通用;
|
|
|
|
|
|
3. 一次 CI 覆盖两个模型,而不是两次构建(每次约 1.5 小时);
|
|
|
|
|
|
4. 新增 TP 可行性校验,把"GEV 只能 TP2、Gemma4 只能 TP4"从文档结论变成启动前断言。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 13. 变更记录
|
|
|
|
|
|
|
|
|
|
|
|
| 日期 | 变更 |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| 2026-10-27 | 由 `gemma4-31b-deploy` + `gev-26b-decide-deploy` 合并为本目录;新增 `detect_model.py`、`verify.sh`、`.gitea`;Dockerfile 去掉 ENV/EXPOSE/ENTRYPOINT;新增 TP 可行性校验和 `GEMMA4_SKIP_TP_CHECK` |
|
2026-10-28 13:34:58 +08:00
|
|
|
|
| 2026-10-27 | CI `v0.1.0` 发布成功(digest `0f6eb25c…`,10.39 GiB) |
|
|
|
|
|
|
| 2026-10-28 | 补录 CI 镜像 digest 与 Gemma-4-31B / GEV 的完整 `docker run` 命令(§11.1–11.3) |
|