直接开始写正文。
接手过几台华为昇腾服务器之后,你会发现一个很现实的问题:硬件算力是摆在那了,但怎么把它高效地管起来、用起来,尤其是同时跑多个大模型推理任务时,资源调度、任务分配、API接口管理全都挤在一起,瞬间就手忙脚乱。
GPUStack 这个名字在 GPU 集群管理圈子里已经不陌生,它本质上是一套开源的 GPU 资源管理和推理服务平台,能把分散的显卡统一纳管,提供推理 API 输出和 Web 界面管理。而昇腾 IA 服务器这边,卡是国产自研的,跑 MindIE、MindSpore 这套生态,和 NVIDIA 的 CUDA 体系完全不是一个路子。问题就来了:GPUStack 能不能管昇腾卡?能。但中间有相当多的细节要处理,从驱动、固件、容器运行时到 GPUStack 的配置,每一步都埋着坑。
这篇就是一份完整的保姆级部署实录,基于我自己在某单位昇腾服务器上从零到一跑通 GPUStack 的过程整理出来的。看完你不用再翻一堆官方文档拼凑步骤,跟着抄就行。
1. 部署前先把账算清:为什么是 GPUStack 加昇腾的组合
先说清楚 GPUStack 到底解决了什么问题。过去在昇腾服务器上部署 AI 应用,最头疼的是两件事:第一,卡是固定的,人和任务却是动态的,今天 A 项目要一张卡,明天 B 项目也要一张卡,完全靠人工分配,谁也说不清当前哪张卡还有余量;第二,应用之间没有隔离和统一入口,每个模型都要单独暴露端口、单独管理地址,测试环境乱成一锅粥。
GPUStack 的定位就是一个“GPU 资源管理器 + 推理服务网关”。你先把服务器上的昇腾卡纳管进来,然后在平台上创建推理实例,平台自动帮你分配卡、启动容器、暴露统一 API 接口。调整模型版本、扩容副本、查看日志,全部在一个界面上完成。这套东西跑在 NVIDIA 生态上已经很成熟,模块化设计让昇腾后端也能被识别和调度。
昇腾这边的情况稍微特殊一点。昇腾卡不是通过 CUDA 暴露给上层的,而是通过昇腾自己的驱动和 CANN 工具包,配合 Ascend Docker Runtime 在容器里挂载 /dev/davinci0 这类设备节点。GPUStack 本身不会直接操作底层驱动,它是靠容器技术把业务跑起来的,所以只要你把昇腾的容器运行时配好,剩下的就交给 GPUStack 去创建 Pod、调度资源。
适合看这篇内容的读者很明确:手里有昇腾服务器,想搭一套统一的大模型推理管理平台;或者已经在别处用过 GPUStack,现在想把昇腾资源也并进来一起管。不过要提前打个预防针——昇腾这块官方文档分散,版本匹配问题特别多,我实测过程中踩坑次数远超部署本身。
2. 环境准备:硬件、软件和版本匹配清单
2.1 硬件配置与系统版本核查
部署的前提是硬件本身能正常跑起来。昇腾 IA 服务器通常配的是 Atlas 系列的加速卡,训练卡还是推理卡无所谓,GPUStack 都能管,但建议先把卡跑通一个基础推理样例,确认硬件是好的再往上搭平台。
我在实际操作中的硬件环境是这样的:一台昇腾服务器,8 张 Atlas 推理卡,每张卡显存 24GB 左右,CPU 是 ARM 架构的鲲鹏处理器,内存 512GB。需要特别提醒,昇腾服务器很多是 ARM CPU,这会影响部分软件包的下载源选择,后面装 Python 和编译依赖时得留心。
操作系统建议用 Ubuntu 20.04 或 22.04 LTS,或者兼容的 openEuler 系列。GPUStack 官方对 Linux 的兼容性还是不错的,但你要是用 CentOS 7 这种老系统,容器里的依赖版本会卡得很死,建议直接上新一点的系统。
上机后先做三件事:
bash uname -a # 查看系统内核和架构 lscpu | grep Architecture # 确认是 ARM 还是 x86 npu-smi info # 查看昇腾卡状态,确认所有卡都被驱动正常识别
npu-smi info 的输出里每个卡应该显示正常状态,温度和功耗都有数值,如果显示“No devices”或者一堆错误码,先别急着装 GPUStack,修驱动去吧。
2.2 软件版本匹配是这场的核心战场
昇腾生态里最痛的就是版本匹配。驱动、固件、CANN 工具包、Ascend Docker Runtime、容器引擎,五样东西版本之间是有对应关系的,装错一个,轻则 NPU 设备在容器里识别不到,重则驱动直接起不来。
我自己用的这套版本组合,实测下来是比较稳的:
| 组件 | 版本选择 | 说明 |
|---|---|---|
| 操作系统 | Ubuntu 22.04 LTS | 长期支持,兼容性最好 |
| 昇腾驱动 | 对应 CANN 8.0.R1 的配套驱动 | 与固件版本一一匹配 |
| 昇腾固件 | 与驱动配套的固件包 | 升级驱动时必须同时升级固件 |
| CANN 工具包 | Ascend-cann-toolkit 8.0.R1 | 提供运行环境和算子库 |
| Ascend Docker Runtime | 22.0.0 以上版本 | 容器内映射 NPU 设备的关键 |
| Docker Engine | 24.x 以上 | 老版本对 runtime 支持不友好 |
| GPUStack | 0.3 以上版本 | 已经开始支持昇腾后端 |
版本这块的核心理念:一切以昇腾官方提供的配套关系表为准。驱动和固件是强绑定关系,驱动升级固件不升,板卡直接报错;CANN 版本又决定上层运行时能不能识别卡。我见过有人卡在“容器里看不到 NPU 设备”查了一整天,最后发现是驱动装好了但固件还是半年前的版本。
2.3 网络与存储规划
GPUStack 架构里有一个主节点和若干个 worker 节点(这里 worker 就是装昇腾卡的服务器)。主节点需要跑 MySQL、日志服务这些基础组件,worker 节点负责实际执行推理任务。组件之间有通信需求,网络得规划到位。
部署前确认这几件事:
- 主节点与 worker 节点之间网络互通,推荐万兆网,因为模型文件动辄几十 GB,传模型时千兆网太折磨人
- 模型存储建议单独挂一个共享存储(NFS 或者对象存储都行),这样多台 worker 可以共享同一个模型仓库,不然每台服务器都得单独拷一份模型,磁盘浪费严重
- GPUStack 需要开放的端口主要是 80(Web 界面和 API)和 443(HTTPS,可配可不配),内网环境直接 HTTP 也没问题
存储这块我多说一句。我一开始图省事,直接把模型放在 worker 本地磁盘,后来创建第二个推理实例时,发现另一台 worker 上没有模型,被迫做了共享存储的迁移,白折腾了半天。如果你有多台昇腾服务器要纳管,别犹豫,提前把 NFS 挂好。
3. 昇腾基础环境:驱动、固件和容器运行时的一次到位配置
3.1 驱动和固件安装的实际操作
安装顺序极其重要:先装固件,再装驱动,最后装 CANN 工具包。顺序反了会报依赖错误,而且大概率要重装系统才能清理干净。
在昇腾官网下载对应型号的固件包和驱动包,通常以 .run 文件形式提供。用 root 身份执行:
bash
安装固件,整个过程大概 3-5 分钟
./Ascend-firmware-xxx.run --full --quiet
安装驱动
./Ascend-driver-xxx.run --full --quiet
验证安装
npu-smi info
安装完成后重启系统,再执行 npu-smi info 确认所有卡都回到正常状态。这一步没通过的话,后面什么都别谈,先解决驱动问题。
重点提醒:安装驱动时加上 --full 参数,只装默认那一小部分很容易漏掉关键组件。另外,安装日志保存在 /var/log/ascend 目录下,真出问题时里面的 install.log 和 dmesg 输出是最直接的排查线索。
3.2 Ascend Docker Runtime 的接入逻辑
GPUStack 要调度昇腾卡,靠的是容器里的 NPU 设备映射。裸机上的驱动识别到的是 /dev/davinci0、/dev/davinci1 这类设备节点,但这些节点必须通过容器运行时挂载进容器里,容器里的进程才能访问 NPU 资源。
Ascend Docker Runtime 就是干这个的。装好之后,Docker 会多一个 runtime 选择,你在跑容器时指定 --runtime ascened 或者加 --device 参数,设备节点就会被自动注入。
安装 Ascend Docker Runtime 的常规路径:下载对应 .run 安装包,执行安装,然后确认 Docker 的 daemon.json 里已经注册了这个 runtime。检查命令:
bash docker info | grep -i runtime
正常情况应该能看到 ascend 运行时出现在列表里。如果看不到,手动去改 /etc/docker/daemon.json,加一个 runtime 配置,然后重启 Docker:
json { "runtimes": { "ascend": { "path": "/usr/local/Ascend/Ascend-Docker-Runtime/ascend-docker-runtime" } } }
改完执行 systemctl restart docker,再用 docker info 验证。
3.3 验证 NPU 设备能进入容器
到这一步可以先手动试一下容器能不能访问 NPU,这能帮你提前暴露八成的问题:
bash docker run --rm --device=/dev/davinci0
-v /usr/local/Ascend/driver:/usr/local/Ascend/driver
-v /usr/local/Ascend/driver/lib64:/usr/local/Ascend/driver/lib64
-it ascend-byoc:22.0.0 bash
进入容器后执行 ls /dev/davinci*,能看到 davinci0 存在基本就成功了。可以进一步跑一个基础的 CANN 样例程序,确认容器里真的能调用 NPU 做算子计算。确认无误后,昇腾这一层的基础环境就算彻底打通了。
我的经验是:务必用“容器能否访问 NPU”作为基础环境的验收标准,而不是看裸机驱动显示正常就觉得万事大吉。GPUStack 实际跑业务时就是在容器里跑的,提前把这层打牢,后面能省出一整天的排查时间。
4. GPUStack 主程序部署与昇腾节点接入
4.1 主节点的安装与初始化
昇腾基础环境准备好之后,开始装 GPUStack。GPUStack 官方提供了一键安装脚本,但我不建议你无脑执行——先理解一下它的组件构成:GPUStack 主程序、数据库、日志组件,以及用于控制和数据面的 Agent。安装脚本会在主节点上把这些东西都装好。
在作为主节点的服务器上执行:
bash
GPUStack 官方提供的一键安装脚本
curl -sfL https://get.gpustack.com | sh
装完后 GPUStack 默认监听 80 端口,浏览器打开服务器的 IP 地址,首次访问会要求创建一个管理员账号。这个账号密码要好好保存,后续所有节点纳管、模型下发都得靠它。
有一点要特别说明,GPUStack 安装脚本执行时间不短,可能接近十分钟,期间会拉取容器镜像。如果服务器能访问公共镜像仓库自然没问题,但在某些内网环境里,你可能需要提前配置好镜像加速或者离线镜像导入。别等到脚本卡住才去看日志,直接先确认 Docker pull 能不能拉到镜像。
4.2 Worker 节点怎么加入:证书与 token 的关系
GPUStack 的实现里,主节点装完后是一个单体模式,它本身就能作为第一个 worker 调度任务。你要纳管其他昇腾服务器,标准做法是拿到主节点的接入地址和 token,然后在目标服务器上执行加入命令。
在 Web 界面的“节点”页面里,GPUStack 会展示一条加入命令,形式大致是:
bash curl -sfL https://你的主节点IP:端口/install.sh | sh -s - --token xxx --worker
把这条命令在昇腾服务器上执行,它就会自动安装 GPUStack 的 worker 组件,并且向主节点发起注册。注册成功后,主节点界面上能看到这台机器,并且能识别出它上面挂的昇腾卡。
这里有个极易踩坑的点:worker 加入时 GPUStack 默认会尝试用 TLS 连接主节点,如果你的主节点用的是自签名证书,worker 加入时会有证书校验失败的问题。解决办法是在加入命令里加上 --insecure 参数跳过校验。内网环境这是很常规的操作。
4.3 GPUStack 识别昇腾卡的机制细节
主节点和 worker 之间通信建立后,GPUStack 会去枚举 worker 上的 GPU 资源。对 NVIDIA 卡它直接调 nvidia-smi,对昇腾卡它走的是看设备节点和 Ascend Runtime 探测的逻辑。
我这边实测下来的结果是:GPUStack 识别昇腾卡并不要求你在 worker 上预装任何 GPUStack 专用驱动,它依赖的是已经装好的 Ascend Docker Runtime。也就是说,只要 worker 上 Docker 能看到 davinci 设备,GPUStack 就能把它盘点成可调度的卡,并展示卡名、显存、健康状况这些信息。
所以你在节点页面上看到昇腾卡的状态之后,先别急着创建推理实例,把每张卡的显存容量记下来,后面填写 GPU 资源分配和模型显存预估参数时要用。
4.4 昇腾后端推理引擎的配置
GPUStack 支持多种推理引擎后端,对昇腾卡来说主流选择是 MindIE。GPUStack 在创建添加模型时,有个参数让你指定 Runtime 或推理引擎,选 MindIE 后它会拉起 MindIE 容器镜像,把 NPU 设备挂进去,然后启动 vLLM 兼容的推理服务。
这里的关键是镜像选择。GPUStack 官方或社区通常提供已经打好 MindIE 环境的基础镜像,你需要把它在 worker 节点上提前拉下来。镜像版本必须和昇腾卡驱动版本配套,不然容器起来后卡上算子无法加载,推理时一直报错。选型建议:如果你同时有昇腾 310 和 910 的卡,优先按卡型号选对应镜像,不要用一个大而全的镜像去打天下。
5. 在昇腾上跑通第一个大模型推理服务
5.1 创建推理实例的操作步骤
确保 GPUStack 界面里能看到昇腾卡的列表之后,开始创建第一个推理实例。进入“模型”页面,点击添加模型,填写:
- 模型名称,自己起个容易认的名字
- 模型来源,支持从本地路径上传,也支持指向一个模型仓库地址
- 推理引擎选 MindIE
- GPU 选择界面里显示的某一张昇腾卡
- 显存和并发参数按实际情况填
GPUStack 会自动完成拉取镜像(如果你指定了镜像地址)、启动容器、挂载 NPU、启动推理服务这几个动作。创建过程会有日志输出,可以实时观察容器启动情况。我第一次创建时在“拉取镜像”这一步卡了很久,后来发现是镜像仓库的网络带宽问题,把镜像先手动 docker pull 到本地就好了。
创建完成后,GPUStack 会给这个模型生成一个 API 访问地址,格式类似于 http://主节点IP:端口/v1/chat/completions。这个地址就是统一推理入口,后续你任何应用只需要对接这个 IP 和 key,不用关心背后跑在哪个 worker 的哪张卡上。
5.2 验证推理服务的完整性
实例创建成功后,用 curl 直接测试一下推理是否能真正跑通:
bash curl http://主节点IP:端口/v1/chat/completions
-H "Content-Type: application/json"
-H "Authorization: Bearer 你的APIKey"
-d '{ "model": "你的模型名", "messages": [{"role": "user", "content": "你好,介绍一下你自己"}], "max_tokens": 200 }'
正常情况下,GPUStack 会通过昇腾卡上的 MindIE 引擎返回完整的回复内容。测试返回有内容后,再看一眼 GPUStack 界面上模型的状态、显存使用、请求日志,确认整体链路是通的。
这步通过,你的 GPUStack 和昇腾的集成就算正式跑通了,可以开始把业务迁过来。
5.3 推理服务的高可用与资源配额设置
跑通一个模型只是开始。如果服务器上有多张昇腾卡,建议你把 GPUStack 的高可用特性用起来:创建推理实例时勾选多个 worker 或多张卡,GPUStack 会做副本调度。某张卡故障时,它能把请求切到其他副本上,避免单点故障影响整个推理链路。
资源配额这点容易被忽略。GPUStack 允许你对不同的 API Key 设置不同的资源池,比如给项目 A 分配 2 张卡,给项目 B 分配 4 张卡。这个功能的实际价值在于:团队里不同的部门可以各自管理自己的模型资源,不会出现某个项目把全部显存占满、其他项目无卡可用的局面。配额设置页面在“设置 — 资源池”里,按需创建即可。
我建议你在正式上线之前,把模型加载方式、并发上限、超时时间这些参数在测试环境多压几轮,再对着 GPUStack 的指标监控看卡的利用率。昇腾卡的计算特性决定了它在长 prompt 场景下比短 prompt 更吃显存,参数需要反复调优才能找到最合适的值。
6. 常见问题与排查实录
6.1 容器里看不到 NPU 设备
这是我被问得最多的问题。排查思路从下往上:
- 裸机执行 npu-smi info 看卡是否正常,报错的话是驱动/固件问题
- 执行 docker info | grep runtime,看 Ascend runtime 是否注册成功
- 手动 docker run 挂载 /dev/davinci0 进容器,看设备节点是否存在
- 检查容器内的驱动库是否和宿主驱动匹配,常见错误是容器内缺 libascend_install.so 之类
这套流程走下来,基本能定位到是在驱动层、runtime 层还是容器层出了问题。大多数情况下,问题出在 Ascend Docker Runtime 的版本和驱动版本不配套,卸载重装对应版本就能解决。
6.2 推理服务启动后立即退出,没有任何错误日志
这个坑挺隐蔽。GPUStack 拉起容器时,如果传入的模型路径在 worker 上不存在或者没有权限读取,MindIE 启动时就会直接退出。但因为日志收集有延迟,界面上可能看不到具体报错。
解决方法是直接到 worker 节点上手动执行 docker logs 看容器退出前的输出,或者挂载目录后自己启动一次 MindIE 推理服务,把环境变量里的路径用绝对路径重新填写一遍。另外,如果使用共享存储,注意各 worker 对同一路径的权限要一致,某些 NFS 挂载默认只读不改配置的话,模型权重文件可能根本写不进去。
6.3 GPUStack 界面显示昇腾卡显存为 0 或状态异常
这种问题多数是 GPUStack 枚举硬件信息时没走 Ascend 的接口,转而走了默认的 NVIDIA 检查逻辑。解决办法是确认 worker 节点的 GPUStack 版本够新,并且在 worker 安装时显式声明了昇腾支持相关的环境变量。
如果版本已经是最新但界面还是显示异常,建议重新执行 worker 加入命令,并在加入后手动重启一次 GPUStack 的 worker 服务。实测中这个操作能刷新大部分硬件信息缓存。
6.4 可以一次性避开的部署习惯
整理几个我吃过亏之后的经验:
- 先把昇腾驱动、固件、CANN、Ascend Docker Runtime 全部装好并验证通过,再装 GPUStack,顺序颠倒会导致 GPUStack 枚举失败
- 所有 worker 节点保持相同的软件版本,昇腾环境版本不一致时,模型可能在节点 A 上正常、节点 B 上直接起不来
- 模型文件放共享存储,不要放本地,不然每次新建实例都要重新拷贝模型,太耗时
- 定期检查 npu-smi info 的输出,昇腾卡在运行久了之后可能因为散热或者固件老化出现性能下降,提前发现能避免线上事故
6.5 一张实用的排查速查表
| 现象 | 首选排查命令 | 大概率原因 |
|---|---|---|
| 裸机看不到卡 | npu-smi info,dmesg | 驱动或固件未正确安装 |
| 容器内无 davinci 设备 | ls /dev/davinci* | Ascend Docker Runtime 未生效 |
| 推理实例创建超时 | docker logs 相应容器 | 镜像拉取失败或模型路径错误 |
| GPUStack 界面识别不到卡 | worker 的服务日志 | 版本过旧或注册信息异常 |
| MindIE 推理报算子错误 | 查看 CANN 版本与驱动版本 | 版本不配套,需要统一升级 |
7. 收尾补一段:这套方案还能怎么延伸
把 GPUStack 和昇腾这一套打完之后,后面可以扩展的空间其实还很大。比如把 GPUStack 的 API 对接到你团队内部的模型管理平台,让业务方通过标准 OpenAI 风格接口调用昇腾推理能力;再比如结合 GPUStack 的多租户能力,给每个项目组分配独立的资源和密钥,审计和计量都能做得比较细。
我对这套组合的理解是:昇腾卡本身算力不差,真正缺的是好用的资源管理软件。GPUStack 恰好补上了这一块。而且它是开源项目,社区更新活跃,昇腾的支持也是一步一步磨出来的。
当然,昇腾生态的成熟度相比 NVIDIA 还是差了不止一个身位。驱动版本乱、文档分散、社区样本少这些问题真实存在。如果你是一次性部署而且环境比较简单,照着这篇走基本几天能搞定;如果环境复杂、版本交叉多,建议先在测试机把整套流程完整走一遍,再上生产,别一上来就动真格的。
整个过程最费时间的不是命令本身,而是各个组件之间的版本匹配和调试。把这篇文章的步骤保存下来,按顺序操作,每一步验证过了再走下一步,大概率能少踩一半的坑。我部署时前前后后花了一周,你要理解了原理再动手,速度会快得多。