技嘉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的情况,如下是情况复现
场景还原
- 第一次启动进入界面,插入鼠标键盘,连接好网络,开始设置系统前的第一次更新
- 进度条跑完,自动重启
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)- 手动重启后
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之后他直接黑屏了
故障现象
- 开始设置系统前的第一次更新
- 连接wifi
- 直接黑屏,除了鼠标能动就不行
简单来说就是在第一次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
你看到这篇文章的时候可能已经有别的系统更新了,不一定需要完全按照我的方案来。
部署前准备
部署的时候的机器状态如下:
- System: Ubuntu 24.04.5
- Kernel:
7.0.0-1019-nvidia(Ubuntu 构建版本:7.0.0-1019.19~24.04.2-nvidia) - Driver:
NVIDIA UNIX Open Kernel Module for aarch64 580.178.04 Release Build(nvidia-driver-580-open) - Container: ghcr.io/anemll/dspark-vllm-gx10:0.1.1
- Model: deepseek-ai/DeepSeek-V4-Flash-Vision-Exp
正常来说,应该能跑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 / head | dgx2 / worker |
|---|---|---|
管理口 enP7s7 | 192.168.16.10/24 | 192.168.16.11/24 |
高速接口 enp1s0f1np1 | 192.168.100.10/24 | 192.168.100.11/24 |
另一高速接口 enP2p1s0f1np1 | 192.168.101.10/24 | 192.168.101.11/24 |
| 本次推理使用的 HCA | rocep1s0f1 | rocep1s0f1 |
两台都是用的默认的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–971 | 1 | 512 | 0.626 秒 | 42.52 | 40.26 |
| 967–974 | 6 | 1024 | 2.730 秒 | 16.68 | 93.10 |
| 7830–7833 | 6 | 512 | 22.626 秒 | 12.51 | 46.87 |
| 31328–31332 | 6 | 256 | 66.272 秒 | 4.99 | 12.25 |
短输入
| 指标 | 单请求 | 六并发 |
|---|---|---|
| 每请求 decode TPS | 62.1 | 32.2 |
| 聚合输出 TPS | 54.1 | 154.9 |
| TTFT | 0.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
- Recovery from kernel panic after dashboard update — unable to mount root fs on unknown-block(0,0)
- DeepSeek-v4-Flash-DSpark-2x-DGX-Spark
- dspark-vllm-gx10
- During the initialization process of the operating system, when connecting to Wi Fi and entering a password, the screen will turn black
- DGX Spark kernel panic after OOBE/update:DKMS arm64/aarch64 冲突及签名模块
- NCCL/RoCE内存注册失败
- GIGABYTE AI TOP ATOM Support
- NVIDIA DGX Spark System Recovery
- NVIDIA Container Toolkit 安装与 Docker runtime 配置
- DeepSeek-V4-Flash-Vision-Exp
- MiaAI-Lab/DeepSeek-v4-Flash-DSpark-2x-DGX-Spark