在这里插入图片描述

最近在昇腾NPU上折腾vllm部署Qwen3大模型,从手动敲命令启动容器,到能打包成镜像在新机器上一键跑起来,踩了不少坑。今天整理个完整流程,分享给有类似需求的朋友,尤其是那些既要保证环境一致,又想省事儿的同学。

先说说背景:为啥要折腾这个?

最开始我在服务器上部署模型,是手动敲一堆docker run命令,挂载设备、映射目录,然后进容器里再启动vllm服务。这一套下来虽然能跑,但有两个大问题:

  1. 换台机器就得重新配一遍,参数多容易错,昇腾的驱动、设备路径稍微不一样就崩
  2. 模型文件好几十个G,总不能每次部署都重新下载吧?

所以就琢磨着:能不能把环境打包成镜像,再用个配置文件管理路径,实现"拷贝文件→改几个路径→一键启动"?试了一圈还真行,下面就是具体步骤。

完整操作流程:从容器到一键部署

第一步:把正在跑的容器"固化"成镜像

我们已经有一个能正常运行的容器(名字叫vllm-ascend),里面装好了vllm环境,也试过启动命令没问题。现在要做的是把这个容器的环境打包成镜像,这样新机器加载镜像就不用重新装依赖了。

操作命令

docker commit vllm-ascend vllm-ascend-custom:v1

这里vllm-ascend-custom:v1是自定义的镜像名,加个版本号方便管理。

划重点

  • 这一步只会打包容器里的环境(比如安装的软件、配置),不会包含挂载的目录内容!像我们挂载的大模型目录/devdata/...,因为是通过-v映射的,本质上存在宿主机,所以镜像大小不会被模型撑大,放心操作。

第二步:写个docker-compose.yml,把启动参数"固定"下来

之前启动容器的命令又长又复杂,设备挂载、目录映射、端口配置一堆参数,记不住也容易输错。用docker-compose可以把这些参数写到配置文件里,一目了然。

在服务器上新建一个docker-compose.yml文件,内容如下(直接抄我的改改就行):

version: '3.8'

services:
  vllm-ascend:
    image: vllm-ascend-custom:v1  # 用我们刚打包的镜像
    container_name: vllm-ascend
    restart: unless-stopped  # 挂了自动重启,省事儿
    ports:
      - "12345:8000"  # 端口映射,外面访问12345就是容器内的8000
    devices:  # 昇腾NPU设备,根据自己机器的设备名改,一般是davinci0到3
      - /dev/davinci0
      - /dev/davinci1
      - /dev/davinci2
      - /dev/davinci3
      - /dev/davinci_manager
      - /dev/devmm_svm
      - /dev/hisi_hdc
    volumes:
      # 下面这些路径用变量代替,方便换机器时修改
      - ${DCMI_PATH}:/usr/local/dcmi
      - ${NPU_SMI_PATH}:/usr/local/bin/npu-smi
      - ${ASCEND_DRIVER_LIB64}:/usr/local/Ascend/driver/lib64/
      - ${ASCEND_DRIVER_VERSION}:/usr/local/Ascend/driver/version.info
      - ${ASCEND_INSTALL_INFO}:/etc/ascend_install.info
      - ${CACHE_PATH}:/root/.cache
      - ${MODEL_PATH}:/models/Qwen3-30B-A3B-Instruct-2507:rw  # 模型路径映射
    command: >  # 容器启动后自动执行vllm服务,不用手动进容器敲了
      vllm serve
      /models/Qwen3-30B-A3B-Instruct-2507
      --served-model-name daosmos
      --host 0.0.0.0
      --port 8000
      --enable-chunked-prefill
      --enable-auto-tool-choice
      --tool-call-parser hermes
      --max-model-len 4096
      --max-num-batched-tokens 4096
      --max-num-seqs 128
      --gpu-memory-utilization 0.7
      --dtype float16
      --tensor-parallel-size 4
      --trust-remote-code
      --block-size 128
      --enable-prefix-caching

第三步:用.env文件管理"可变路径",换机器不头疼

不同服务器的目录结构可能不一样:比如模型可能存在/data/models/,也可能在/opt/models/;昇腾驱动的路径也可能不同。

解决办法是:新建一个.env文件,把所有可能变的路径写成变量,这样换机器时只改这个文件就行。

.env文件内容示例:

# 昇腾驱动和工具的路径,新机器按实际情况填
DCMI_PATH=/usr/local/dcmi
NPU_SMI_PATH=/usr/local/bin/npu-smi
ASCEND_DRIVER_LIB64=/usr/local/Ascend/driver/lib64/
ASCEND_DRIVER_VERSION=/usr/local/Ascend/driver/version.info
ASCEND_INSTALL_INFO=/etc/ascend_install.info

# 缓存路径,随便填个持久化的目录就行
CACHE_PATH=/root/.cache

# 模型在当前服务器的实际路径,重点改这个!
MODEL_PATH=/devdata/Qwen3-30B-A3B-Instruct-2507

注意.env文件要和docker-compose.yml放在同一个目录下,这样docker-compose才能读到变量。

第四步:把镜像传到新服务器,加载使用

镜像做好了,配置文件也写好了,接下来就是迁移到新服务器。

  1. 在原服务器把镜像导出成文件

    docker save -o vllm-ascend-custom.tar vllm-ascend-custom:v1
    

    这会生成一个tar包,大小取决于你的环境(一般几个G,比带模型小多了)。

  2. 传到新服务器
    scp或者U盘拷贝都行,比如:

    scp vllm-ascend-custom.tar 用户名@新服务器IP:/home/用户名/
    
  3. 在新服务器加载镜像

    docker load -i /home/用户名/vllm-ascend-custom.tar
    

第五步:新服务器一键启动服务

  1. 把配置文件传过去
    docker-compose.yml.env也传到新服务器的同一个目录(比如/opt/vllm/)。

  2. 修改.env文件
    根据新服务器的实际情况,改.env里的路径,尤其是MODEL_PATH(模型文件需要你提前拷贝到新服务器,放在这个路径下)。

  3. 启动服务
    进入配置文件所在目录,执行:

    docker-compose up -d  # -d表示后台运行
    
  4. 检查是否启动成功
    看日志有没有报错:

    docker-compose logs -f vllm-ascend
    

    如果看到Uvicorn running on http://0.0.0.0:8000,就说明成了!访问新服务器IP:12345就能调用模型了。

注意要点:这些坑我踩过,你别再掉进去

  1. 设备挂载要对应
    新服务器的昇腾设备名(比如davinci0)必须和docker-compose.yml里写的一致,不然会报"设备不存在"的错。如果新机器只有2张卡,就删掉后面的davinci2davinci3,同时把--tensor-parallel-size改成2。

  2. 模型必须单独拷贝
    镜像里没有模型,新服务器必须有完整的模型文件,且路径和.env里的MODEL_PATH一致,不然vllm会报"找不到模型文件"。

  3. 驱动版本要匹配
    新服务器的昇腾驱动版本最好和原服务器一致,不然可能出现"库不兼容"的错误(比如libascendcl.so找不到)。

  4. 端口别冲突
    如果新服务器的12345端口被占用了,改docker-compose.yml里的12345:8000,比如换成12346:8000

常见错误及解决办法

  1. 启动时报"device not found"
    → 检查docker-compose.yml里的devices列表,是不是和新服务器的/dev/目录下的昇腾设备名一致(用ls /dev/davinci*查看)。

  2. vllm启动时报"model not found"
    → 先看容器内的模型路径对不对:docker exec -it vllm-ascend ls /models/Qwen3-30B-A3B-Instruct-2507,如果是空的,说明MODEL_PATH挂载错了,重新核对.env里的路径。

  3. 日志里有"libxxx.so: cannot open shared object file"
    → 昇腾驱动或工具的路径没挂载对,检查.env里的ASCEND_DRIVER_LIB64等变量,确保宿主机的这些路径下有对应的库文件。

  4. 容器启动后立刻退出
    → 大概率是command里的vllm命令写错了,比如参数拼写错误。可以先把docker-compose.yml里的command注释掉,手动进容器(docker-compose exec vllm-ascend bash),在里面敲vllm命令调试,成功后再更新配置文件。

最后总结

这套流程的核心就是:用docker commit固化环境,用docker-compose+.env管理变量,既保证了环境一致性,又解决了不同机器路径不一样的问题。

现在我换机器部署,只需要三步:传镜像、传配置文件、改.env路径,比之前手动敲命令快多了。如果你也在折腾昇腾上的大模型部署,希望这篇分享能帮你少走点弯路~ 有问题欢迎留言交流!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐