训练任务从提交到运行:完整链路和排障地图

这份文档解决一个问题:当一个训练任务出问题时,你应该先判断它卡在哪一层,而不是一上来就随机翻日志。

训练任务的主链路可以记成一句话:

text 复制代码
用户提交任务 -> 平台接单 -> K8s 创建资源 -> 调度找机器 -> 节点启动容器 -> 容器拿到 GPU -> 训练进程启动 -> 日志/指标/模型回收

对应到系统组件:

text 复制代码
用户/CLI/Web
  -> Platform API
  -> Kubernetes API / CRD / Job / Pod
  -> Scheduler / Queue
  -> kubelet / containerd / CNI / Volume
  -> NVIDIA Device Plugin / GPU Runtime
  -> PyTorch / torchrun / NCCL
  -> Prometheus / Loki / Artifact / Metadata

你后面学习 Linux、Kubernetes、GPU、NCCL、Prometheus,都可以挂到这条链路上。

0. 先看总图

text 复制代码
┌─────────────────────────────────────────────────────────────────────┐
│ 1. 用户提交任务                                                      │
│ 镜像、命令、CPU、内存、GPU、数据路径、输出路径、队列、优先级          │
└──────────────────────────────┬──────────────────────────────────────┘
                               │
                               v
┌─────────────────────────────────────────────────────────────────────┐
│ 2. 平台 API                                                          │
│ 鉴权、参数校验、配额校验、任务入库、生成 K8s 资源                    │
└──────────────────────────────┬──────────────────────────────────────┘
                               │
                               v
┌─────────────────────────────────────────────────────────────────────┐
│ 3. Kubernetes 资源                                                   │
│ Job / Pod / CRD / ConfigMap / Secret / PVC / Service                 │
└──────────────────────────────┬──────────────────────────────────────┘
                               │
                               v
┌─────────────────────────────────────────────────────────────────────┐
│ 4. 调度层                                                            │
│ Scheduler / Queue / Quota / Priority / Gang Scheduling               │
└──────────────────────────────┬──────────────────────────────────────┘
                               │
                               v
┌─────────────────────────────────────────────────────────────────────┐
│ 5. 节点运行层                                                        │
│ kubelet / containerd / CNI / Volume / cgroup                         │
└──────────────────────────────┬──────────────────────────────────────┘
                               │
                               v
┌─────────────────────────────────────────────────────────────────────┐
│ 6. GPU 容器层                                                        │
│ NVIDIA Device Plugin / GPU Runtime / CUDA / nvidia-smi               │
└──────────────────────────────┬──────────────────────────────────────┘
                               │
                               v
┌─────────────────────────────────────────────────────────────────────┐
│ 7. 训练运行层                                                        │
│ torchrun / PyTorch DDP / rank / NCCL / 数据读取 / checkpoint          │
└──────────────────────────────┬──────────────────────────────────────┘
                               │
                               v
┌─────────────────────────────────────────────────────────────────────┐
│ 8. 回收和观测层                                                      │
│ 日志、指标、事件、模型产物、任务状态、失败原因                       │
└─────────────────────────────────────────────────────────────────────┘

1. 用户提交任务

这一层做什么

用户通过 Web、CLI、SDK 或 API 提交训练任务。平台收到的是一组训练意图,而不是一个已经能运行的容器。

典型输入:

字段 含义 常见问题
镜像 运行环境,包含 CUDA、Python、PyTorch、代码依赖 镜像不存在、版本不对、太大拉取慢
启动命令 容器启动后执行什么 命令写错、入口脚本缺失
CPU/内存/GPU 任务资源规格 超配额、规格不合法、GPU 型号不匹配
数据路径 训练数据在哪里 路径不存在、无权限、挂载失败
输出路径 checkpoint 和模型保存位置 无写权限、存储满、上传失败
队列/项目 使用哪个团队的资源 队列无资源、配额不足
环境变量 分布式训练、NCCL、业务参数 缺失或配置错误

怎么判断是不是这一层的问题

如果任务在平台页面或 API 层就创建失败,通常还没到 Kubernetes。

优先确认:

text 复制代码
任务有没有 task uid?
平台有没有返回参数错误?
用户选择的 namespace / project / queue 是否正确?
资源规格是否超过限制?
数据和输出路径是否有权限?

下一步去哪查

如果任务连 UID 都没有:查平台 API 请求和返回。

如果任务有 UID,但 Kubernetes 里没有资源:进入第 2 层,查平台 API 到 K8s 的创建逻辑。

2. 平台 API 层

这一层做什么

平台 API 把用户请求转换成平台内部任务和 Kubernetes 资源。

它通常负责:

text 复制代码
鉴权:用户能不能提交任务
参数校验:镜像、命令、资源、路径是否合法
配额校验:CPU、内存、GPU 是否还有额度
任务入库:记录 task uid、用户、namespace、状态
生成配置:环境变量、volume、secret、启动脚本
创建资源:Job、Pod、CRD、ConfigMap、Secret、PVC
状态返回:让用户能查任务状态、日志和指标

常见故障

text 复制代码
API 5xx 或超时
鉴权失败
namespace 不存在
配额不足
任务入库成功但 K8s 资源没创建
K8s 资源创建成功但平台状态没更新
Controller 没消费任务

怎么判断是不是这一层的问题

看三个事实:

text 复制代码
平台任务是否存在?
平台任务状态是什么?
Kubernetes 里是否有对应 Job/Pod/CRD?

常用命令:

bash 复制代码
kubectl get pod -n <namespace> | grep <task-name>
kubectl get job -n <namespace> | grep <task-name>
kubectl get all -n <namespace> | grep <task-name>

判断:

text 复制代码
平台有任务,K8s 没资源:平台 API 或 controller 问题。
平台没任务,K8s 也没资源:请求可能没成功。
平台有任务,K8s 也有资源:继续看 Pod 状态。

3. Kubernetes 资源层

这一层做什么

Kubernetes 接到平台创建的对象后,进入声明式控制流程。

常见对象:

对象 作用
Pod 容器真正运行的最小单元
Job 一次性任务,适合训练和数据处理
CRD 自定义任务类型,例如 PyTorchJob、RayJob、MPIJob
ConfigMap 普通配置
Secret token、ak/sk、镜像密钥等敏感配置
PVC 挂载数据或输出存储
Service 分布式 rendezvous 或服务访问

Controller 的职责是让"期望状态"变成"实际状态"。

例子:

text 复制代码
期望状态:我要一个 8 卡 PyTorch 分布式训练任务。
实际状态:现在还没有 worker Pod。
Controller 动作:创建对应 Pod,并写入 rank、环境变量和资源请求。

常见故障

text 复制代码
CRD 创建了,但 Controller 没处理
Job 创建了,但 Pod 没生成
Pod 生成了,但 ConfigMap/Secret 缺失
PVC 未绑定
任务状态没有回写

怎么判断是不是这一层的问题

看资源是否完整:

bash 复制代码
kubectl get pod -n <namespace> | grep <task-name>
kubectl get job -n <namespace> | grep <task-name>
kubectl get events -n <namespace> --sort-by=.lastTimestamp | tail -100
kubectl describe pod <pod> -n <namespace>
kubectl describe job <job> -n <namespace>

如果是 CRD:

bash 复制代码
kubectl get pytorchjob -n <namespace>
kubectl describe pytorchjob <name> -n <namespace>

判断:

text 复制代码
没有 Pod:查平台 API、CRD controller、Job controller。
有 Pod 但 Pending:进入调度层。
有 Pod 但 ContainerCreating:进入节点运行层。
有 Pod Running:进入 GPU 容器或训练运行层。

4. 调度层

这一层做什么

Scheduler 决定 Pod 放到哪台节点。

它会检查:

text 复制代码
CPU 是否够
内存是否够
GPU 是否够
GPU 型号是否匹配
节点污点和 Pod 容忍是否匹配
节点亲和性是否满足
PVC 是否能挂载
队列是否准入
配额是否足够
优先级和抢占策略

AI 训练里最容易踩的是 GPU 资源碎片。

text 复制代码
任务要求单机 8 卡。
集群空闲 GPU 总数是 8 张。
但分散在 4 台机器上,每台 2 张。
结果:总量够,单机不够,任务仍然 Pending。

Gang Scheduling 是什么

分布式训练经常需要多个 Pod 一起启动。Gang Scheduling 就是"成组调度":

text 复制代码
要么一组 Pod 全部调度成功,要么一个都不启动。

原因很简单:

text 复制代码
16 个 worker 的训练任务,如果只启动 5 个 worker,任务也跑不了。
这 5 个 worker 还会占住 GPU,浪费资源。

常见故障

text 复制代码
Insufficient cpu
Insufficient memory
Insufficient nvidia.com/gpu
node affinity conflict
had untolerated taint
PVC not bound
quota exceeded
queue not admitted

怎么判断是不是这一层的问题

Pod 状态通常是:

text 复制代码
Pending

核心命令:

bash 复制代码
kubectl describe pod <pod> -n <namespace>
kubectl get events -n <namespace> --sort-by=.lastTimestamp | tail -100
kubectl describe node <node>
kubectl get node -o wide

你重点看 Events 里 scheduler 给出的原因。

5. 节点运行层:kubelet / containerd

这一层做什么

Pod 被调度到某台节点后,本机 kubelet 开始接管。kubelet 会调用 containerd、CNI、volume plugin,把容器真正拉起来。

kubelet 大致做:

text 复制代码
获取 Pod spec
创建 Pod 网络
拉取镜像
创建 Pod sandbox
挂载 volume
准备 ConfigMap 和 Secret
设置 cgroup 资源限制
启动容器
持续上报状态

containerd 负责更底层的容器生命周期:

text 复制代码
拉镜像
管理镜像层
创建容器
启动容器进程
记录容器状态和日志

常见状态和含义

Pod 状态 通常含义
ImagePullBackOff 镜像拉不下来
ErrImagePull 镜像地址、权限或网络错误
ContainerCreating 网络、挂载、runtime、sandbox 创建中或卡住
CrashLoopBackOff 容器启动后很快退出并反复重启
OOMKilled 容器内存超过 limit,被 cgroup kill
Error 容器进程异常退出

怎么判断是不是这一层的问题

常用命令:

bash 复制代码
kubectl describe pod <pod> -n <namespace>
kubectl logs <pod> -n <namespace>
kubectl logs <pod> -n <namespace> --previous

到节点上查:

bash 复制代码
journalctl -u kubelet -f
journalctl -u containerd -f
crictl ps -a
crictl inspect <container_id>
crictl logs <container_id>

快速判断:

text 复制代码
ImagePullBackOff:查镜像、registry、Secret、网络。
ContainerCreating:查 CNI、PVC、volume、containerd、runtime。
CrashLoopBackOff:查启动命令、环境变量、应用日志、退出码。
OOMKilled:查内存 limit、模型下载、解压、数据预处理、sidecar。

6. GPU 容器层

这一层做什么

容器 Running 后,还要确认 GPU 真正可用。

GPU 容器依赖:

text 复制代码
宿主机 GPU 和驱动正常
NVIDIA Device Plugin 正常上报 GPU
Pod 正确 request nvidia.com/gpu
container runtime 正确注入 GPU 设备和驱动库
容器内 CUDA 能正常访问 GPU

关键判断

这三句话很重要:

text 复制代码
Pod Running 不等于 GPU 可用。
GPU 可见不等于训练能跑。
训练能启动不等于分布式通信成功。

常见故障

text 复制代码
宿主机有 GPU,但容器内看不到 GPU
device plugin 没有上报 GPU
节点 GPU 掉卡
驱动异常
CUDA 和驱动版本不兼容
Pod 没有 request nvidia.com/gpu
GPU 分配了,但训练进程没用起来

怎么判断是不是这一层的问题

Kubernetes 侧:

bash 复制代码
kubectl describe pod <pod> -n <namespace> | grep -A5 -B5 nvidia.com/gpu
kubectl describe node <node> | grep -A8 -B8 nvidia.com/gpu
kubectl exec -it <pod> -n <namespace> -- nvidia-smi
kubectl logs -n kube-system ds/nvidia-device-plugin-daemonset

节点侧:

bash 复制代码
nvidia-smi
nvidia-smi topo -m
nvidia-smi -q
dmesg -T | grep -i xid

7. 训练运行层:PyTorch / torchrun / NCCL

这一层做什么

容器启动后,真正开始训练。

分布式训练常见结构:

text 复制代码
torchrun 启动多个训练进程
每个进程叫一个 rank
每个 rank 通常绑定一张 GPU
所有 rank 组成一个 world
PyTorch DDP 负责分布式训练逻辑
NCCL 负责 GPU 间通信

关键变量:

名称 含义
WORLD_SIZE 总进程数
RANK 当前进程的全局编号
LOCAL_RANK 当前进程在本节点内的编号
MASTER_ADDR 主节点地址
MASTER_PORT 主节点端口

NCCL 负责:

text 复制代码
GPU 间 all-reduce
参数广播
梯度同步
节点内 NVLink/PCIe 通信
节点间 RDMA/TCP 通信

常见故障

text 复制代码
rank 数不一致
某些 worker 没启动
master 地址不可达
master 端口不通
NCCL 初始化卡住
NCCL timeout
NCCL 选错网卡
RDMA 异常
某个 rank OOM 导致其他 rank 等待
数据加载慢导致 GPU 空转
checkpoint 写入慢导致周期性卡顿

怎么判断是不是这一层的问题

常用环境变量:

bash 复制代码
NCCL_DEBUG=INFO
NCCL_DEBUG_SUBSYS=INIT,NET,GRAPH,COLL
TORCH_DISTRIBUTED_DEBUG=DETAIL

排查问题:

text 复制代码
所有 rank 是否都启动?
每个 rank 的日志是否一致?
最早报错的是哪个 rank?
NCCL 选择了哪张网卡?
节点间网络是否互通?
GPU 是否有 Xid/ECC 错误?
CPU、存储、网络是否成为瓶颈?

快速判断:

text 复制代码
卡在 init_process_group:查 rank、master、网络、端口。
NCCL timeout:查某个 rank 是否退出、RDMA、网卡、GPU 异常。
CUDA OOM:查显存、batch size、模型大小、优化器状态。
GPU 利用率低:查数据加载、CPU、存储、通信、batch size。
checkpoint 慢:查存储吞吐、写入策略、checkpoint 大小。

8. 回收和观测层

这一层做什么

训练平台不能只把任务跑起来,还要把状态、日志、指标和产物收回来。

通常回收:

text 复制代码
容器日志
Kubernetes Event
任务状态
Pod 状态
GPU 利用率
GPU 显存
CPU/内存
网络和存储指标
训练 step 指标
loss / accuracy 等业务指标
checkpoint
最终模型文件
评估结果
失败原因

任务结束后还要做:

text 复制代码
更新任务状态
保存模型和 artifact
上传 checkpoint 或最终模型
记录任务运行时间和资源用量
释放资源
回写 metadata
生成失败诊断
触发后续 Pipeline 节点

常见故障

text 复制代码
训练实际成功,但平台状态没有更新
Pod 已删除,日志查不到
模型上传失败
checkpoint 没归档
任务完成后资源没释放
指标缺失
失败原因被吞掉

怎么判断是不是这一层的问题

先分清"真实状态"和"平台展示状态":

text 复制代码
真实状态:Kubernetes Pod / Job / CRD 到底怎么样。
展示状态:平台页面、平台 API、数据库里显示怎么样。

如果两者不一致,重点查状态同步、日志采集、产物上传、metadata 回写。

9. 按 Pod 状态快速定位

这张表是日常排障最常用的。

现象 优先怀疑层 重点排查
平台任务创建失败 用户提交层 / 平台 API 参数、权限、配额、API 日志
平台有任务但没有 Pod 平台 API / Controller 是否创建 K8s 资源,controller 是否报错
Pod Pending 调度层 GPU、CPU、内存、队列、配额、亲和性、污点、PVC
Pod ImagePullBackOff 节点运行层 镜像地址、registry、Secret、网络
Pod ContainerCreating 节点运行层 CNI、PVC、volume、containerd、runtime
Pod CrashLoopBackOff 容器启动层 命令、环境变量、依赖服务、应用日志
Pod OOMKilled Linux/cgroup 层 内存 limit、模型下载、数据处理、sidecar
Pod Running 但无训练日志 容器/GPU/训练启动层 启动脚本、数据准备、模型下载、GPU、rendezvous
有日志但卡住 训练运行层 rank、NCCL、RDMA、数据加载、checkpoint
训练完成但平台没更新 回收和观测层 状态同步、产物上传、metadata 回写

10. 标准排障顺序

以后遇到训练任务问题,按这个顺序问:

text 复制代码
1. 任务 UID、namespace、name 是什么?
2. 平台任务有没有创建成功?
3. Kubernetes 资源有没有生成?
4. Pod 有没有创建?
5. Pod 当前状态是什么?
6. 如果 Pending,scheduler event 是什么?
7. 如果 ContainerCreating,镜像、网络、挂载、runtime 是否正常?
8. 如果 Running,容器进程有没有启动?
9. 容器内能不能看到 GPU?
10. 训练进程有没有启动?
11. 如果是分布式训练,所有 rank 是否都启动?
12. NCCL 初始化是否成功?
13. 数据读取是否正常?
14. checkpoint 和模型输出是否正常?
15. 平台状态、日志、指标、产物是否回写?

11. 两个例子

例子 A:8 卡任务一直 Pending

不要先看训练日志,因为训练还没开始。

排查路径:

text 复制代码
Pod Pending
-> 看 describe pod 的 Events
-> 如果是 Insufficient nvidia.com/gpu
-> 看任务要求单机 8 卡还是分布式 8 卡
-> 看节点 allocatable GPU
-> 看队列和配额
-> 看是否 GPU 资源碎片

常用命令:

bash 复制代码
kubectl describe pod <pod> -n <namespace>
kubectl get events -n <namespace> --sort-by=.lastTimestamp | tail -100
kubectl describe node <node> | grep -A8 -B8 nvidia.com/gpu

例子 B:Pod Running,但没有进入训练日志

这时不能直接判断是代码问题。

排查路径:

text 复制代码
Pod Running
-> 看容器日志是否完全没有输出
-> 看启动脚本是否卡在数据准备或模型下载
-> exec 进去看进程是否存在
-> 看容器内 nvidia-smi 是否正常
-> 如果是分布式任务,看所有 rank 是否都启动
-> 看是否卡在 torchrun rendezvous 或 NCCL init

常用命令:

bash 复制代码
kubectl logs <pod> -n <namespace>
kubectl exec -it <pod> -n <namespace> -- ps -ef
kubectl exec -it <pod> -n <namespace> -- nvidia-smi

12. 最终记忆版

把训练任务排障记成这条链:

text 复制代码
有没有任务
-> 有没有 K8s 资源
-> 有没有 Pod
-> Pod 是什么状态
-> 有没有分到节点
-> 容器有没有启动
-> GPU 能不能看到
-> 训练进程有没有起来
-> 分布式通信有没有成功
-> 数据和产物有没有正常读写
-> 平台状态有没有回写

这就是训练平台排障的主干。后面所有技术点,都是在补强这条链上的某一段。

相关推荐
用户723429355335 小时前
Kubernetes 基础对象:Pod、Job、Deployment、Service 等
aiops
析数塔1 天前
AI 时代测试开发新范式:从用例验证到 Agent 评测体系
agent·测试·aiops
SRETalk3 天前
如何使用 AI 解答开源项目的问题,其实只需要一句话
aiops·categraf
SRETalk4 天前
夜莺开源监控如何使用 Docker 部署,有哪些注意事项?
aiops·夜莺监控
小猿姐15 天前
MySQL Top 10 热点问题 AI 运维实战:从内核诊断到云原生运维
mysql·云原生·aiops
属鼠哥16 天前
一场正在发生的范式转变:Loop Engineering(循环工程)
人工智能·aiops
AIOps打工人17 天前
新人用 AI 30 分钟,我并不高兴
aiops
松岩20 天前
网络问题导致 Pod Pending
kubernetes·aiops