vLLM Ascend 昇腾推理部署:从硬件检测到生产上线
华为昇腾 NPU 上部署 vLLM 的完整指南:NPU 设备检测、Docker/Docker Compose/Kubelet 四种部署方式、Qwen3/DeepSeek/GLM 等 30+ 模型支持,以及 PD 分离和监控。
一、vllm-ascend 是什么
vllm-ascend 是 华为和 vLLM 社区官方合作 的昇腾 NPU 后端插件(Apache 2.0)。它让 vLLM 支持的每一行代码对昇腾 NPU 都有效 — 不需要改推理逻辑,只换后端硬件。
二、NPU 设备发现与检测
部署前最重要的一步:确认服务器上是否有 NPU、是否可用。以下是从硬件到软件栈的完整检测流程。
2.1 硬件层:NPU 是否存在
# 1. PCIe 设备检测 — 查看是否有华为昇腾 NPU
# 华为 Vendor ID = 19e5,用 -d 按厂商 ID 过滤最准确
lspci -d 19e5:
# 或者按厂商名(部分设备名不含 "ascend" 字样,用 "huawei" 更可靠)
lspci | grep -i huawei
# Atlas 300I/800 系列 PCIe 卡会在这里显示
# 2. davinci 设备文件 — 最直接的判断
ls -la /dev/davinci*
# 期望输出(8 卡服务器):
# /dev/davinci0 /dev/davinci1 /dev/davinci2 /dev/davinci3
# /dev/davinci4 /dev/davinci5 /dev/davinci6 /dev/davinci7
# /dev/davinci_manager
# /dev/devmm_svm
# /dev/hisi_hdc
# 3. 统计 NPU 数量
ls /dev/davinci[0-9]* | wc -l
2.2 驱动层:npu-smi 工具
npu-smi 是昇腾 NPU 的标配管理工具(类似 NVIDIA 的 nvidia-smi),但参数体系更复杂:昇腾硬件有三层编号 —— NPU(物理卡槽)、Chip(卡内芯片)、Device(操作系统设备号)。
# 第一步:先看总览
npu-smi info
典型输出(Atlas 300I Pro 310P3,一张卡内含 2 个 Chip):
+-------------------------------+-----------------+--------------------------+
| NPU Name | Health | Power(W) Temp(C) Hugepages-Usage(page) |
| Chip Device | Bus-Id | AICore(%) Memory-Usage(MB) |
+===================+===========+=============================================+
| 1 310P3 | OK | NA 75 0 / 0 | ← NPU ID=1
| 0 0 | 0000:01..| 0 1439 / 44280 | ← Chip 0, Device 0
+-------------------------------+-----------------+--------------------------+
| 1 310P3 | OK | NA 73 0 / 0 | ← 同一张卡 NPU ID=1
| 1 1 | 0000:01..| 0 1501 / 43693 | ← Chip 1, Device 1
+-------------------------------+-----------------+--------------------------+
| 2 310P3 | OK | NA 74 0 / 0 | ← NPU ID=2
| 0 2 | 0000:02..| 0 1495 / 44280 |
+-------------------------------+-----------------+--------------------------+
| 2 310P3 | OK | NA 73 0 / 0 |
| 1 3 | 0000:02..| 0 1443 / 43693 |
+-------------------------------+-----------------+--------------------------+
... NPU 4,5 同理(NPU 0,3 槽位为空)
三层编号解读:
- NPU ID(
-i):物理卡槽编号,310P3 等双芯卡上不连续(如 1,2,4,5)- Chip ID(
-c):卡内芯片编号,双芯卡为 0 和 1- Device:操作系统设备号,对应
/dev/davinci0~/dev/davinci7,供docker --device使用大多数查询必须同时指定
-i和-c才能定位到一个具体 chip。
npu-smi 常用命令:
# 查看 NPU 1, Chip 0 的详细信息
npu-smi info -i 1 -c 0
# 板卡信息(型号/序列号/IP)
npu-smi info -t board -i 1 -c 0
# 温度
npu-smi info -t temp -i 1 -c 0
# 显存(HBM)使用情况
npu-smi info -t memory -i 1 -c 0
# AICore 使用率
npu-smi info -t usages -i 1 -c 0
# 固件版本(卡级属性,只认 -i 不认 -c)
npu-smi info -t firmware -i 1
# 持续监控(不带 -i/-c 看全部)
watch -n 1 npu-smi info
常见错误:
-i 0→Invalid card id。因为 NPU ID 是物理槽位号,和/dev/davinci的设备号不是同一个东西。以npu-smi info输出的 NPU 列为准。
2.3 驱动版本确认
# 查看驱动版本
cat /usr/local/Ascend/driver/version.info
# 输出示例:driver_version=23.0.0
# 查看 ascend 安装信息
cat /etc/ascend_install.info
# 查看 CANN 版本
cat /usr/local/Ascend/ascend-toolkit/latest/opp/built-in/op_impl/ai_core/tbe/version.info 2>/dev/null
# 或者
ls /usr/local/Ascend/ascend-toolkit/
# 输出示例:9.0.0
# 查看 NNAL 版本
ls /usr/local/Ascend/nnal/
# 输出示例:9.0.0
2.4 Python 层:torch-npu 检测
# 检查 torch-npu 是否安装
python3 -c "import torch_npu; print(torch_npu.__version__)"
# NPU 是否可用(最关键的一行)
python3 -c "import torch; print('NPU available:', torch.npu.is_available())"
# 设备数量
python3 -c "import torch; print('NPU count:', torch.npu.device_count())"
# 设备名称
python3 -c "import torch; [print(f'Device {i}: {torch.npu.get_device_name(i)}') for i in range(torch.npu.device_count())]"
# 完整检测脚本
python3 << 'EOF'
import torch
print(f"PyTorch version: {torch.__version__}")
print(f"NPU available: {torch.npu.is_available()}")
if torch.npu.is_available():
print(f"NPU count: {torch.npu.device_count()}")
for i in range(torch.npu.device_count()):
print(f" Device {i}: {torch.npu.get_device_name(i)}")
print(f" Memory: {torch.npu.get_device_properties(i).total_memory / 1024**3:.1f} GB")
else:
print("WARNING: torch.npu.is_available() = False!")
print("Check: CANN version matches torch-npu version? Driver loaded?")
EOF
2.5 设备不存在时的排障路径
| 现象 | 可能原因 | 检查命令 |
|---|---|---|
/dev/davinci* 不存在 | 驱动未安装或未加载 | lsmod | grep drv |
npu-smi 命令未找到 | CANN 未安装或 PATH 未设 | ls /usr/local/Ascend/ |
npu-smi 报错 | 驱动版本与固件不匹配 | dmesg | grep -i davinci |
torch.npu.is_available() = False | torch-npu 版本与 CANN 不匹配 | pip show torch-npu |
| 容器内看不到设备 | --device 未正确挂载 | 检查 docker run 的 --device 参数 |
完整的环境就绪确认清单:
✅ lspci -d 19e5: 或 lspci | grep huawei 能看到华为设备
✅ /dev/davinci0 ... /dev/davinciN 存在
✅ /dev/davinci_manager 存在
✅ npu-smi info 输出正常、Health = OK
✅ /usr/local/Ascend/driver/version.info 存在
✅ /usr/local/Ascend/ascend-toolkit/latest → 指向 CANN 9.0.0
✅ torch.npu.is_available() = True
✅ torch.npu.device_count() = 期望值
三、硬件要求
支持的设备
| 系列 | 型号 | 用途 |
|---|---|---|
| Atlas A2 训练 | 800T A2 / 900 A2 PoD / 200T A2 Box16 / 300T A2 | 训练+推理 |
| Atlas A2 推理 | 800I A2 | 高吞吐推理 |
| Atlas A3 训练 | 800T A3 / 900 A3 SuperPoD / 9000 A3 SuperPoD | 训练+推理 |
| Atlas A3 推理 | 800I A3 | 高吞吐推理 |
| Atlas 300I | 300I Pro (310P3) / 300I Duo | 推理(PCIe 标卡,43GB HBM) |
软件栈版本
┌──────────────────────────────────┐
│ vllm-ascend │ v0.20.2rc1+
├──────────────────────────────────┤
│ torch-npu 2.10.0 │ 昇腾版 PyTorch
├──────────────────────────────────┤
│ torch 2.10.0 │
├──────────────────────────────────┤
│ CANN 9.0.0 │ 昇腾计算架构(= CUDA 等价物)
├──────────────────────────────────┤
│ NNAL 9.0.0 │ 昇腾神经网络加速库(libatb.so)
├──────────────────────────────────┤
│ Ascend HDK / 驱动 │ 固件+驱动
├──────────────────────────────────┤
│ 昇腾 NPU 硬件 │ Atlas A2/A3
└──────────────────────────────────┘
四、模型准备(ModelScope)
国内环境 HuggingFace 访问不稳定,推荐用 ModelScope 下载模型到本地,然后让 vLLM 直接读本地路径。
# 安装 ModelScope CLI
pip install modelscope
# 下载模型到本地目录(路径按自己习惯组织)
modelscope download --model Qwen/Qwen3-0.6B --local_dir /path/to/models/Qwen3-0.6B
modelscope download --model Qwen/Qwen3-8B --local_dir /path/to/models/Qwen3-8B
# 启动时用本地路径替代 HuggingFace model ID
# ❌ vllm serve Qwen/Qwen3-8B # 会尝试从 HF 拉取
# ✅ vllm serve /path/to/models/Qwen3-8B # 直接用本地文件
关键点:容器部署时,通过
-v /path/to/models:/models:ro把宿主机模型目录挂载进容器,容器内用/models/Qwen3-8B即可。
五、Docker 单机部署
5.1 拉取镜像并启动
挂载说明:下面的
-v中,driver/lib64、driver/version.info、ascend_install.info是推理必须的。hccn_tool(卡间通信工具)仅在多节点部署时需要,且训练卡才有 — 如果你的/usr/local/Ascend/driver/tools/hccn_tool不存在,直接去掉这一行即可。
# 设置要用的 NPU 设备
export DEVICE=/dev/davinci0
# 选择镜像(A2 和 A3 不同)
# Atlas A2:
export IMAGE=quay.io/ascend/vllm-ascend:v0.20.2rc1
# Atlas A3:
# export IMAGE=quay.io/ascend/vllm-ascend:v0.20.2rc1-a3
docker run --rm \
--name vllm-ascend \
--shm-size=1g \
--device $DEVICE \
--device /dev/davinci_manager \
--device /dev/devmm_svm \
--device /dev/hisi_hdc \
-v /usr/local/dcmi:/usr/local/dcmi \
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
-v /etc/ascend_install.info:/etc/ascend_install.info \
-v /root/.cache:/root/.cache \
-p 8000:8000 \
-it $IMAGE bash
5.2 多卡 Docker 启动
# 使用 4 张 NPU(davinci0 ~ davinci3)
docker run --rm \
--name vllm-ascend \
--shm-size=1g \
--device /dev/davinci0 \
--device /dev/davinci1 \
--device /dev/davinci2 \
--device /dev/davinci3 \
--device /dev/davinci_manager \
--device /dev/devmm_svm \
--device /dev/hisi_hdc \
-v /usr/local/dcmi:/usr/local/dcmi \
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
-v /etc/ascend_install.info:/etc/ascend_install.info \
-v /root/.cache:/root/.cache \
-p 8000:8000 \
-it $IMAGE bash
# 容器内验证
npu-smi info # 看到 4 张卡
python3 -c "import torch; print(torch.npu.device_count())" # 4
5.3 验证 NPU 可用
# 在容器内
npu-smi info
# 输出 NPU 型号、温度、显存使用
python3 -c "import torch; print(torch.npu.is_available())"
# True
5.4 启动推理服务 — Qwen3-0.6B
# 在容器内
vllm serve /models/Qwen3-0.6B \
--host 0.0.0.0 \
--port 8000
# 另一个终端测试
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3-0.6b",
"messages": [{"role": "user", "content": "你好"}]
}'
六、Docker Compose 部署
Docker Compose 适合持久化运行、多卡管理、以及需要精确控制资源和服务依赖的场景。
关于 shm_size:
/dev/shm是容器内共享内存,默认仅 64MB。PyTorch 的 DataLoader 和多卡并行(tensor parallelism)依赖/dev/shm做进程间 tensor 通信,64MB 完全不够 — 典型表现为DataLoader worker exited unexpectedly或 OOM。单卡设1gb,多卡或大 batch 设2gb以上。
6.1 基础 docker-compose.yml
version: "3.8"
services:
vllm-ascend:
image: quay.io/ascend/vllm-ascend:v0.20.2rc1
container_name: vllm-ascend
# 使用 command 直接启动服务,无需手动进容器
command: >
vllm serve /models/Qwen3-8B
--host 0.0.0.0
--port 8000
--max-model-len 8192
shm_size: "1gb"
ports:
- "8000:8000"
devices:
# 挂载全部 8 张 NPU
- /dev/davinci0:/dev/davinci0
- /dev/davinci1:/dev/davinci1
- /dev/davinci2:/dev/davinci2
- /dev/davinci3:/dev/davinci3
- /dev/davinci4:/dev/davinci4
- /dev/davinci5:/dev/davinci5
- /dev/davinci6:/dev/davinci6
- /dev/davinci7:/dev/davinci7
- /dev/davinci_manager:/dev/davinci_manager
- /dev/devmm_svm:/dev/devmm_svm
- /dev/hisi_hdc:/dev/hisi_hdc
volumes:
# 驱动和工具挂载
- /usr/local/dcmi:/usr/local/dcmi
- /usr/local/bin/npu-smi:/usr/local/bin/npu-smi
- /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/
- /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info
- /etc/ascend_install.info:/etc/ascend_install.info
# 模型缓存持久化(避免每次重建容器重新下载)
- /path/to/models:/models:ro
# 可写日志目录
- /data/logs/vllm:/var/log/vllm
environment:
- HF_HOME=/root/.cache/huggingface
restart: unless-stopped
# 健康检查
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 120s
deploy:
resources:
reservations:
devices:
- driver: ascend
count: all
capabilities: [npu]
6.2 多服务编排(推理 + 网关)
version: "3.8"
services:
# === Qwen3-8B 推理服务(NPU 0-3) ===
vllm-qwen:
image: quay.io/ascend/vllm-ascend:v0.20.2rc1
container_name: vllm-qwen
command: >
vllm serve /models/Qwen3-8B
--host 0.0.0.0
--port 8000
--tensor-parallel-size 4
shm_size: "2gb"
devices:
- /dev/davinci0:/dev/davinci0
- /dev/davinci1:/dev/davinci1
- /dev/davinci2:/dev/davinci2
- /dev/davinci3:/dev/davinci3
- /dev/davinci_manager:/dev/davinci_manager
- /dev/devmm_svm:/dev/devmm_svm
- /dev/hisi_hdc:/dev/hisi_hdc
volumes:
- /usr/local/dcmi:/usr/local/dcmi
- /usr/local/bin/npu-smi:/usr/local/bin/npu-smi
- /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/
- /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info
- /etc/ascend_install.info:/etc/ascend_install.info
- /path/to/models:/models:ro
environment:
- HF_HOME=/root/.cache/huggingface
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 180s
# === DeepSeek-R1 推理服务(NPU 4-7) ===
vllm-deepseek:
image: quay.io/ascend/vllm-ascend:v0.20.2rc1
container_name: vllm-deepseek
command: >
vllm serve /models/DeepSeek-R1
--host 0.0.0.0
--port 8001
--tensor-parallel-size 4
shm_size: "2gb"
devices:
- /dev/davinci4:/dev/davinci4
- /dev/davinci5:/dev/davinci5
- /dev/davinci6:/dev/davinci6
- /dev/davinci7:/dev/davinci7
- /dev/davinci_manager:/dev/davinci_manager
- /dev/devmm_svm:/dev/devmm_svm
- /dev/hisi_hdc:/dev/hisi_hdc
volumes:
- /usr/local/dcmi:/usr/local/dcmi
- /usr/local/bin/npu-smi:/usr/local/bin/npu-smi
- /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/
- /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info
- /etc/ascend_install.info:/etc/ascend_install.info
- /path/to/models:/models:ro
environment:
- HF_HOME=/root/.cache/huggingface
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8001/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 300s
# === Nginx 反向代理(统一入口) ===
nginx:
image: nginx:alpine
container_name: vllm-gateway
ports:
- "8080:8080"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
vllm-qwen:
condition: service_healthy
vllm-deepseek:
condition: service_healthy
restart: unless-stopped
配套的 nginx.conf:
worker_processes auto;
events { worker_connections 1024; }
http {
# 按模型名路由到对应后端
# Qwen3 → 8000,DeepSeek → 8001
# 客户端请求时传 model 参数,Nginx 按 model 分流
server {
listen 8080;
# Qwen 系列
location /v1/chat/completions {
# 需要更复杂的 Lua/OpenResty 逻辑来按请求体中的 model 路由
# 简单场景下可直接代理到默认后端
proxy_pass http://vllm-qwen:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_read_timeout 600s;
}
# DeepSeek 系列指定路径
location /deepseek/v1/chat/completions {
proxy_pass http://vllm-deepseek:8001/v1/chat/completions;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_read_timeout 600s;
}
# 健康检查聚合
location /health {
# 返回所有后端健康状态
return 200 '{"qwen":"http://vllm-qwen:8000/health","deepseek":"http://vllm-deepseek:8001/health"}';
}
}
}
6.3 Compose 运维命令
# 启动所有服务
docker compose up -d
# 查看日志
docker compose logs -f vllm-qwen
# 仅重启单个服务
docker compose restart vllm-deepseek
# 停止并删除(保留模型缓存卷)
docker compose down
# 停止并删除全部(含模型缓存)
docker compose down -v
七、Kubelet 静态 Pod 部署
当你有一台或几台昇腾服务器,不想搭完整 K8s 集群,但希望用 Pod 的方式管理容器生命周期时,Kubelet 静态 Pod 是最轻量的方案。
7.1 前置条件
# 1. 安装 kubelet(无需 API Server/etcd)
# Ubuntu:
apt-get install -y kubelet kubeadm kubectl
# 或者只装 kubelet(如果你有其他方式装 kubectl)
# 2. 确认 kubelet 运行
systemctl status kubelet
# 3. 确认静态 Pod 目录存在
ls /etc/kubernetes/manifests/
# 默认静态 Pod 清单目录,放入 YAML 即可自动创建
Kubelet 会持续监控 /etc/kubernetes/manifests/ 目录,放入的任何 Pod YAML 会被自动创建,删除文件则 Pod 被删除。不需要 API Server,kubelet 独立完成。
7.2 静态 Pod YAML
# /etc/kubernetes/manifests/vllm-ascend.yaml
apiVersion: v1
kind: Pod
metadata:
name: vllm-ascend
namespace: default
labels:
app: vllm-ascend
model: qwen3-8b
spec:
# 不指定 restartPolicy 时静态 Pod 默认为 Always
restartPolicy: Always
hostNetwork: true # 使用宿主机网络,NPU 通信需要
hostIPC: true # NPU 跨进程通信
containers:
- name: vllm
image: quay.io/ascend/vllm-ascend:v0.20.2rc1
command:
- vllm
- serve
- /models/Qwen3-8B
- --host
- "0.0.0.0"
- --port
- "8000"
- --max-model-len
- "8192"
ports:
- containerPort: 8000
hostPort: 8000
resources:
limits:
# 声明 4 张昇腾 NPU
huawei.com/Ascend910: 4
requests:
huawei.com/Ascend910: 4
volumeMounts:
- name: driver
mountPath: /usr/local/Ascend/driver
readOnly: true
- name: dcmi
mountPath: /usr/local/dcmi
readOnly: true
- name: npu-smi
mountPath: /usr/local/bin/npu-smi
readOnly: true
- name: ascend-install
mountPath: /etc/ascend_install.info
readOnly: true
- name: model-cache
mountPath: /root/.cache/huggingface
- name: shm
mountPath: /dev/shm
env:
- name: HF_HOME
value: /root/.cache/huggingface
securityContext:
privileged: true # NPU 设备访问需要特权
volumes:
- name: driver
hostPath:
path: /usr/local/Ascend/driver
- name: dcmi
hostPath:
path: /usr/local/dcmi
- name: npu-smi
hostPath:
path: /usr/local/bin/npu-smi
- name: ascend-install
hostPath:
path: /etc/ascend_install.info
- name: model-cache
hostPath:
path: /data/models
type: DirectoryOrCreate
- name: shm
hostPath:
path: /dev/shm
7.3 NPU Device Plugin(可选,但推荐)
如果你的 kubelet 需要调度 NPU 资源(huawei.com/Ascend910),需要部署昇腾设备插件:
# 昇腾官方设备插件(DaemonSet 形式,但静态 Pod 也可以用)
# 方式 1:直接在宿主机给 kubelet 配置 NPU 资源
# 编辑 /var/lib/kubelet/config.yaml 或 kubelet 启动参数
# 添加:
# --feature-gates=DevicePlugins=true
# 方式 2:如果没有设备插件,可以去掉 resources 段
# 裸用 hostPath 挂载 /dev/davinci* 也是可以的
不用设备插件的简化版(裸设备挂载):
# /etc/kubernetes/manifests/vllm-ascend-noplugin.yaml
apiVersion: v1
kind: Pod
metadata:
name: vllm-ascend-noplugin
spec:
restartPolicy: Always
hostNetwork: true
hostIPC: true
containers:
- name: vllm
image: quay.io/ascend/vllm-ascend:v0.20.2rc1
command:
- vllm
- serve
- /models/Qwen3-8B
- --host
- "0.0.0.0"
- --port
- "8000"
ports:
- containerPort: 8000
hostPort: 8000
volumeMounts:
- name: davinci0
mountPath: /dev/davinci0
- name: davinci1
mountPath: /dev/davinci1
- name: davinci-manager
mountPath: /dev/davinci_manager
- name: devmm-svm
mountPath: /dev/devmm_svm
- name: hisi-hdc
mountPath: /dev/hisi_hdc
- name: driver
mountPath: /usr/local/Ascend/driver
readOnly: true
- name: npu-smi
mountPath: /usr/local/bin/npu-smi
readOnly: true
- name: model-cache
mountPath: /root/.cache/huggingface
- name: shm
mountPath: /dev/shm
env:
- name: HF_HOME
value: /root/.cache/huggingface
securityContext:
privileged: true
volumes:
- name: davinci0
hostPath:
path: /dev/davinci0
type: CharDevice
- name: davinci1
hostPath:
path: /dev/davinci1
type: CharDevice
- name: davinci-manager
hostPath:
path: /dev/davinci_manager
type: CharDevice
- name: devmm-svm
hostPath:
path: /dev/devmm_svm
type: CharDevice
- name: hisi-hdc
hostPath:
path: /dev/hisi_hdc
type: CharDevice
- name: driver
hostPath:
path: /usr/local/Ascend/driver
- name: npu-smi
hostPath:
path: /usr/local/bin/npu-smi
- name: model-cache
hostPath:
path: /data/models
type: DirectoryOrCreate
- name: shm
hostPath:
path: /dev/shm
7.4 静态 Pod 运维
# 放入 YAML 后自动启动
cp vllm-ascend.yaml /etc/kubernetes/manifests/
# 查看 Pod 状态(通过 kubelet 的只读端口)
curl -s http://localhost:10255/pods | jq '.items[] | select(.metadata.name | startswith("vllm")) | {name: .metadata.name, phase: .status.phase}'
# 或者直接查容器
docker ps | grep vllm
# 静态 Pod 容器名格式:k8s_<container>_<pod>_<namespace>_<uid>
# 查看日志
docker logs -f <container-id>
# 修改 Pod:直接编辑 YAML,kubelet 自动 apply
vi /etc/kubernetes/manifests/vllm-ascend.yaml
# 删除 Pod:删除 YAML 文件
rm /etc/kubernetes/manifests/vllm-ascend.yaml
# Pod 自动被终止
# 临时停止(保留 YAML,不删除):移走
mv /etc/kubernetes/manifests/vllm-ascend.yaml /tmp/
# 恢复:
mv /tmp/vllm-ascend.yaml /etc/kubernetes/manifests/
7.5 何时用 Kubelet 而非 Docker Compose
| 场景 | 推荐 |
|---|---|
| 单台服务器,手动管理 | Docker Compose |
| 单台服务器,未来可能加 K8s | Kubelet 静态 Pod(迁移到 K8s 零成本) |
| 多台服务器,已有 kubelet | Kubelet 静态 Pod + Ansible 分发 |
| 需要健康检查自动重启 | 两者都支持,Kubelet 更原生 |
| 需要资源声明(CPU/内存) | Kubelet(resources.limits) |
| 已有 K8s 集群 | 直接用 Deployment + Volcano Job |
八、多卡推理(Tensor Parallelism)
# 2 张 NPU 并行
vllm serve /models/DeepSeek-R1 \
--tensor-parallel-size 2 \
--host 0.0.0.0 \
--port 8000
九、支持的模型(v0.20)
vllm-ascend 的模型支持非常丰富,以下是官方文档列出的全部模型:
Qwen3 系列(最全)
| 模型 | 特点 |
|---|---|
| Qwen3-Dense (0.6B/8B/32B) | 纯 Dense 架构 |
| Qwen3-30B-A3B | MoE,30B 参数 3B 激活 |
| Qwen3-235B-A22B | MoE,235B 参数 22B 激活 |
| Qwen3-VL (2B/4B/8B/32B) | 多模态 |
| Qwen3-Coder-30B-A3B | 代码模型 |
| Qwen3-Embedding | 嵌入模型 |
| Qwen3-Reranker | 重排序模型 |
| Qwen3-8B-W4A8 / 32B-W4A4 | 量化模型 |
| Qwen3-Omni-30B-A3B-Thinking | 全模态+推理 |
| Qwen3.5-27B / 397B-A17B | 最新代 |
DeepSeek 系列
| 模型 | 特点 |
|---|---|
| DeepSeek-V3 / V3.1 | MoE 671B |
| DeepSeek-V3.2 | 稀疏注意力 |
| DeepSeek-V4-Flash / V4-Pro | 最新代 |
| DeepSeek-R1 | 推理模型 |
| DeepSeek-OCR-2 | OCR 专用 |
GLM 系列
| 模型 | 特点 |
|---|---|
| GLM-4.5 / 4.6 / 4.7 | 智谱系列 |
| GLM-5 / GLM-5.1 | 最新代 |
Kimi 系列
| 模型 | 特点 |
|---|---|
| Kimi-K2-Thinking | Moonshot |
| Kimi-K2.5 | 最新代 |
其他
| 模型 | 来源 |
|---|---|
| MiniMax-M2.5 | MiniMax |
| PaddleOCR-VL | 百度 OCR |
| Hunyuan-A13B-Instruct | 腾讯混元 |
| Hy3-preview | — |
| Mixtral-8x7B | Mistral |
| gpt-oss-120b | OpenAI |
| Qwen3-ASR-1.7B | 语音识别 |
十、多节点部署
10.1 前置检查
每个节点确认 NPU 可达:
# 获取 NPU IP(-i 填 NPU ID, -c 填 Chip ID)
npu-smi info -t board -i 1 -c 0
# 在输出中找 IP 行
# 跨节点 ping 测试
ping <other-node-npu-ip>
10.2 每节点启动容器
# 节点 1
docker run ... \
-e VLLM_HOST_IP=<node1-ip> \
-e VLLM_PORT=8000 \
-it $IMAGE bash
# 节点 2
docker run ... \
-e VLLM_HOST_IP=<node2-ip> \
-it $IMAGE bash
10.3 多节点 Docker Compose(每节点独立)
每台节点上都放一个精简 compose 文件,只需要映射本地 NPU:
# node1 的 docker-compose.yml(4 卡)
services:
vllm-worker:
image: quay.io/ascend/vllm-ascend:v0.20.2rc1
command: >
vllm serve /models/DeepSeek-V3
--host 0.0.0.0
--port 8000
--tensor-parallel-size 4
--pipeline-parallel-size 2
network_mode: host
# ... devices/volumes 同上单机配置
10.4 多节点通过 Kubelet + Ansible 分发
当你有多台昇腾服务器且都装了 kubelet 时,用 Ansible 统一分发静态 Pod YAML:
# ansible playbook: deploy-vllm.yaml
- hosts: ascend_nodes
tasks:
- name: 复制静态 Pod YAML
copy:
src: files/vllm-ascend.yaml
dest: /etc/kubernetes/manifests/vllm-ascend.yaml
owner: root
mode: "0644"
- name: 等待 Pod Ready
wait_for:
port: 8000
timeout: 300
十一、pip 手动安装(不推荐,仅供了解)
# 1. 准备 CANN 环境
# 用 CANN 预构建镜像
docker run --rm -it quay.io/ascend/cann:9.0.0-910b-ubuntu22.04-py3.11 bash
# 2. 创建虚拟环境
python3 -m venv vllm-ascend-env
source vllm-ascend-env/bin/activate
# 3. 安装 vllm-ascend(自动拉 torch-npu)
pip install vllm-ascend
# 4. 验证
python3 -c "import vllm; print(vllm.__version__)"
注意:pip install vllm-ascend 会自动安装 torch-npu==2.10.0 和 torch==2.10.0,不需要手动装。
十二、和 NVIDIA vLLM 的差异
| 维度 | vLLM (NVIDIA) | vLLM (Ascend) |
|---|---|---|
| 后端 | CUDA | CANN + torch-npu |
| 安装 | pip install vllm | pip install vllm-ascend |
| 启动命令 | vllm serve ... | 完全一样 |
| OpenAI API | 完全兼容 | 完全兼容 |
| 量化 | FP8/FP4/AWQ/GPTQ | W4A8/W4A16(昇腾原生) |
| 模型支持 | 所有 HuggingFace 模型 | 官方适配列表(30+) |
| 镜像源 | Docker Hub | quay.io/ascend |
| Docker Compose | 通用 | 需挂载设备+驱动卷 |
| K8s 调度 | GPU Operator | 设备插件或裸设备挂载 |
十三、和你的现有 AI 基础设施集成
| 你的组件 | vLLM Ascend 的关系 |
|---|---|
| HAMi | HAMi 支持 Ascend NPU 虚拟化,vllm-ascend 可以跑在 HAMi 切分的 vNPU 上 |
| Volcano | vllm-ascend 推理服务可提交为 Volcano Job |
| GPUStack | GPUStack 支持 Ascend NPU,底层可调用 vllm-ascend |
| NVIDIA GPU 集群 | 如果你有 NVIDIA + Ascend 混合集群,vLLM 可以统一 API,后端自适应 |
十四、运维速查
常见命令
# === 宿主机检测 ===
lspci -d 19e5: # PCIe 设备(华为 Vendor ID)
ls /dev/davinci* # 设备文件
npu-smi info # 基础概览(NPU + Chip + Device 三层)
npu-smi info -t memory -i 1 -c 0 # 指定 chip 的显存详情
# === 容器内检测 ===
python3 -c "import torch; print(torch.npu.device_count())"
python3 -c "import torch; print(torch.npu.get_device_name(0))"
# === vLLM 服务 ===
vllm serve <model> --host 0.0.0.0 --port 8000
curl http://localhost:8000/v1/models # 模型列表
curl http://localhost:8000/health # 健康检查
# === Docker ===
docker logs -f vllm-ascend
docker compose logs -f vllm-worker
# === Kubelet ===
curl -s http://localhost:10255/pods | jq
ls /etc/kubernetes/manifests/
常见问题
| 问题 | 原因 | 解决 |
|---|---|---|
/dev/davinci* 不存在 | 驱动未安装/未加载 | 检查 dmesg | grep -i davinci |
npu-smi 报错/无输出 | CANN 未安装或驱动版本不匹配 | cat /usr/local/Ascend/driver/version.info |
libatb.so not found | NNAL 未安装 | 用 CANN 预构建镜像,或手动安装 NNAL |
torch.npu.is_available() = False | 驱动或 CANN 版本不匹配 | 确认 CANN==9.0.0, torch-npu==2.10.0 |
| OOM | 模型太大、batch 太大 | 加 --tensor-parallel-size 或多节点 |
| 镜像拉取慢 | quay.io 国内访问慢 | 提前同步到私有 registry |
| 容器内看不到 NPU | --device 参数遗漏 | 核对 docker run --device /dev/davinci* |
| Kubelet 静态 Pod 不启动 | 格式错误或 kubelet 未运行 | journalctl -u kubelet -f |
自检清单
- 能说清楚 vllm-ascend 的定位(vLLM + CANN 后端,不是新推理引擎)
- 能在服务器上完整检测 NPU 设备(lspci → /dev/davinci* → npu-smi → torch.npu)
- 能用 Docker 启动 vllm-ascend 容器并跑通 Qwen3-0.6B
- 能编写 docker-compose.yml 启动持久化推理服务
- 能编写 Kubelet 静态 Pod YAML 部署 vllm-ascend
- 理解 Ascend 软件栈:CANN ↔ CUDA,torch-npu ↔ torch.cuda
- 知道 vllm-ascend 和 NVIDIA vLLM 命令完全一致,差异在后端
- 能说出昇腾硬件系列(Atlas A2/A3)和对应场景
- 知道多卡推理用
--tensor-parallel-size,命令和 NVIDIA 一致
十五、KV Cache 与并发数
vLLM 启动成功后会打印两行关键日志,直接告诉你这个推理服务能撑多少并发:
(EngineCore pid=190) INFO 07-20 08:33:44 [kv_cache_utils.py:1710] GPU KV cache size: 741,888 tokens
(EngineCore pid=190) INFO 07-20 08:33:44 [kv_cache_utils.py:1711] Maximum concurrency for 8,192 tokens per request: 90.56x
15.1 日志含义
| 日志字段 | 含义 | 说明 |
|---|---|---|
GPU KV cache size: 741,888 tokens | KV Cache 总容量 | GPU 显存中分配给 KV Cache 的 token 总数 |
Maximum concurrency for 8,192 tokens per request: 90.56x | 理论最大并发数 | 每个请求最多 8,192 token 时,能同时处理 ~90 个请求 |
15.2 计算公式
最大并发数 = KV Cache 总容量 / max-model-len
741,888 / 8,192 = 90.56
max-model-len对应启动参数--max-model-len(默认 8192),表示每个请求允许的最大 token 数(prompt + generation)。
15.3 怎样影响并发数
| 调整方向 | 做法 | 效果 |
|---|---|---|
| 提高并发 | 减小 --max-model-len | KV Cache 总容量不变 → 每个请求分到的 token 少 → 并发↑ |
| 降低并发 | 增大 --max-model-len | 每个请求需要更多 token → 并发↓,但能处理更长的上下文 |
| 提高并发 | 增加 GPU 数(TP 扩展) | 总 KV Cache 增大 → 并发↑ |
15.4 实际并发 vs 理论并发
日志中的 90.56x 是理论最大值,实际并发受以下因素影响:
- 请求长度不均:短请求和长请求混在一起,实际分配的 KV Cache 不是平均的
- 前缀缓存(Prefix Caching):相同 system prompt 的请求共享 KV Cache,实际并发可能高于理论值
- 显存碎片:运行一段时间后 KV Cache 可能有碎片,实际可用略低于理论值
监控建议:运行中通过 Prometheus 指标
vllm:gpu_cache_usage_perc和vllm:num_requests_waiting观察实际 KV Cache 使用率和排队情况,不要只看启动日志的理论值。