声明
内网测试环境,无法承诺在生产环境使用,仅供学习参考。全程操作无互联网。
vLLM 部署 Qwen3.8-27B 说明文档
本仓库用于通过 Docker Compose 在 GPU 服务器上部署 Qwen3.8-27B(OpenAI 兼容接口),并对接 newapi 统一对外提供服务。
环境描述
Ubuntu22
nvidia GPU设备多个
内网测试,无互联网
docker最新版本
采用模型qwen3.8-27B
一、说明(部署对象与关键结论)
| 项 | 值 |
|---|---|
| 模型 | Qwen3.8-27B(HuggingFace Qwen/Qwen3.8-27B,bf16 原始权重) |
| 权重体积 | 约 54GB(27B 参数 × 2 字节),单张 A100-40GB 装不下 |
| 部署策略 | Tensor Parallel = 2(两张卡分摊权重,未量化、零质量损失) |
| 镜像 | vllm/vllm-openai:v0.29.0 |
| 容器名 | ruichuang-qwen3.8-27B |
| 使用 GPU | 设备 2 + 3(部署时完全空闲,各 4MiB) |
| 服务端口 | 宿主 8011 → 容器 8000 |
| 服务模型名 | Qwen3.8-27B |
| 重启策略 | unless-stopped(崩溃/重启自动拉起) |
| 对接方式 | newapi 跨机同局域网直连 |
⚠️ 模型为 bf16,单卡 40GB 显存无法容纳。若未来要改回「单卡」,必须先做 4-bit/8-bit 量化生成新权重,再调整
--tensor-parallel-size 1与--quantization参数(见第四节「进阶调整」)。
二、准备环境
在目标 GPU 服务器(下文称 gpu01)上确认:
-
Docker + Docker Compose v2
bashdocker --version docker compose version -
NVIDIA Container Toolkit (让容器能调 GPU)
bashnvidia-smi # 能看到 8 张 A100 即驱动正常 docker info | grep -i nvidia # 应能看到 nvidia runtime -
模型权重已就位
bashls /home/data/ruichuang/Qwen3.8-27B/model-*.safetensors路径必须与 compose 中挂载一致(见第三节
volumes)。 -
确认 GPU 2、3 空闲 (避免与其他任务抢卡)
bashnvidia-smi部署前 GPU 2、3 的
Memory-Usage应为约4MiB。 -
物理机端口 8011 未被占用
bashss -ltnp | grep 8011 # 无输出即可
三、Compose 配置说明
文件:docker-compose-ruichuang-qwen3.8-27b.yaml
| 字段 | 值 | 说明 |
|---|---|---|
name |
ruichuang-qwen3.8-27b |
Compose 项目名,影响容器网络前缀 |
image |
vllm/vllm-openai:v0.29.0 |
vLLM OpenAI 服务镜像(已确认真实可用版本) |
container_name |
ruichuang-qwen3.8-27B |
固定容器名,便于 docker logs/exec |
runtime |
nvidia |
使用 nvidia 容器运行时(本机 compose 的 gpus 字段仅支持 all,故走 runtime) |
environment |
NVIDIA_VISIBLE_DEVICES=2,3 |
限定容器内仅可见 2、3 号 GPU(vLLM 的 TP=2 即用这两张) |
shm_size |
16gb |
增大共享内存,避免多 worker 时 RuntimeError |
ipc |
host |
与宿主共享 IPC 命名空间,配合 shm 提升多进程效率 |
ports |
8011:8000 |
宿主 8011 映射到容器 8000(vLLM 监听端口) |
volumes |
/home/data/ruichuang/Qwen3.8-27B:/models:ro |
只读挂载模型目录到 /models |
restart |
unless-stopped |
容器退出或宿主重启后自动拉起 |
pull_policy |
if_not_present |
锁定 v0.29.0,避免被意外重新拉取覆盖 |
security_opt |
no-new-privileges:true |
禁止容器内提权 |
cap_drop |
ALL |
丢弃全部 Linux capabilities(若启动报 capability 错误可移除此项) |
logging |
max-size 50m / max-file 3 |
日志轮转,防止长期运行撑满磁盘 |
healthcheck |
curl 带 key 探 127.0.0.1:8000/v1/models |
复刻 newapi 真实检查(服务就绪+鉴权通过+模型已注册)才标记 healthy;start_period 600s。用 curl 而非 python:vLLM v0.29.0 镜像(基础 nvidia/cuda:13.0.3-base-ubuntu24.04)保证有 curl 与 python3,但无裸 python 别名 ,用 python -c 会 not found |
command |
见下 | vLLM 启动参数(镜像 entrypoint 已含 vllm serve,此处只传参数) |
command 参数逐项说明:
| 参数 | 值 | 说明 |
|---|---|---|
--model |
/models |
模型目录(容器内路径) |
--served-model-name |
Qwen3.8-27B + qwen3.8-27b |
对外的模型标识(vLLM 大小写敏感,故同时注册大小写两个别名;newapi 填任一均可) |
--host / --port |
0.0.0.0 / 8000 |
容器内监听地址与端口 |
--dtype |
bfloat16 |
A100 原生支持,精度/速度均衡 |
--tensor-parallel-size |
2 |
2 卡并行,必需(单卡放不下) |
--gpu-memory-utilization |
0.95 |
单卡可用显存比例,留 5% 余量 |
--max-model-len |
131071 |
最大上下文 ≈128K |
--max-num-seqs |
8 |
最大并发序列数 |
--api-key |
sk-ruichuang-qwen38-27b-... |
访问密钥,newapi 必须填相同值;内网环境直接内联明文 |
--enable-prefix-caching |
开 | 复用前缀 KV,省算力 |
--reasoning-parser |
qwen3 |
思考链解析器;指定后 v0.29.0 即启用 reasoning(旧版 --enable-reasoning 开关已被移除,不要再加) |
--enable-auto-tool-choice |
开 | 启用函数/工具调用 |
--tool-call-parser |
qwen3_coder |
工具调用解析器 |
--trust-remote-code |
开 | 允许模型自定义代码(新架构常需) |
安全与暴露面提示
- 密钥 :内网环境,api-key 已直接内联到 compose 的
--api-key行(明文)。若部署到公网或更严格环境,建议外置到.env并通过${VLLM_API_KEY}注入。- 端口暴露 :
8011绑定宿主全网卡(0.0.0.0)。因 newapi 跨机直连必须可达,故靠「api-key 鉴权 + 防火墙仅放行 newapi 网段」双保险。切勿在公网无防护暴露此端口。- trust-remote-code:仅对可信模型(如官方 Qwen)开启;换成来源不明模型前请先评估。
- 并发上限 :
--max-model-len 131071 × --max-num-seqs 8的 KV cache 超过显存,vLLM 会按可用显存自动限制实际并发(约 1~2 条长上下文),属正常行为,不会启动失败。
docker-compose-ruichuang-qwen3.8-27b.yaml完整配置
bash
name: ruichuang-qwen3.8-27b
services:
vllm:
image: vllm/vllm-openai:v0.29.0
container_name: ruichuang-qwen3.8-27B
# 仅用空闲的 2、3 号 A100(TP=2 分摊 27B 权重,单卡 40GB 装不下 bf16)
# 注:本机 compose 版本的 gpus 字段仅支持 "all",故用 nvidia runtime + 环境变量限定卡号
runtime: nvidia
environment:
- NVIDIA_VISIBLE_DEVICES=2,3
shm_size: 16gb
ipc: host
ports:
# 监听宿主所有网卡;生产环境务必用防火墙仅放行 newapi 所在网段(密钥已鉴权,但最小化暴露面)
- "8011:8000"
volumes:
- /home/data/ruichuang/Qwen3.8-27B:/models:ro
restart: unless-stopped
pull_policy: if_not_present
# 镜像 entrypoint 已含 `vllm serve`,这里只传参数(与 docker run 等价)
# 注意:--max-model-len 131071 × --max-num-seqs 8 的 KV cache 超过显存,
# vLLM 会按可用显存自动限制实际并发(约 1~2 条长上下文并发),不会启动失败。
command:
- --model
- /models
# 单条 flag 接多值(vLLM 语义:SERVED_MODEL_NAME [SERVED_MODEL_NAME ...]);
# 重复写两条 --served-model-name 会被后者覆盖,导致只注册最后一个名。
# 同时注册大写/小写,规避 newapi 大小写不一致的 404。
- --served-model-name
- Qwen3.8-27B
- qwen3.8-27b
- --host
- 0.0.0.0
- --port
- "8000"
- --dtype
- bfloat16
- --tensor-parallel-size
- "2"
- --gpu-memory-utilization
- "0.95"
- --max-model-len
- "131071"
- --max-num-seqs
- "8"
- --api-key
- sk-ruichuang-qwen38-27b-86227ee6768a3b4dd1fb25fdff0ddbb1a0cebc064588fd2f
- --enable-prefix-caching
- --reasoning-parser
- qwen3
- --enable-auto-tool-choice
- --tool-call-parser
- qwen3_coder
# 仅对可信模型开启;Qwen3.8 为新架构,需要执行仓库内自定义代码
- --trust-remote-code
# ===== 多模态(视觉)支持 =====
# Qwen3.8-27B 是原生 VLM(架构 Qwen3_5ForConditionalGeneration,config.json 含 vision_config),
# 无需任何「开启多模态」开关,vLLM 加载视觉模型即自动启用图片/视频理解。以下两项为可选调优。
# 每个提示词最多图片数:vLLM 默认各模态 999(无封顶),此处显式限制以防客户端大量灌图打满显存/算力。
# 注意:该值必须是合法 JSON 字符串(vLLM 用 json.loads 解析),不能写 image=1(实测报 cannot be converted to loads)。
# 单图场景用 {"image": 1};多图场景按需调大(如 {"image": 4});带尺寸:{"image": {"count": 4, "width": 512, "height": 512}}
- --limit-mm-per-prompt
- '{"image": 1}'
# 多模态处理器缓存(GiB):缓存已处理的图片特征,避免对相同图片重复预处理,加速重复图/多轮图场景。
# vLLM 默认值即为 4;此处显式调大以真正发挥作用。注意总占用 = 本值 ×(API进程数 + data_parallel_size),
# 当前 TP=2(dp=1)→ 约 本值×2 的主机内存。设为 0 关闭(不推荐)。
- --mm-processor-cache-gb
- "8"
# ===== 生产加固 =====
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
logging:
driver: json-file
options:
max-size: "50m"
max-file: "3"
healthcheck:
# 已核对 vLLM v0.29.0 镜像构建记录:基础镜像 nvidia/cuda:13.0.3-base-ubuntu24.04,
# 镜像内保证存在 curl 与 python3(/usr/bin/python3),无 wget、无裸 python 别名(此前用 python -c 直接 not found)。
# 故采用 curl 探活(官方推荐范式,无引号嵌套陷阱):带 api-key 打 /v1/models,
# 返回 2xx 即 服务就绪+鉴权通过+模型已注册;-f 使 4xx/5xx 也判失败。
# 127.0.0.1 强制 IPv4(服务仅监听 0.0.0.0=IPv4,localhost 可能解析到 ::1 导致连不上)。
test:
- CMD-SHELL
- >-
curl -fsS --max-time 5
-H "Authorization: Bearer sk-ruichuang-qwen38-27b-86227ee6768a3b4dd1fb25fdff0ddbb1a0cebc064588fd2f"
http://127.0.0.1:8000/v1/models >/dev/null 2>&1 || exit 1
interval: 30s
timeout: 10s
retries: 5
start_period: 600s
# ============ newapi 对接要点 ============
# 1) 新增渠道,类型选「vLLM」(或 OpenAI 兼容)
# 2) Base URL: http://<gpu01内网IP>:8011/v1 (把 <gpu01内网IP> 换成 gpu01 在局域网的真实 IP)
# 3) API Key: sk-ruichuang-qwen38-27b-86227ee6768a3b4dd1fb25fdff0ddbb1a0cebc064588fd2f (与 --api-key 一致)
# 4) 自定义/模型名填: Qwen3.8-27B
# 5) 建令牌,把该模型分配给对应令牌即可调用
#
# 密钥管理:内网环境,api-key 已直接内联到本文件(--api-key 行);如需更稳妥可外置到 .env。
# 启动: docker compose -f docker-compose-ruichuang-qwen3.8-27b.yaml up -d
# 日志: docker compose -f docker-compose-ruichuang-qwen3.8-27b.yaml logs -f
# 状态: docker compose -f docker-compose-ruichuang-qwen3.8-27b.yaml ps (看 health 列)
# 自检: curl http://localhost:8011/v1/models -H "Authorization: Bearer sk-ruichuang-qwen38-27b-86227ee6768a3b4dd1fb25fdff0ddbb1a0cebc064588fd2f"
四、如何调整配置
编辑 docker-compose-ruichuang-qwen3.8-27b.yaml 后,docker compose up -d 重新拉起即可生效(改 command 参数需重建容器:docker compose up -d --force-recreate)。
1. 换 GPU 卡
yaml
runtime: nvidia
environment:
- NVIDIA_VISIBLE_DEVICES=4,5 # 改成任意两张空闲卡,如 4,5 / 2,4
说明:本机 compose 版本的
gpus字段仅支持"all",无法指定卡号,因此用runtime: nvidia+NVIDIA_VISIBLE_DEVICES来选卡。TP 卡数需与
--tensor-parallel-size一致;当前为 2 卡,若改成 1 张必须先把模型量化(见进阶)。
2. 换宿主机端口
yaml
ports:
- "8012:8000" # 前半改宿主机端口(8011~8015 可用段内)
3. 换模型路径 / 模型名
yaml
volumes:
- /新路径/Qwen3.8-27B:/models:ro
command:
- --served-model-name
- 自定义名字 # newapi 侧同步改
4. 调并发与上下文
yaml
command:
- --max-num-seqs
- "16" # 提高并发(多吃 KV cache)
- --max-model-len
- "262144" # 上下文拉到 256K(需显存足够)
5. api-key 管理(当前为内联明文)
当前 compose 的 --api-key 行已直接写入明文 key(内网环境按需求内联)。如需更稳妥:
- 改为外置:删除
--api-key行,在 compose 加env_file: [.env]并把 key 写进.env(VLLM_API_KEY=...),再docker compose up -d --force-recreate重建。 - 轮换密钥 :直接改
--api-key明文(或改.env)后重建容器,newapi 渠道同步改。 - 内联明文请避免把 compose 文件转发到不可信环境或提交到公开 Git 仓库。
6. 进阶:改回单卡(需先量化)
单卡 40GB 无法直接跑 bf16。路线:用 llm-compressor 或 autoawq 产出 4-bit 权重,再:
yaml
gpus: "device=2"
command:
- --tensor-parallel-size
- "1"
- --quantization
- awq # 或 compressed-tensors(fp8)
五、如何部署
-
把
docker-compose-ruichuang-qwen3.8-27b.yaml传到 gpu01(如/home/data/ruichuang/或任意目录)。 -
在该目录执行:
bashdocker compose -f docker-compose-ruichuang-qwen3.8-27b.yaml up -d -
观察启动日志(模型加载约需 1~3 分钟):
bashdocker compose -f docker-compose-ruichuang-qwen3.8-27b.yaml logs -f看到
Uvicorn running on http://0.0.0.0:8000即服务就绪。 -
常用运维:
bashdocker compose -f docker-compose-ruichuang-qwen3.8-27b.yaml ps # 状态 docker compose -f docker-compose-ruichuang-qwen3.8-27b.yaml down # 停止 docker compose -f docker-compose-ruichuang-qwen3.8-27b.yaml up -d --force-recreate # 改配置后重建
六、部署后验证
容器启动后先等模型加载(约 1~3 分钟)。可用
docker compose -f docker-compose-ruichuang-qwen3.8-27b.yaml ps看health列:从starting变healthy即就绪(健康探测为容器内置curl带 api-key 打127.0.0.1:8000/v1/models,正是 newapi 实际依赖的检查,start_period600s)。若
health列一直unhealthy,用下面命令看探活真实输出定位根因:
bashdocker inspect ruichuang-qwen3.8-27B --format='{{range .State.Health.Log}}{{.ExitCode}} {{.Output}}{{end}}'正常应出现
0+ 空输出;若非 0,输出会直接给出原因(如curl: not found、连接拒绝、401)。
1. 模型列表(需带 api-key)
bash
curl http://localhost:8011/v1/models \
-H "Authorization: Bearer sk-ruichuang-qwen38-27b-86227ee6768a3b4dd1fb25fdff0ddbb1a0cebc064588fd2f"
返回应包含 "id": "Qwen3.8-27B"。
2. 一次对话测试
bash
curl http://localhost:8011/v1/chat/completions \
-H "Authorization: Bearer sk-ruichuang-qwen38-27b-86227ee6768a3b4dd1fb25fdff0ddbb1a0cebc064588fd2f" \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen3.8-27B",
"messages": [{"role": "user", "content": "用一句话介绍你自己"}],
"max_tokens": 200
}'
3. 确认 GPU 占用
bash
nvidia-smi
GPU 2、3 的 Memory-Usage 应升至约 27GB+/卡,且出现 VLLM::EngineCore 进程。
4. 常见故障排查
| 现象 | 可能原因 | 处理 |
|---|---|---|
| 容器反复重启 | 显存不足 / 参数错 | docker logs ruichuang-qwen3.8-27B 看堆栈 |
CUDA out of memory |
gpu-mem-util 过高或 max-num-seqs 过大 | 降到 0.90 / 调小 seqs |
| newapi 调不通 | api-key 不一致 | 核对 compose 与 newapi 渠道 key 完全相同 |
| 推理很慢 | KV cache 被 max-model-len 占满 | 适当下调 max-model-len |
七、如何对接 newapi 使用
前提:newapi 与 gpu01 同局域网、可直连。
-
登录 newapi 后台 → 渠道管理 → 添加渠道。
-
渠道类型选 vLLM(或「OpenAI」兼容类型)。
-
填写:
- Base URL :
http://<gpu01内网IP>:8011/v1
(把<gpu01内网IP>换成 gpu01 在局域网的实际 IP,如192.168.1.20) - API Key :
sk-ruichuang-qwen38-27b-86227ee6768a3b4dd1fb25fdff0ddbb1a0cebc064588fd2f
(即 compose--api-key行内联的值,必须与之一致) - 模型 :填写
Qwen3.8-27B(自定义/支持的模型名)
- Base URL :
-
保存并测试渠道连通性(newapi 有「测试」按钮)。
-
令牌管理 → 新建令牌 ,把
Qwen3.8-27B分配给该令牌。 -
用 newapi 提供的「API 地址 + 令牌」即可像调用 OpenAI 一样使用该模型:
bashcurl https://<newapi地址>/v1/chat/completions \ -H "Authorization: Bearer <newapi令牌>" \ -H "Content-Type: application/json" \ -d '{"model":"Qwen3.8-27B","messages":[{"role":"user","content":"你好"}]}'
若 newapi 与 gpu01 不在同一台机,确保 gpu01 防火墙放行 8011 端口,且
<gpu01内网IP>在 newapi 所在网络可达。