07 正确的部署脚本与一键部署:deploy.sh 逐参数拆解
文章目录
- [07 正确的部署脚本与一键部署:deploy.sh 逐参数拆解](#07 正确的部署脚本与一键部署:deploy.sh 逐参数拆解)
-
- [1. 准备模型软链接(路径不进 git)](#1. 准备模型软链接(路径不进 git))
- [2. 构建补丁镜像(一次性,1--2 分钟)](#2. 构建补丁镜像(一次性,1–2 分钟))
- [3. 配置并启动](#3. 配置并启动)
- [4. 验证:看什么日志、跑什么测试](#4. 验证:看什么日志、跑什么测试)
-
- [4.1 前台调试:run_debug.sh](#4.1 前台调试:run_debug.sh)
- [4.2 重启与升级的缓存语义](#4.2 重启与升级的缓存语义)
- [5. 常见启动失败对照](#5. 常见启动失败对照)
- 系列:GLM-5.3-NVFP4 部署实录(8×A800 / sm80)。
- 上一篇:06 问题深拆③:推测解码https://blog.csdn.net/yang2330648064/article/details/164192449)。
- 前面六篇解决了"能不能跑"和"跑得快",本篇解决"跑得稳、别人也能一键跑起来"。这是最终验证通过的部署方式:三个准备步骤 + 一条启动命令。
- GLM5.3 nvfp4 VLLM部署方案
1. 准备模型软链接(路径不进 git)
- 模型权重不进仓库,用项目内软链接间接引用:
bash
mkdir -p models
ln -sfn /path/to/real/GLM-5.3-NVFP4 models/GLM-5.3-NVFP4
ln -sfn /path/to/real/GLM-5.3-DFlash2 models/GLM-5.3-DFlash2
这样做的优势
- 部署脚本和挂载配置只引用项目内的软链接路径,真实存储路径不出现在任何脚本里(也不泄漏进 git)
- Docker 挂载时在宿主机侧解析软链接的真实目录,容器内统一从
/models/GLM-5.3-NVFP4访问 - 换机器只需重建软链接。
2. 构建补丁镜像(一次性,1--2 分钟)
bash
DOCKER_BUILDKIT=0 docker build -t vllm/vllm-openai:v0.28.0-glm53-sm80 \
-f Dockerfile.glm53-sm80 .
3. 配置并启动
bash
cp env.local.example env.local # 可按需覆盖默认值
./deploy.sh start
deploy.sh会打印模型挂载源与真实目录的对照,然后拉起容器。所有默认值都集中在脚本头部,可用env.local覆盖(该文件被 git 忽略,只放本地差异化配置):
bash
# env.local.example ------ 常用覆盖项
# PORT=8001
# MODEL_NAME=glm-5.3-nvfp4
# GPU_MEM_UTIL=0.95
# MAX_MODEL_LEN=65536
# MAX_NUM_SEQS=16
# MAX_NUM_BATCHED_TOKENS=8192
# SPEC_METHOD=mtp # mtp | dflash | none
# CUDAGRAPH_CAPTURE_SIZES=1,2,4,8,12,16
# KV_CACHE_MEMORY= # 例如 18339330048,按启动日志提示填,可再榨 2-3GiB KV
-
其中
KV_CACHE_MEMORY值得单独说:启动日志会提示"剩余显存还可放多少 KV",把它换算成字节数填进去即可把 0.95 利用率下的 KV 从 ~15GiB 提到 ~17--18GiB,长上下文并发场景直接受益。 -
完整
docker run如下(来自脚本):
bash
docker run -d --name glm53-nvfp4 \
--gpus all \
--shm-size=32g \
-e VLLM_ATTENTION_BACKEND=TRITON_MLA_SPARSE \
-e PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True \
-v $PWD/models/GLM-5.3-NVFP4:/models/GLM-5.3-NVFP4:ro \
-v $PWD/models/GLM-5.3-DFlash2:/models/GLM-5.3-DFlash2:ro \
-v $PWD/.compile_cache:/root/.cache/vllm \
-p 8001:8001 \
vllm/vllm-openai:v0.28.0-glm53-sm80 \
/models/GLM-5.3-NVFP4 \
--host 0.0.0.0 --port 8001 \
--tensor-parallel-size 8 \
--trust-remote-code \
--dtype bfloat16 \
--gpu-memory-utilization 0.95 \
--max-model-len 65536 \
--kv-cache-dtype bfloat16 \
--max-num-seqs 16 \
--max-num-batched-tokens 8192 \
--served-model-name glm-5.3-nvfp4 \
--compilation-config '{"cudagraph_capture_sizes":[1,2,4,8,12,16]}' \
--attention-config '{"sparse_mla_force_mqa": true}' \
--tool-call-parser glm47 --enable-auto-tool-choice \
--reasoning-parser glm45 \
--speculative-config '{"method":"mtp","num_speculative_tokens":5}'
- 关键参数解释
| 参数 | 值 | 说明 |
|---|---|---|
--tensor-parallel-size |
8 | 433G 权重 TP8 每卡 ~54G,TP 数再低显存放不下 |
--kv-cache-dtype |
bfloat16 |
A800 不支持 fp8 KV;注意全称,写 bf16 报错 |
--gpu-memory-utilization |
0.95 | 权重占 ~58.3GiB/卡,剩给 KV 约 15GiB |
--max-model-len |
65536 | 实测 4 并发 × 32k 上下文通过 |
--max-num-seqs |
16 | 并发上限;同时决定 CUDA 图捕获尺寸裁剪的上界(见 08 篇) |
--attention-config |
sparse_mla_force_mqa=true |
必填 ,否则 prefill 崩在 forward_mha(坑 2) |
--compilation-config |
捕获尺寸 1,2,4,8,12,16 | torch.compile 开启 + CUDA 图捕获裁剪(坑 9 修复后;裁剪逻辑见 08 篇) |
--speculative-config |
MTP × 5 | A800 上 DFlash2 接受率崩塌(坑 13),默认 MTP |
-e PYTORCH_CUDA_ALLOC_CONF |
expandable_segments:True |
减少碎片;偶发 mapping 警告可忽略 |
-v .compile_cache:/root/.cache/vllm |
编译缓存挂载 | 首启 ~8min,之后 ~3min(见 08 篇) |
--reasoning-parser glm45 |
思考内容进 reasoning 字段 |
|
--tool-call-parser glm47 --enable-auto-tool-choice |
工具调用支持 |
运维子命令:./deploy.sh start|stop|status|logs|shell。另有两个实用设计:
- 启动前检测 8 卡是否被占用(
nvidia-smi显存 >100MiB 即告警); PREEMPT_CONTAINER=xxx ./deploy.sh start可自动停掉占卡的其他容器。
4. 验证:看什么日志、跑什么测试
- 启动后
./deploy.sh logs盯这几行关键日志(全部出现即成功链路):
bash
Using TRITON_MLA_SPARSE attention backend ... ← 后端命中
Using 'MARLIN' NvFp4 MoE backend ← NVFP4 软件回退生效
Load weight ... 87/87 ← 分片全部加载(页缓存热 ~80s)
init engine ... took 38.64 s ← 引擎初始化
Application startup complete. ← 就绪
- 完整冷启动(含权重加载,页缓存热)约 5 分钟。然后跑冒烟与功能验证:
bash
curl -s http://127.0.0.1:8001/v1/models
./test_api.sh # 冒烟:17×13=221,reasoning 字段正常
./scripts/ttft_test.py # 首 token 延迟
./scripts/ctx_4x32k_test.py # 4 并发 × ~30k 上下文
./scripts/thinking_mode_test.py # 思考模式三档
test_api.sh 的冒烟逻辑是"探活 + 数学 sanity"两步:先请求 /v1/models 确认服务就绪,再让模型算 17 × 13(期望 221),并打印 content / reasoning / finish_reason 三个字段------一次请求同时验证了推理正确性、reasoning parser 挂载、生成正常终止三件事,是每次改配置后最方便的回归测试。
4.1 前台调试:run_debug.sh
- 改动启动参数做实验时,
docker run -d+docker logs -f的循环太绕。run_debug.sh用前台运行 跑同一套配置(--rm容器,Ctrl+C 即停,退出即清理),全量日志直接刷在终端:
bash
SPEC_METHOD=mtp ./run_debug.sh # 环境变量与 deploy.sh 同名同义
它和 deploy.sh 的唯一实质差别是运行方式和默认 SPEC_METHOD(调试脚本默认 dflash,便于对照测接受率)。排查启动崩溃时建议一律用它------日志不经过缓冲转发,报错栈完整可见。
4.2 重启与升级的缓存语义
日常运维中两类常见操作的正确姿势:
- 原样重启 (机器重排队、进程崩了):直接
./deploy.sh stop && ./deploy.sh start。编译缓存命中,约 3 分钟就绪;权重在页缓存里的话加载只花 ~9s。 - 改了补丁/参数后重启 :vLLM 的编译缓存按代码与配置哈希管理,补丁文件变了对应产物自动失效重编(首启 ~8min 的成本只付一次);改
MAX_NUM_SEQS等调度参数不会使编译失效,但会改变 CUDA 图捕获需求 ------记得同步检查CUDAGRAPH_CAPTURE_SIZES上界。
5. 常见启动失败对照
| 现象 | 检查 |
|---|---|
No valid attention backend found |
镜像是否用补丁镜像(tag glm53-sm80),不是官方裸镜像 |
prefill 崩 forward_mha |
是否漏了 --attention-config '{"sparse_mla_force_mqa": true}' |
--kv-cache-dtype bf16 报非法 |
写全称 bfloat16 |
--speculative-config cannot be converted |
JSON 拼接的字面引号问题(坑 12),用无空格裸 JSON |
崩 attention.hpp Unsupported architecture |
补丁 7/9 未打:indexer 仍走 deep_gemm |
下一篇:08 启动加速:编译缓存挂载与 CUDA 图捕获裁剪------把 8 分钟的首启压到 3 分钟。