← 返回文章列表

技嘉DGX Spark GB10 (AI TOP ATOM) 双机部署DeepSeek与踩坑

多的不少,少的不唠,本地部署大模型,现在就开搞

物料准备

  • 主机:2 x 技嘉DGX Spark GB 10 (或者叫AI ATOM ATOM)
  • 线缆/模块:1 x Connect X7 支持的高速线 / 2 x QSFP56/QSFP112光模块(单模多模都行) + 对应的高速线
  • 外设:鼠标 + 键盘 + 显示器: 鼠标键盘最好支持typec直连,因为dgx spark只有三个usbc口,没有usba口,可以用usbc hub但有可能不兼容
  • 1 x typec u盘 (optional): 用于恢复
  • 1 x 小交换机一个 + 网线若干条 (optional): 用于ssh同时连接两台进行操作
  • 电源线 + 网线 + hdmi线若干条

总之,机器还是挺漂亮的,但是他没有usba口,全c的配置在装机初期非常反人类,鼠标键盘最好要支持typec直连,因为在进bios之前可能读不到,务必准备好能被uefi正常识别的c口输入设备。

系统安装

这套 ARM 架构的硬件和系统环境比较新,初始化过程中大概率会遇到各种玄学问题

安装失败怎么恢复

什么,你说系统安装的时候Kernel Panic了!!!

总之,在部署第一台的时候就遇到了在setup界面就kernel panic的情况,如下是情况复现

场景还原

  1. 第一次启动进入界面,插入鼠标键盘,连接好网络,开始设置系统前的第一次更新
  2. 进度条跑完,自动重启
  3. Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
  4. 手动重启后Shift + Insert无法进入grub页面

修复方案

我这边选择的是直接重装,因为机器都还没初始化完成,也没什么需要保留的东西,所以直接重装感觉简单一点。

当然,如果你已经如果已经放了模型和数据,然后你不想重装,你可以尝试用usb live system尝试修复引导,我这里就不展开讲了

技嘉官方给AI TOP ATOM提供了专用的DGX OS recovery image,所以我们可以直接用启动盘修复,不需要用 Live CD 手动修复了,还是比较方便的。

可以先去GIGABYTE-AI-TOP-ATOM support下载恢复镜像DGXOS-Spark-Gigabyte-GA1.2.1-OTA1.1-RC,找最新的即可

然后写入u盘

# 查看你的u盘位置,按照你真实的u盘地址来,不要写错了
lsblk
# unmount
sudo umount /dev/sda?* 2>/dev/null
# 写入
sudo dd if="你的DGX_OS.iso" of=/dev/sda bs=4M status=progress conv=fsync
# sync
sync

进入bios, 按住Del, 注意是按住, 开机时进入BIOS/UEFI。

按住 Del
→ 再按电源键
→ Del 一直按住

注意这个时候需要最好用普通键盘,然后直连usbc口,不要走usbc hub不然可能检测不到键盘导致进不了bios。

开机 Del → BIOS → Save & Exit → Boot Override,选择你的u盘

出现三个选项, 选dgx spark installtion options

- DGX Spark Installation Options
- Boot from next volume
- UEFI Firmware Settings\

选择完成之后又会出现几个选项,这里就直接选Install DGX OS 7.3.1 for DGX Spark

- Install DGX OS 7.3.1 for DGX Spark
- Install DGX OS 7.3.1 for DGX Spark without NVIDIA drivers for DGX Spark
- Advanced Installation Options
- Boot Into Secure Shell
- Check Media for Defects

选择完成之后,他就会进去直接进入了一个ubuntu server,并直接开始安装了

这个是正常的,屏幕上应该会一直跳命令,或者在 apt-get install 卡一会。

等待他自动重启几次之后,就可以正常进入setup界面了

可能原因

可以参考这篇在nvidia官方论坛上的帖子。

帖子里的情况是更新把新kernel装进去了,但是DKMS的post-install hook失败了,后面的initramfs生成步骤没跑到。

感觉好像和我的挺像的,因为之前在另外一个机器上,在运行apt upgrade的时候也遇到了这个问题,就是直接post install fail了,所以我才这台机器可能在初始setup的时候也遇到了相同问题,导致机器直接panic了。

结果就是有vmlinuz,没有对应的 initrd.img,重启后kernel找不到根文件系统,于是直接 panic。

总之这b硬件和软件还是挺新的,遇到什么问题都不奇怪了只能说是

进入安装界面后黑屏

什么情况,进入初始化界面之后我连接wifi之后他直接黑屏了

故障现象

  1. 开始设置系统前的第一次更新
  2. 连接wifi
  3. 直接黑屏,除了鼠标能动就不行

简单来说就是在第一次setup的界面里,在连接wifi之后,系统直接黑屏,按Ctrl + Alt + F3直接显示GIGABYTE标识,没有别的内容了

除了鼠标能动,其他全是黑的,因为正常安装的会有更新条,现在没了所以我能100% 确认出现了问题

解决方案

最后的解决方案也是参考nvidia论坛里的帖子。

我们可以手动重启一次,按如下键重启

Ctrl + Alt + Delete

重启之后一般能恢复下载与安装系统更新了

nvidia-smi has failed

可恶,怎么还有问题啊

这个其实是其中一台机器在我手动运行DGX Dashboard里的update后出现的问题。

就是在DGX Dashboard里面运行更新后,执行 nvidia-smi 报错:

NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver.

查了一圈,感觉是驱动出了问题,但是也没搞明白到底那里出了问题

sudo modprobe nvidia
modprobe: ERROR: could not insert 'nvidia': Key was rejected by service

总之最后的解决办法是移除 nvidia-dkms-580-open,换回oem系统提供的预编译签名模块。

# 最后那个包名结尾的 `-` 是让 apt 移除它,
sudo apt install --allow-downgrades \
  nvidia-driver-580-open/noble-updates \
  linux-modules-nvidia-580-open-nvidia-hwe-24.04/noble-updates \
  nvidia-dkms-580-open-
# 确认安装成功后再重启
sudo reboot

你看到这篇文章的时候可能已经有别的系统更新了,不一定需要完全按照我的方案来。

部署前准备

部署的时候的机器状态如下:

正常来说,应该能跑nvidia-smi -L,并且能看到NVIDIA GB10。

连接connectx7网络,验证网络连接成功

我这里用一个普通交换机,然后用普通网口连接两台dgx spark和我的电脑,这样我就可以ssh上去管理,不然要来回在两台机器间输命令有点麻烦

另外一根高速线直连两台Spark,模型之间的通信走ConnectX-7。大概就是这样:

笔记本 ── 普通交换机 ── dgx1 管理口
                    └── dgx2 管理口

dgx1 ConnectX-7 ═══════ dgx2 ConnectX-7

然后就是配置网络了,我用的配置如下

实际网卡名可以先用 ip -br addr 和 rdma link show查看

用途dgx1 / headdgx2 / worker
管理口 enP7s7192.168.16.10/24192.168.16.11/24
高速接口 enp1s0f1np1192.168.100.10/24192.168.100.11/24
另一高速接口 enP2p1s0f1np1192.168.101.10/24192.168.101.11/24
本次推理使用的 HCArocep1s0f1rocep1s0f1

两台都是用的默认的NetworkManager管理网络,简单点可以在gnome的网络设置里选对应的高速接口,IPv4改成手动,填地址和 /24,网关留空不填。

用命令的话,先用 nmcli connection show 找连接名,然后用如下命令配置ip。

# dgx1 (Head节点)
sudo nmcli connection modify 'Wired connection 5' \
  ipv4.method manual ipv4.addresses 192.168.100.10/24 \
  ipv4.gateway '' ipv4.never-default yes connection.autoconnect yes
sudo nmcli connection up 'Wired connection 5'
# dgx2 (Worker节点)
sudo nmcli connection modify 'Wired connection 5' \
  ipv4.method manual ipv4.addresses 192.168.100.11/24 \
  ipv4.gateway '' ipv4.never-default yes connection.autoconnect yes
sudo nmcli connection up 'Wired connection 5'

再从dgx1看一下实际走的路由,顺便测试一下能不能ping通

ip route get 192.168.100.11
ping -c 3 -I enp1s0f1np1 192.168.100.11
rdma link show

配置节点间ssh免密

当然除了配置网络,还要配置dgx1到dgx2的免密ssh连接,因为启动脚本会从 head 连 worker,同步文件和启动容器,所以在 dgx1 上也要配好公钥。

# 在 dgx1 上执行
# 如果还没有密钥,先生成
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519
# 复制公钥
ssh-copy-id username@192.168.100.11
# 验证无密码登录
ssh -o BatchMode=yes username@192.168.100.11 hostname

这里最好使用高速网的ip,这样后面就算拔掉普通网线,head仍然能找到worker

Docker 与 NVIDIA Runtime 配置

OEM的DGX OS预装了 Docker 和 Toolkit,所以不需要额外安装,两台机器只需确保将把NVIDIA runtime配进Docker就ok了。

你可以在两台上运行如下命令完成nvidia runtime的安装,

# sanity check
docker version
docker compose version
nvidia-ctk --version
# 安装
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

如果 nvidia-ctk 不存在,先按 NVIDIA Container Toolkit 的安装文档安装

配置docker sudo权限

另外,后面的启动脚本用普通用户调用docker,所以两台对应用户都要有docker权限。所以你需要把用户加进了docker组,然后重新登录,让组权限生效

sudo usermod -aG docker "$USER"

下载必要内容

这里其实没啥,我这里选择了MiaAI-Lab的部署方式,部署前需要准备好Docker镜像并下载 DeepSeek,我这里下载了DeepSeek Vision-Exp这个模型。

docker镜像拉取

先安装运行镜像,分别在两台都拉同一个版本

# 拉取
docker pull --platform linux/arm64 ghcr.io/anemll/dspark-vllm-gx10:0.1.1
# 测试,可以不跑
docker run --rm --gpus all --entrypoint nvidia-smi \
  ghcr.io/anemll/dspark-vllm-gx10:0.1.1

当然你也可以拉完之后手动传输load,比如dgx1已经拉好了linux/arm64 镜像,用可以用docker save导出,传给 dgx2,再用docker load导入

docker save --platform linux/arm64 -o ~/dspark-arm64.tar \
  ghcr.io/anemll/dspark-vllm-gx10:0.1.1
scp ~/dspark-arm64.tar username@192.168.100.11:~/
ssh username@192.168.100.11 'docker load -i ~/dspark-arm64.tar'

模型拉取

模型可以用Hugging Face CLI 下到自己的目录。国内可以在ModelScope/DeepSeek-V4-Flash-Vision-Exp拉取,下面两种方式选一种就行。

假设已经有 uv,两台分别下载:

mkdir -p ~/models/DeepSeek-V4-Flash-Vision-Exp
uvx --from huggingface_hub hf download \
  deepseek-ai/DeepSeek-V4-Flash-Vision-Exp \
  --local-dir ~/models/DeepSeek-V4-Flash-Vision-Exp

用 ModelScope CLI 的话,还是用 uv:

mkdir -p ~/models/DeepSeek-V4-Flash-Vision-Exp
uvx --from modelscope modelscope download \
  --model deepseek-ai/DeepSeek-V4-Flash-Vision-Exp \
  --local_dir ~/models/DeepSeek-V4-Flash-Vision-Exp

也可以一台下载完再复制给另一台,

比如dgx1已经下载好了,就在dgx1上用rsync通过高速网复制过去,利用ConnectX-7跑直接跑满200gb/s带宽

ssh username@192.168.100.11 'mkdir -p ~/models/DeepSeek-V4-Flash-Vision-Exp'
rsync -a --partial --info=progress2 \
  ~/models/DeepSeek-V4-Flash-Vision-Exp/ \
  username@192.168.100.11:/home/username/models/DeepSeek-V4-Flash-Vision-Exp/

MiaAI Lab的部署脚本

最后是部署脚本,在dgx1上准备

mkdir -p ~/dspark-deploy
git clone https://github.com/MiaAI-Lab/DeepSeek-v4-Flash-DSpark-2x-DGX-Spark.git \
  ~/dspark-deploy/recipe
cd ~/dspark-deploy/recipe
# 总之看你,我这里用的是这个git hash的版本,你可以直接用最新的
git checkout 97e8733238f81f5fdc44b241f8996a7858825744
cp .env.dspark.example .env.dspark

worker的运行文件会由head的启动脚本同步。两台本地再准备一下运行缓存目录:

mkdir -p ~/.cache/huggingface

开始部署

我们用了MiaAI-Lab 的方案,所以部署方案还是比较简单的。

主要就是改配置,然后在 head 上跑启动脚本。下面是我的 .env.dspark 里需要关注的部分,改原有的对应项,其余保留示例文件的配置,用户名、路径和 IP 按自己的换:

# head 通过高速网登录 worker
WORKER_HOST=username@192.168.100.11
WORKER_DIR=/home/username/dspark-deploy/recipe

# 双机推理通信
MASTER_ADDR=192.168.100.10
VLLM_HOST_IP=192.168.100.10
WORKER_VLLM_HOST_IP=192.168.100.11
NCCL_IB_HCA=rocep1s0f1
NCCL_SOCKET_IFNAME=enp1s0f1np1
TP_SOCKET_IFNAME=enp1s0f1np1
GLOO_SOCKET_IFNAME=enp1s0f1np1
NCCL_NET=IB

# 两台各用自己的权重和缓存
HF_CACHE=/home/username/.cache/huggingface
WORKER_HF_CACHE=/home/username/.cache/huggingface
DSPARK_WORKER_HF_NFS=0
# 运行时直接使用已下载好的文件,不再联网查询
HF_HUB_OFFLINE=1
# 这个也是
TRANSFORMERS_OFFLINE=1
DSPARK_VLLM_IMAGE=ghcr.io/anemll/dspark-vllm-gx10:0.1.1
DSPARK_MODEL_OFFICIAL=/models/deepseek-v4-flash-vision-exp
# 留空,因为已经有了本地路径
DSPARK_REVISION=
DSPARK_ENCODING_FILE=/models/deepseek-v4-flash-vision-exp/encoding/encoding_dsv4.py

# 对外 API,和上面的双机通信地址分开
VLLM_HOST=192.168.16.10
VLLM_PORT=8888

MAX_MODEL_LEN=1048576
MAX_NUM_SEQS=6
MAX_NUM_BATCHED_TOKENS=8192
GPU_MEMORY_UTILIZATION_TEXT=0.835
MTP_NUM_TOKENS=6

# 手动管理模型启停
DSPARK_RESTART_POLICY=no

其中DSPARK_MODEL_OFFICIAL填的是容器里的路径,所以还要改 docker-compose.dspark.yml。

在 services.vllm-dspark.volumes 下面加这一行,把模型mount进去

      - /home/username/models/DeepSeek-V4-Flash-Vision-Exp:/models/deepseek-v4-flash-vision-exp:ro

最后只要在dgx1上启动就好了,它会同步worker的配置和补丁,按顺序启动worker和head,并做预热

第一次启动的时候会读权重、编译和做graph capture,所以可能时间会比较常

cd ~/dspark-deploy/recipe
./start-deepseek-v4-flash-dspark.sh

权重加载成功,RDMA内存注册失败(KHO 缺陷)

在第一次启动的时候遇到了一个问题,head在profiling 阶段挂掉,然后看docker日志发现了如下问题

torch.distributed.DistBackendError: NCCL error
ncclSystemError
Call to ibv_reg_mr_iova2 failed with error Cannot allocate memory

在经过了一点简单的搜索之后(当然是ai自己搜的),找到了论坛的这个帖子,发现7.0.0-1019-nvidia上的 KHO问题会影响这类NCCL/RoCE内存注册。内核 7.0.0-1019-nvidia 的 KHO功能与RoCE驱动冲突,导致内存无法被注册给RDMA子系统。

nvidia给出的临时解决方式方法是关闭KHO,也就是加 kho=off

但是运气比较好的是,我发现只有head(dgx1)有这个问题,我的worker(dgx2)没有这个问题,然后worker的kho是关的。

检查了一下两个机器上分别装的包,发现nvidia正好在我部署那天的早上发布了补丁包nvidia-spark-grub-kho,dgx2更新的时候更新到了,dgx1还没更新。

所以只需要安装一下补丁ok了。

sudo apt-get install --no-install-recommends nvidia-spark-grub-kho=1.0-1
sudo update-grub
sudo reboot

重启之后检查kho是不是关了

# 正常来说应该包含kho=off
cat /proc/cmdline
# 正常的话应该出现 ls: cannot access '/sys/kernel/debug/kho': No such file or directory
sudo ls /sys/kernel/debug/kho

简单的性能测试

api起来之后就可以测试了,

curl --noproxy '*' -fsS http://192.168.16.10:8888/health
curl --noproxy '*' -fsS http://192.168.16.10:8888/v1/models
curl --noproxy '*' -fsS --max-time 120 \
  http://192.168.16.10:8888/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "deepseek-v4-flash-vision-exp",
    "messages": [{"role": "user", "content": "17 × 23 等于多少?只回答数字。"}],
    "temperature": 0,
    "max_tokens": 32,
    "chat_template_kwargs": {"thinking": false}
  }'

这边是测试结果

长上下文场景

输入 tokens / 请求并发输出 tokens / 请求TTFT 中位数每请求 decode TPS 中位数聚合输出 TPS
970–97115120.626 秒42.5240.26
967–974610242.730 秒16.6893.10
7830–7833651222.626 秒12.5146.87
31328–31332625666.272 秒4.9912.25

短输入

指标单请求六并发
每请求 decode TPS62.132.2
聚合输出 TPS54.1154.9
TTFT0.305 秒0.836 秒

总之,短输入单流约62tps,六并发每个大约32tps、总吞吐约155tps,但是换成长输入就会慢不少。

一些别的notice

hdmi问题

总之不要热插拔,要么一直不接,要用输出的话就关机接上显示屏再重启。

因为好像热插拔会导致gpu初始化失败,然后nvidia-smi报No devices were found。

反正好像我开机的时候接上hdmi就导致了这个问题,不接然后重启就没这个问题了。

部署后运维的快捷指令

启动模型

ssh dgx1.local 'nvidia-smi -L'
ssh dgx2.local 'nvidia-smi -L'
ssh dgx1.local 'cd ~/dspark-deploy/recipe && ./start-deepseek-v4-flash-dspark.sh'

停止模型:

ssh dgx1.local 'docker stop -t 30 deepseek-v4-flash-vllm-dspark-1'
ssh dgx2.local 'docker stop -t 30 deepseek-v4-flash-vllm-dspark-1'

开关桌面

# 设置以后开机不进入桌面
sudo systemctl set-default multi-user.target

# 关闭桌面
sudo systemctl stop display-manager

# 临时开启桌面
sudo systemctl start display-manager

# 设置开启进入桌面
sudo systemctl set-default graphical.target

修改 API 监听地址,修改 .env.dspark:

VLLM_HOST=192.168.16.10
VLLM_PORT=8888

关闭 Wi-Fi

ssh -t dgx1.local 'sudo nmcli radio wifi off'
ssh -t dgx2.local 'sudo nmcli radio wifi off'

Reference

  1. Recovery from kernel panic after dashboard update — unable to mount root fs on unknown-block(0,0)
  2. DeepSeek-v4-Flash-DSpark-2x-DGX-Spark
  3. dspark-vllm-gx10
  4. During the initialization process of the operating system, when connecting to Wi Fi and entering a password, the screen will turn black
  5. DGX Spark kernel panic after OOBE/update:DKMS arm64/aarch64 冲突及签名模块
  6. NCCL/RoCE内存注册失败
  7. GIGABYTE AI TOP ATOM Support
  8. NVIDIA DGX Spark System Recovery
  9. NVIDIA Container Toolkit 安装与 Docker runtime 配置
  10. DeepSeek-V4-Flash-Vision-Exp
  11. MiaAI-Lab/DeepSeek-v4-Flash-DSpark-2x-DGX-Spark