mcpField
T
tao-run-on-slurm

tao-run-on-slurm

github.com/nvidia云与 DevOps3.8k1.6k 次安装今天更新
代码仓库

关于 tao-run-on-slurm

tao-run-on-slurm 是面向 TAO 工作流的 SLURM 集群运行技能,供需要使用远程 GPU 集群的用户运行任务。它通过 SSH 提交和管理作业,并要求数据及镜像在 GPU 分配前准备到共享存储。

主要功能

  1. 01通过 SSH 提交 SLURM 作业
  2. 02查询状态、查看日志和取消作业
  3. 03支持单节点与多节点任务
  4. 04GPU 作业前准备容器镜像和数据
  5. 05检查集群及 SSH 前置条件

适用场景

  1. 01在共享 Lustre 上运行 TAO 训练任务
  2. 02查看远程作业状态及输出日志
  3. 03取消已提交或运行中的作业

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/nvidia/skills --skill tao-run-on-slurm

安装后在 Claude Code 中输入/tao-run-on-slurm确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

BENCHMARK.md
skill-card.md
skill.oms.sig
config/
skillspector-baseline.yaml
evals/
evals.json
references/
cosmos-slurm-guardrails.md
detailed-guide.md
skill_info.yaml
slurm-container-execution.md
slurm-preflight-storage.md
slurm-ssh-credentials.md

详细介绍

SLURM

单独安装? 如果此会话并非由 TAO 技能库插件初始化,请先运行 tao-setup 技能(主机预检、凭据、跨技能发现)。

面向由 SLURM 管理的集群的远程 GPU 计算平台。作业通过 SSH 从启动主机提交到登录节点,暂存到共享文件系统,再使用 sbatch 提交,并通过 srun 容器支持执行。

适用场景

当用户可以使用受管理的 GPU 集群、共享 Lustre 存储以及由调度器分配的 GPU 时,使用 SLURM。如果文件仅存在于 Agent 机器上,请勿使用 SLURM;数据和输出必须能从集群访问。

预检 + SSH

确认已导出 SLURM_USER 和 SLURM_HOSTNAME,并且可以通过无密码 SSH 连接到登录主机(ssh -o BatchMode=yes)。 启动主机需要 ssh,不需要本地 sbatch、srun、Enroot 或 Lustre 挂载。请在选定的远程登录节点/计算节点环境中预检调度器、Pyxis、Enroot 和共享存储依赖项。可通过 SSH 标准输入传送已安装技能中的特定模型检查器;不要暂存临时源代码补丁,也不要将启动主机当作 SLURM 环境。 对于私有 nvcr.io 镜像,请在集群上为每个(集群、用户)组合安装一次 ~/.config/enroot/.credentials:Pyxis/Enroot 不会从作业环境读取 NGC_KEY,如果没有持久凭据,受身份验证保护的拉取会在作业启动时因 "Could not process JSON input" 失败。请通过 printf | ssh heredoc 安装,以确保 NGC_KEY 的值不会写入 shell 历史记录、中间文件或聊天输出;切勿对该值使用 cat/echo。

如果预检失败,Agent 会提示用户通过 Bash 授权安装/修复。可通过 pip 安装的 Python 依赖项除外:自动安装,然后重新运行预检。

完整预检脚本、enroot 凭据 heredoc、前置密钥设置(密钥对、ssh-copy-id、known_hosts、容器密钥挂载、2FA 处理)以及 SSH 故障修复提示,请参阅 references/slurm-ssh-credentials.md。

执行 — 四个动词

tao-run-on-slurm 是平台使用方:通过 ssh + sbatch/squeue/sacct/scancel 运行 spec-bundle,仅修改 job-record。存储属于A 层(Lustre)——提交前将数据集暂存到共享路径,并通过 Pyxis 读取;切勿在分配的计算资源内获取 S3 数据(调度器会因 GPU 空闲超时终止作业,浪费的时间仍会计费)。$BANK = ${TAO_SKILL_BANK_PATH};$LOGIN = 已解析的 SLURM_HOSTNAME。

提交
  1. 复用已暂存的内容 — 绝不重复操作(A 级):
    • 镜像: @@IMAGE@@ 是 Lustre 上的 .sqsh — 如果已有镜像,请复用 (ssh $LOGIN ls <sqsh>);只有在镜像不存在时,才用 enroot import 转换一次(按名称缓存 — 参见 references/slurm-container-execution.md)。
    • 数据集: 确认数据集已在 Lustre 上(ssh $LOGIN test -e …),并 引用这些路径;tao-data-io 只暂存尚不存在的小型辅助输入 — 绝不重新暂存已有数据,也绝不在分配到的计算资源内暂存训练 集。 然后在 Lustre 上使用这些路径编写规格文件:<job_dir>/specs/spec.yaml。
  2. 凭据 → sidecar(绝不内联): 如果运行需要会话凭据 (例如 HF_TOKEN),请将其写入 Lustre 上权限为 600 的 sidecar,并让模板在退出时将其彻底删除;NGC 镜像拉取使用一次性的 ~/.config/enroot/.credentials(参见 references/slurm-ssh-credentials.md), 而不是作业环境:
    set -a; source /path/to/.env; set +a   # omit if already exported
    printf 'export HF_TOKEN=%s\n' "$HF_TOKEN" | ssh $LOGIN "umask 077; cat > <job_dir>/job_$JOB_ID.env"
    
  3. 打开记录 — 在启动前生成 ID,并绑定 Lustre 上的 results_dir:
    JOB_ID=$("$BANK/scripts/tao_job_record.py" open --platform slurm --image "$IMAGE" \
      --network-arch "$ARCH" --action "$ACTION" --storage-tier A --results-root "$SLURM_BASE_RESULTS_DIR")
    
  4. 使用可选的模型生命周期。 如果已验证的 spec-bundle 包含 execution,则在将分布式意图映射到原生 SLURM/Pyxis 时,保留其顺序和语义。只暂存其校验和闭合的 supporting_files。完整的通用生命周期和暂存约定见 references/slurm-container-execution.md。
  5. 渲染 templates/slurm/singlenode.sbatch.tmpl — 替换所有 @@<NAME>@@(JOB_NAME=$JOB_ID、NUM_GPUS、CPUS_PER_TASK、TIME、LOG_DIR、 IMAGE、CONTAINER_MOUNTS=<RUNTIME_SUPPLIED_MOUNTS>、COMMAND=<bundle command reading the shared-storage spec>、SBATCH_EXTRA= 账户/分区行、ENV_FILE= sidecar 路径或 留空、EXTRA_ENV= 任意集群 NCCL 参数)→ <job_dir>/sbatch/job_$JOB_ID.sbatch。 提交前进行 lint 和语法检查: redact_secrets.py lint <sbatch> 必须 通过,且 bash -n <sbatch> 必须成功。
  6. 提交 + 记录为 RUNNING:
    SLURM_ID=$(ssh $LOGIN "sbatch --parsable <job_dir>/sbatch/job_$JOB_ID.sbatch")
    "$BANK/scripts/tao_job_record.py" mark "$JOB_ID" --state RUNNING --backend-ref "$SLURM_ID"
    

跳过检查门禁或打开记录的提交没有 ID — 因此无法启动。

状态
# sacct ANNOTATES states ("CANCELLED by 12345") and truncates them to the
# default column width, so a cancelled job reads back as "CANCELLED+" and
# matches nothing in the table below — reporting UNKNOWN instead of CANCELED.
# Widen the column, take the first word, drop the truncation marker.
st=$(ssh $LOGIN "sacct -j $SLURM_ID -X -n -o State%30" | awk '{print $1}' | tr -d '+')
# (use squeue while the job is still PENDING; sacct lags briefly after submit)
SLURM 状态词汇
PENDINGPENDING
RUNNING / COMPLETINGRUNNING
COMPLETEDCOMPLETE(确认 results_dir 中的 status.json)
FAILED / TIMEOUT / OUT_OF_MEMORYERROR(区分基础设施错误与程序错误 → 重试,M6)
NODE_FAIL / BOOT_FAILERROR,err_class=ERR_INFRA(--requeue 会重新排队这些作业)
CANCELLED / PREEMPTED / REVOKEDCANCELED
(未找到)UNKNOWN

原生子状态会随转换的 message 一并传递。按选定间隔轮询; 排队时间较长很正常 — 不要因耗时而停止。

日志
ssh $LOGIN "tail -n ${N:-200} <log_dir>/$JOB_ID-$SLURM_ID/main.out"   # SLURM auto-creates the %x-%j subdir
取消
ssh $LOGIN "scancel $SLURM_ID"
"$BANK/scripts/tao_job_record.py" mark "$JOB_ID" --state CANCELED --source agent

将已终止的 SLURM 作业视为取消成功。

多节点(节点数 > 1)

相同的四个动词,提交时增加三项:

  1. 渲染 templates/slurm/multinode.sbatch.tmpl,而不是单节点模板——它是严格的超集(增加了 --nodes / --wait-all-nodes 和 rendezvous 代码块)。WORLD_SIZE 表示节点数(这是 TAO 的误称);绝不要将其改为全局 rank 数。
  2. 先运行 NCCL 探测——在实际作业之前,用容器的 torchrun 运行一个开销很低的双节点 all-reduce(scripts/nccl_allreduce_probe.py),超时时间约为 120 秒。在调用 torchrun 前,将 TAO rendezvous 值保存为 TAO_NODE_COUNT=$WORLD_SIZE、TAO_GPUS_PER_NODE=$NUM_GPU_PER_NODE 和 TAO_NODE_RANK=$SLURM_PROCID;torchrun 会将标准的 WORLD_SIZE 覆盖为全局进程数。NCCL_PROBE_OK → 继续。超时(collective 挂起)→ 在 EXTRA_ENV 中设置集群的 NCCL 参数并重新探测——在 CS-OCI-ORD 上,该参数为 export NCCL_P2P_DISABLE=1(节点内 P2P 挂起),通常还会设置 NCCL_SOCKET_IFNAME=eth0 / NCCL_IB_DISABLE=1。按集群缓存可用的环境变量,以便后续作业跳过探测。还要满足 gpus_per_node > 1 才启用检测——在单节点有 2 个或更多 GPU 时也会触发 P2P 挂起。
  3. Tier-A Lustre、sidecar 凭证、记录和 lint 均保持不变。
Cosmos 后端防护措施

渲染 Cosmos 命令前,请阅读 references/cosmos-slurm-guardrails.md。其中定义了镜像暂存、planner 实例化、Framework 和 Cosmos-RL 启动约定、worker/runtime 要求,以及退出状态处理。

存储

使用共享文件系统 URI,而不是本地路径或 file:// 路径;对于远程后端,tao-core 会拒绝本地路径和 file:// 路径。

  • Lustre 上由用户提供的数据集使用 lustre:///absolute/path。
  • 微服务元数据中可能会出现 slurm:// 路径,并会在容器启动前转换为 Lustre 路径。

数据集根目录(模型技能会将其映射到所需文件)或直接使用 spec-key 路径均可。SSH 连接成功后、生成脚本前,从登录主机对每个必需的数据集路径执行 test -e;如果失败,请停止并要求提供正确路径或已暂存的数据,而不是生成会在第一个训练作业中失败的脚本。根目录模式与直接 spec 模式、后端详情和结果目录默认值,请参阅 references/slurm-ssh-credentials.md。

容器执行

tao-core 通过 Pyxis/Enroot 运行 TAO 容器:

  1. 将 spec、环境和云元数据的紧凑 JSON 文件暂存到 <job_dir>/specs、<job_dir>/env 和 <job_dir>/meta 下。
  2. 在 GPU 作业之前,使用 srun -n1 -p <conversion_partition> enroot import 将 Docker 镜像转换为缓存的 SQSH 镜像。这是每个镜像只需支付一次的开销,并非可选优化——请参阅下文的 在 GPU 分配之外获取镜像。
  3. 在 <job_dir>/sbatch/job_<job_id>.sbatch 下写入 sbatch 脚本。
  4. 提交 sbatch --export=ALL <script>。
  5. 使用 srun --container-image=<image> --container-mounts=<RUNTIME_SUPPLIED_MOUNTS> 运行容器。

接受的镜像格式:/path/to/image.sqsh、registry#image:tag、docker://registry#image:tag,以及普通的 registry/image:tag(需要时会转换为 Pyxis 格式)。SQSH 转换会按镜像名称缓存;对于 :latest 镜像,除非启用了 force_reconvert_latest,否则会复用缓存的 SQSH 镜像。

在 GPU 分配前获取镜像

从分配开始时起,GPU 就归你使用,而不是从计算开始时起。 训练前的任何操作——拉取镜像仓库中的镜像、转换镜像、获取数据集——都会占用空闲且计费的 GPU,并会被集群的 GPU 空闲回收器发现。首次拉取 TAO 镜像并进行 enroot 转换需要几分钟,这段时间足以导致任务被终止,也会产生不必要的费用。

因此,GPU 作业启动时,镜像必须已经是本地 .sqsh 文件。直接将 docker:// 或 registry#image:tag URI 传给 srun --container-image=,会让 Pyxis 在分配期间拉取并转换镜像——这正是需要避免的陷阱。先在 CPU 分区上转换一次,然后让后续所有作业都指向生成的文件:

# One-time per image, on CPU — costs no GPU time.
ssh $LOGIN "test -e <sqsh>" || \
  ssh $LOGIN "srun --chdir=/tmp -n1 -c4 --mem=7200M \
    -p <cpu_partition> -t <minutes> \
    bash -c 'set -Eeuo pipefail
      export TMPDIR=/tmp
      export ENROOT_TEMP_PATH=/tmp/enroot-tao-\${SLURM_JOB_ID}
      export SLURM_ENROOT_TEMP_PATH=\${ENROOT_TEMP_PATH}
      mkdir -p \"\${ENROOT_TEMP_PATH}\"
      cd /tmp
      enroot import -o <sqsh> docker://<registry>#<image>:<tag>'"

# Every GPU job then references the file, never the registry.
srun --container-image=<sqsh> ...

数据也遵循同样的规则:提交前先将数据暂存到 Lustre(tier A),不要在分配期间获取。

CS-OCI-ORD 转换使用 cpu_long、4 个 CPU、7200M 内存、不独占节点、节点本地的 Enroot 临时路径,并且至少需要 120 分钟。执行参考记录了相关证据和 QOSGrpMemLimit 恢复约定。

部分转换会自动检测:通过 hsqs 魔数验证 SQSH,因此截断的文件会被拒绝,而不会被悄悄使用。转换只执行一次,之后会按镜像名称缓存。

转换失败时,绝不能回退到镜像仓库中的镜像。 看似方便的恢复方式——将 docker://… 传给 srun 并让 Pyxis 处理——会让拉取操作重新回到 GPU 分配期间,造成转换原本要避免的开销,而且恰好是在已经出现问题时发生。应将转换失败或文件截断视为致命错误:在 CPU 分区上修复后重新提交。

诊断:如果作业生成输出的速度异常缓慢,请检查 --container-image= 实际接收的内容。如果这里是镜像仓库 URI,而不是 .sqsh 路径,就说明拉取操作发生在 GPU 上。

监控和取消

  • 调度器状态通过已存储的 SLURM 作业 ID 从 squeue/sacct 获取;TAO 终端状态来自共享结果文件夹中的 status.json。
  • 启用聊天监控时,对于任何非终态作业(PENDING、RUNNING 或其他状态),都应按请求的间隔持续轮询。不要在经过固定时长(例如 30 分钟)后停止;共享 GPU 分区上的排队等待时间较长很常见。
  • 启用聊天监控时,SLURM 作业仍处于非终态就不要发送最终回复。最终回复会导致脱离监控;仅当用户要求脱离/停止,或作业达到终态时,才使用最终回复。
  • 通过 SSH 从 <job_dir>/slurm-logs/<slurm_job_name>-<slurm_job_id>/main.out 和 .err 读取日志。
  • 通过查询 backend_details.slurm_metadata.slurm_job_id 获取作业 ID,并通过 SSH 运行 scancel <slurm_job_id> 取消作业。将作业不存在或已终止的情况视为取消成功。

状态映射:

  • PENDING -> Pending
  • RUNNING 或 COMPLETING -> Running
  • COMPLETED -> 检查 status.json
  • FAILED、BOOT_FAIL、DEADLINE、OUT_OF_MEMORY、NODE_FAIL -> 如果日志符合可重试的基础设施故障模式,则重试;否则为 Error
  • CANCELLED、PREEMPTED、REVOKED -> Canceled
  • TIMEOUT -> Error
  • SUSPENDED、STOPPED -> Running(仍由调度器管理,之后可能恢复;原生子状态会出现在状态转换消息中——与 docker 的 paused 采用相同约定)

必需输入

在 SLURM 信息收集环节询问以下内容;完整的凭据列表、微服务架构的键和默认值请参阅 references/slurm-ssh-credentials.md。

  • SLURM_USER(必需):登录节点的 SSH 用户名。
  • SLURM_HOSTNAME(必需):用于故障转移的逗号分隔登录主机名。
  • SLURM_PARTITION(必需):用于提交 GPU 作业的分区列表。打包的默认值为 polar,polar3,polar4,grizzly,这些分区均按 4 小时队列处理。
  • SSH_KEY_PATH(首选,预期在启动前提供):用于非交互式公钥身份验证的私钥。进行问题排查时,优先询问此项;优先使用它,而非作为后备方案的 SSH_AUTH_SOCK 代理套接字。
  • SLURM_BASE_RESULTS_DIR(可选):共享文件系统基础路径;默认值为运行时提供并验证的共享存储根目录。
  • SLURM_ACCOUNT(通常由站点策略要求):用于 #SBATCH --account 的账户。

除非用户表示其站点要求提供账户、需要自定义结果根目录,或工作流无法在不覆盖默认值的情况下继续,否则不要在初始信息收集环节询问 SLURM_ACCOUNT 或 SLURM_BASE_RESULTS_DIR。

资源默认值

tao-core 中的默认值:

  • num_nodes:1
  • num_gpus:4
  • max_num_gpus_per_node:8
  • cpus_per_task:16
  • time_hours:4
  • timeout_hours:3.8
  • max_time_hours:4
  • container_mounts:运行时提供的显式源路径到目标路径的挂载
  • use_requeue:true
  • use_sqsh:true

启动器必须使用打包的 4 小时作业时长和 3.8 小时子进程超时默认值,绝不能使用 12 小时。如果用户提供的 SLURM_TIME_HOURS 更长,请在提交前确认所选分区支持该时长。对于打包的默认分区列表 polar,polar3,polar4,grizzly,拒绝超过 4 小时的请求;只有在用户确实需要更长的作业时长时,才询问是否更换分区。

达到或超过 max_num_gpus_per_node 时,分配独占节点,并根据 GPU 总数计算节点数量。

多节点与重试

对于多节点作业(num_nodes > 1),渲染后的 templates/slurm/multinode.sbatch.tmpl 会设置 sbatch 指令,并导出 PyTorch 分布式 rendezvous 环境变量:WORLD_SIZE、NUM_GPU_PER_NODE、 NODE_RANK、MASTER_ADDR 和 MASTER_PORT(29500)。TAO 入口会读取 WORLD_SIZE + NUM_GPU_PER_NODE,并在内部构建 torchrun。Cosmos-RL 对 controller、policy 和 rollout worker 有特殊的多节点角色处理。 有关 NCCL 探测门控和按集群缓存环境变量,请参阅上文提交小节 ### Multi-node (nodes > 1)。

SLURM 作业输入请使用 Lustre,而不是 S3。 作业一经派发,GPU 分配 便立即开始,因此如果脚本开头花很长时间从 s3:// 下载数据,就会消耗 分配时长,可能导致作业因 GPU 空闲而被终止,而且无论如何都会产生费用。 请先将训练数据暂存到共享文件系统中,并通过 lustre:///... 引用。对于 小型辅助输入(检查点、配置),可以预先从 S3/HF/NGC 获取,但不要用于 训练数据集。K8s/Brev 不受此调度器空闲限制约束。

发生基础设施故障(NODE_FAIL、BOOT_FAIL、NCCL 传输超时、CUDA 驱动程序 初始化失败、GPU/IB 链路中断、OOM-killer 回收节点、Xid 错误)时,请根据 日志判断故障属于基础设施还是程序,并在重新提交暂存的工作负载前,使用 --retry-of 创建新的重试记录(M6)。普通训练失败会立即显现,因此损坏的 规范不会消耗重试额度。默认通过 SLURM_USE_REQUEUE=true 启用 #SBATCH --requeue,因此在任何 Agent 级别的重新提交之前,SLURM 本身会在 NODE_FAIL 或抢占时重新排队作业;Cosmos 等工作负载约定可能要求使用 --no-requeue。

如果 sbatch --parsable 返回空响应或 SSH 断开,请视为情况不明: 通过完全匹配的作业名称进行核对,切勿盲目提交,并验证继承的节点排除设置。 所引用的执行指南定义了完整的决策表。有关多节点环境变量/sbatch 指令的 完整细节与表格、集群要求、完整的 Lustre 而非 S3 规则,以及故障模式检查 清单,请参阅 references/slurm-container-execution.md。

参考资料

  • references/slurm-ssh-credentials.md — 预检脚本、SSH/密钥设置、 enroot 凭据、完整凭据列表、后端详情、存储规则、 SSH 修复提示词。
  • references/slurm-container-execution.md — 容器执行步骤、监控、状态映射、 取消、多节点详情、Lustre 而非 S3、重试、故障模式。
  • references/slurm-preflight-storage.md — 扩展预检/存储说明。
  • references/cosmos-slurm-guardrails.md — Cosmos Framework 和 Cosmos-RL 启动与状态防护措施。
  • references/detailed-guide.md — 拆分参考资料的导航图。

评论

支持 Markdown