DGX Spark 容器工作流实战:NGC PyTorch 与 Unsloth 镜像的 docker run 规范、标签解析与可复现运行
本指南是 DGX Spark 环境技能包中"容器工作流"(container-workflow)参考文档的完整展开。它面向在 NVIDIA DGX Spark(GB10 / aarch64 / SM121 / CUDA 13)上进行 PyTorch 训练与 Unsloth 微调的工程师,给出两条官方认可镜像的具体 docker run 调用、移动标签的摘要(digest)固定流程、拉取与本地重建的取舍,以及裸 pip 兜底方案。读完本文,你将能按可复现的标准在 Spark 上启动训练容器、把结果落盘到宿主机、并对"容器优先"(Container-First)规则背后的 ABI 匹配逻辑形成体系化认知。
背景:为什么 Spark 上"容器优先"是硬规则
DGX Spark 搭载 GB10 Grace Blackwell 芯片:aarch64 CPU、SM121 GPU、128GB 统一内存(UMA)、CUDA 13。相比常见的 x86 + CUDA 12 服务器,这是一个更窄、更年轻的平台——aarch64 + CUDA 13 的 wheel 生态仍在逐步补齐(依据 spark-environment-setup/SKILL.md 的定位描述)。
容器优先的核心理由是固定版本(pinning),而非便利。Triton、xformers、transformers 的版本与 GB10 的 SM121 目标和 CUDA 13 之间存在窄交互;容器把三者锁定在一个已在当前硬件上验证过的组合里,而裸 pip 把解析责任留给你自己,代价是"一次一个导入错误"。仓库技能包甚至为这个决策预置了快速判定:
- 标准训练/推理工作 → NGC PyTorch 容器;
- Unsloth 为中心的微调 → Unsloth 容器(自带已验证的 Triton/xformers/transformers 组合);
- 两者都不合适(自定义系统包、本地 IDE 解释器)→ 按精确顺序执行裸 pip。
判定细节可参见 SKILL.md 的 Container-First Rule,而本文聚焦其中可落地的两条容器路径。
NGC PyTorch 容器:标准训练的通用底座
NGC 镜像用于通用训练/推理底座。参考文档给出了如下具体调用:
docker run --runtime=nvidia --gpus all -it --rm \
--ipc=host --ulimit memlock=-1 --ulimit stack=67108864 \
-v "$(pwd)/finetuning:/workspace/finetuning" \
nvcr.io/nvidia/pytorch:25.09-py3
每个参数的用途必须理解到位,否则容器内环境会以隐蔽方式失败:
--runtime=nvidia --gpus all:将 GB10 GPU 暴露给容器。缺少该参数时,容器内的 PyTorch 会报告"无 CUDA 设备",尽管宿主机侧一切正常。这与 gotcha-checks.md 的 GPU 检测五假设 中的第一项(运行时/标志)直接对应——在容器内执行nvidia-smi失败即指向这一项。--ipc=host与--ulimit组合:--ipc=host避免共享内存饥饿;--ulimit memlock=-1解除内存锁上限;--ulimit stack=67108864(64MB)放宽栈空间。三者共同保护 PyTorch DataLoader 多进程 worker 的共享内存与栈需求。-v "$(pwd)/finetuning:/workspace/finetuning":把仓库的finetuning/运行目录挂载进容器。检查点与日志因此落在宿主机文件系统,而非临时容器层——--rm标志在退出时删除容器(以及一切未挂载出去的内容)。若省略挂载,训练产物会随容器销毁而丢失。
标签(Tag)指引:25.09 与更新 blessed tag 的取舍
25.09-py3 是在该硬件上实际验证过可工作的标签(内置 torch 2.9.0a0+50eac811a6.nv25.09、CUDA 13.0,满足 ABI 规则预期;对于微调工作流中实际用到的包,未观察到功能差异)。参考文档明确了一条务实原则:当 SKILL.md 提到更新的 blessed tag(如 25.11-py3)时,应将其视为"本地可用则拉取"的指引,而非硬性要求——如果引用的新 tag 未在本地缓存且拉取不现实,就回退到最新可用的 25.x tag,并在运行记录(run notes)中注明这个缺口,不要阻塞在 tag 上。
同时要注意 NGC 构建的一个特性:其 PyTorch 是在容器内部针对 CUDA 13 编译的,没有 +cu130 wheel 标签——因此 pip show torch 不会出现 cu130 字样,这个"缺失"本身不是失败(详见 stack-matrix.md 与 ABI 规则)。
Unsloth 容器:移动标签必须先固定摘要再运行
对于以 Unsloth 为中心的微调运行,应优先使用专门镜像而非通用 NGC 镜像——它自带了为该硬件验证过的固定 Triton/xformers/transformers 组合。
与 NGC 的带日期 tag(25.09-py3)不同,unsloth/unsloth:dgxspark-latest 是一个移动 tag(moving tag)。直接把它当作正式运行的调用是不可靠的——必须先解析并固定它的 digest,然后按 digest 运行。参考文档给出的完整三步流程:
# 1. Discovery step: pull the moving tag and confirm it starts.
docker pull unsloth/unsloth:dgxspark-latest
# 2. Resolve the tag to its current digest.
docker inspect --format='{{index .RepoDigests 0}}' unsloth/unsloth:dgxspark-latest
# -> unsloth/unsloth@sha256:<resolved digest>
# 3. Run by digest — this is the reproducible invocation.
docker run --runtime=nvidia --gpus all -it --rm \
--ipc=host --ulimit memlock=-1 --ulimit stack=67108864 \
-v "$(pwd)/finetuning:/workspace/finetuning" \
unsloth/unsloth@sha256:<resolved digest>
- 第 1 步的
docker pull是发现步骤:拉取移动 tag 并确认它能启动; - 第 2 步用
docker inspect把 tag 解析为当前 digest(RepoDigests中的sha256:...); - 第 3 步按 digest 运行,这才是可复现的正式调用。
在 CI 或任何"可复现性重要"的流水线中,应把固定的 @sha256:... digest 替换掉 tag——如果运行记录只写了 dgxspark-latest,一旦 tag 移动,这个运行将无法复现。每次接手新的 blessed release 时都要重新解析并重新固定 digest(参见下文"拉取 vs 重建")。其余参数(--runtime=nvidia --gpus all、--ipc=host、ulimit、finetuning/ 挂载)的理由与 NGC 调用完全一致。
这条"移动 tag 必须先固定"的约束同样被上游正式使用:在 stack-matrix.md 的组件矩阵 中,Unsloth 行明确标注 unsloth/unsloth:dgxspark-latest 是移动 tag,并要求可复现/CI 场景下固定 digest。
拉取 vs 重建:什么时候该做什么
参考文档给出了两条边界清晰的原则:
应当拉取新 tag 的场景:有新 blessed release 发布,或你在追查一个"新 tag 的变更日志声称已修复"的 bug。
应当在本地重建的场景:某个具体项目需要一个额外的系统包或 Python 依赖层(以两条基础镜像之一为 FROM 起点),且该依赖与固定的训练栈不冲突。
明确禁止的场景:不要为了"升级"基础镜像已经固定的某个组件而重建——那会重新引入容器存在本来就是为了规避的版本矩阵问题。这与技能包的 G9 教训一致:裸 pip 环境里 Triton、xformers、transformers 各自漂移,没有任何东西把它们钉在 GB10 的 SM121 目标上(见 spark-training-gotchas/SKILL.md G9)。
裸 pip 逃生通道:uv 隔离与 --override 强制固定
当容器确实不合适(参见 SKILL.md 的 Container-First Rule)时,参考文档要求:用 uv 隔离环境,而非系统 Python,并在其中按 NVIDIA playbook 的安装顺序执行。
其中的关键陷阱与对策:
- 如果
uv坚持选择一个与 playbook 固定版本冲突的依赖版本(在 aarch64/CUDA 13 wheel 生态尚年轻的当下很常见),使用uv pip install --override强制固定版本通过,而不是让解析器静默替换成不兼容的构建; - 环境建立后,必须先用 SKILL.md 的 Verification Commands 验证,再信任该环境。
完整的固定版本序列(来自 SKILL.md,对应 stack-matrix 的 dated 已知可用矩阵):
pip install "transformers==5.13.1" "peft==0.19.1" "hf_transfer==0.1.9" "datasets==4.3.0" "trl==1.8.0"
pip install --no-deps "unsloth==2026.7.2" "unsloth_zoo==2026.7.2" "bitsandbytes==0.49.2"
pip install -U "torchao==0.17.0"
- 第二条命令的
--no-deps不是可选项:在 aarch64 上让 pip 重新解析 Unsloth 的依赖树,是拉入不兼容 torch 或 triton 构建的常见途径; - 第三条
torchao==0.17.0也不是可选项:NGC 基础镜像内置的 torchao 对当前 peft 的 LoRA-attach 路径来说太旧(ImportError: ... torchao ... only versions above 0.16.0 are supported),这是硬阻塞,不是警告; - 所有
==固定都是承重的(load-bearing),取自 stack-matrix.md 的 dated 已知可用版本矩阵——未固定的安装会解析到当前 PyPI 版本,远远超出该 Unsloth 版本声明支持的区间。
一个值得注意的生态变化(记录在 stack-matrix.md):HF_HUB_ENABLE_HF_TRANSFER 在 huggingface_hub 1.23+ 已废弃,设置它只会产生 FutureWarning,下载实际走 Xet。在 1.23+ 上应改为设置 HF_XET_HIGH_PERFORMANCE=1;旧文档中提及 hf_transfer 的指令应理解为"让下载变快"的意图,而非字面意义的当前 API 要求。
启动前验证:容器内环境是否真正就绪
无论走哪条容器路径,参考文档与技能包都要求在跑昂贵负载之前先验证 GPU 可见性。容器启动后立即执行:
import torch
print(torch.cuda.is_available(), torch.version.cuda)
预期输出为一行 <bool> <cuda-version>:
True 13.0
如果输出 False,不要直接跳到重装 wheel——ABI 不匹配只是多种原因之一。技能包给出的排查假设表(详见 stack-matrix.md 的逐假设细节):
| 假设 | 快速检查 |
|---|---|
| 运行时/标志 | 容器内 nvidia-smi 同样失败 |
| 设备可见性 | echo $CUDA_VISIBLE_DEVICES(注意:显式设为空串会隐藏所有设备) |
| 权限 | ls -l /dev/nvidia* |
| CUDA 初始化状态 | 进程卡死;用全新 shell/容器重试 |
| ABI 不匹配(常见元凶) | torch.version.cuda 不以 13 开头 |
先查 nvidia-smi:如果它不显示 GPU,问题属于前三类而非 ABI。只有确认是 ABI 问题后才重装 wheel——在排除 1–4 之前重装只会浪费一次循环而不改变结果。ABI 规则的详细内容(CUDA 12/13 wheel 对 libcudart.so.12/.so.13 的链接错配、典型症状、修复路径)可参见 spark-environment-setup/SKILL.md 的 ABI Rule 一节。
另一个高频坑:训练开始后如果 Triton 内核编译失败,设置 TRITON_PTXAS_PATH=/usr/local/cuda/bin/ptxas 重试(组件矩阵中 Triton 一行的要求)。
组件矩阵与已知可用版本:支撑上述决策的事实表
stack-matrix.md 是本文所有容器/裸 pip 决策背后的逐组件事实表,与 SKILL.md 的 Component Quick Table 一一对应:
| 组件 | 状态 | 说明 |
|---|---|---|
| PyTorch(cu130, aarch64) | ✅ | 官方 wheel 位于 download.pytorch.org/whl/cu130,匹配系统 CUDA 13 ABI |
| bitsandbytes | ✅ | 0.48+ 开箱即用 |
| Triton | ✅(需环境变量) | 需设置 TRITON_PTXAS_PATH=/usr/local/cuda/bin/ptxas,否则内核编译找不到 ptxas |
| flash-attn | ❌ 跳过 | 无 sm_121 内核可发布或可构建;此硬件上 PyTorch 的 SDPA 后端更快 |
| xformers | 仅源码构建 | 无预编译 aarch64/SM121 wheel;构建需设 TORCH_CUDA_ARCH_LIST=12.1 |
| vLLM | 仅 nightly wheel | 使用 wheels.vllm.ai/nightly/cu130;SM121 修复约在 2026-06 进入 nightly 通道 |
| TransformerEngine / NVFP4 训练 | 仅容器 | 裸 pip 不现实;NVFP4BlockScaling 面向 SM100,SM121 支持视为有保留 |
| Unsloth | ✅(容器优先) | 官方镜像 unsloth/unsloth:dgxspark-latest(移动 tag,需固定 digest)或 NVIDIA playbook pip 序列 |
| Axolotl / TRL / PEFT | ✅ | 标准安装,无需特殊处理 |
| LLaMA-Factory / NeMo | 脆弱/进行中 | 在本平台不可靠,先查上游 issue |
一个值得单独强调的硬件细节是 sm_121 vs sm_121a:GB10 的 GPU 识别为 sm_121,但部分较新内核特性(尤其 NVFP4 的原生 cvt.e2m1x2 转换指令)需要为超集目标 sm_121a 编译的代码。若 NVFP4 推理比 FP8 慢约 32%,通常就是这个原因——检查所用 wheel/容器的构建标志,再下结论说硬件是瓶颈(对应训练 gotchas 的 G7)。
与技能包其他部分的衔接
容器工作流是整个 DGX Spark 环境设置技能的落地执行层,与同包其他文件形成闭环:
- 决策入口:spark-environment-setup/SKILL.md 定义 Container-First Rule、ABI Rule 与 Verification Commands,本文是其
references/container-workflow.md的展开; - 事实底座:references/stack-matrix.md 提供逐组件状态与 dated 已知可用版本矩阵;
- 启动前预检:spark-training-gotchas/SKILL.md 定义 G1–G10 失败模式,其中 G1(ABI 不匹配)、G9(容器优先 vs 裸 pip)直接由本工作流解决;其 assets/preflight.sh 可自动执行 G1/G3/G4/G7/G9 检查;
- Agent 化执行:dgx-spark-ops-engineer.md 描述"环境医生"型 Agent 的容器工作流引导职责——在推荐宿主机级改动之前,先引导修复走向 NGC 或 Unsloth 容器镜像;spark-preflight.md 则把预检编排成可调用的命令并产出
env-report.json; - 运行期运维:spark-memory-thermal-ops/SKILL.md 承接"环境已验证之后"的阶段——UMA 内存头寸、OOM Ladder、热监控。
结语
容器工作流在 DGX Spark 环境设置中承担"可执行层"的角色:NGC 镜像用带日期 tag 直接运行即可,Unsloth 镜像必须先固定 digest 再运行,本地重建只用于叠加不冲突的依赖而绝非"升级"已固定组件,裸 pip 则是必须遵循固定顺序与 --override 纪律的兜底通道。所有路径共享同一条验证底线:在启动任何昂贵负载之前,确认 torch.cuda.is_available() 为 True 且 torch.version.cuda 以 13 开头。参考文档右上角的 "Last verified: 2026-07-14" 提醒所有 tag 与版本信息都是带日期快照——新 blessed tag 发布时应重新验证并更新决策,这正是把"固定版本"当作流程而非一次性动作的正确姿势。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00