1. 训练任务为什么一直停在 Pending
在 Java 平台里创建训练任务以后,数据库很快就能生成一条 TrainingJob。页面显示“排队中”,真正执行训练的 Pod 却可能一直没有启动。
这时只看 Spring Boot 日志,通常找不到原因。任务已经离开业务接口,进入了另一条链路:
TrainingJob
→ Kubernetes Job
→ Pod
→ Scheduler
→ GPU Node
→ Container Runtime
→ Driver / Device Plugin
→ Dataset Volume任何一层没有准备好,训练进程都无法开始。Kubernetes 节点因此不能只理解成“一台装了 Docker 的 Linux 服务器”。它同时承载资源发现、工作负载运行、网络、临时磁盘和数据卷挂载。
2. 调度器看到的是资源与约束
Kubernetes 通过设备插件把 GPU 暴露成扩展资源。训练 Pod 一般在 limits 中申请 GPU:
apiVersion: batch/v1
kind: Job
metadata:
name: train-policy-v12
spec:
template:
spec:
restartPolicy: Never
containers:
- name: trainer
image: registry.example/trainer:2026-08
resources:
requests:
cpu: "4"
memory: 16Gi
limits:
cpu: "8"
memory: 32Gi
nvidia.com/gpu: "1"镜像名和资源数值只是示例。实际值要结合模型、批量大小、精度和运行时测量确定。
如果集群没有可用的 nvidia.com/gpu,或者可用节点受到污点、亲和性和配额限制,Pod 会保持 Pending。调度器负责把 Pod 放到满足条件的节点;它不会替训练程序安装正确驱动,也不会判断某个模型一定能放进显存。
排查时应该先看 Pod 条件和调度事件:
kubectl get pod -n ai-training
kubectl describe pod train-policy-v12-xxxxx -n ai-training
kubectl get node -L accelerator日志里如果还没有容器启动记录,问题可能发生在调度或镜像拉取阶段,继续翻训练脚本没有帮助。
3. 节点状态会沿着平台链路向上冒泡
一个节点至少涉及下面几类状态:
| 节点条件 | 对训练任务的影响 |
|---|---|
| CPU、内存不足 | Pod 无法调度,或者与其他任务争用资源 |
| GPU 未被设备插件发现 | 调度器看不到可申请的 GPU |
| 镜像磁盘不足 | 镜像拉取或容器创建失败 |
| 临时磁盘不足 | DataLoader、日志或中间文件写入失败 |
| 数据卷挂载失败 | 容器可能停在创建阶段 |
| 节点网络异常 | 无法拉取镜像、读取对象存储或上报状态 |
Kubernetes 的资源请求参与调度,资源限制约束容器运行。只填写 GPU、不填写 CPU 和内存,会让调度器缺少完整需求,也容易造成节点上多个任务相互影响。
节点本地盘还可能同时保存镜像层、容器日志、临时文件和数据缓存。训练读取缓存增长时,如果没有空间上限和清理策略,最终影响的可能是同一节点上的其他服务。
4. 容器 Running 仍然不等于训练可用
Pod 进入 Running,只能说明容器进程已经启动。训练真正开始前还要确认:
GPU 在容器内可见
数据卷已经挂载
数据集版本存在
配置和检查点可以读取
输出目录可以写入
状态上报地址可访问训练容器可以增加启动检查,把这些前置条件变成明确失败。检查不应执行完整训练,也不应把凭据写入日志。
Kubernetes Volume 让文件出现在容器目录里,其中临时卷跟随 Pod 生命周期,持久卷拥有独立生命周期。数据集、检查点和模型产物需要根据恢复目标选择存储位置,不能默认写在容器根文件系统。
5. Pod 重建与训练恢复是两件事
节点故障以后,控制器可以创建新的 Pod。新的 Pod 是否能从上次进度继续,取决于训练程序和检查点:
Kubernetes 恢复:重新创建运行环境
训练程序恢复:读取兼容的 checkpoint 继续计算检查点可能包含模型权重、优化器、学习率调度器和当前步数。只保存最终权重,无法自然恢复训练过程。数据集版本、代码版本和参数也要与检查点关联,否则“继续运行”可能已经换了输入条件。
6. Java 平台需要保存两套状态
Java 控制面不能把 Kubernetes Pod Phase 直接当成完整业务状态。可以分别记录:
业务状态:CREATED → QUEUED → RUNNING → SUCCEEDED / FAILED
运行状态:Job 名称、Pod、节点、调度原因、退出码Spring Boot 负责权限、任务参数、数据版本、幂等提交和历史记录;Kubernetes 负责工作负载生命周期。同步程序根据 Job 和 Pod 状态更新运行记录,并保留原始原因,例如 Unschedulable、镜像拉取失败或容器退出。
页面上的“排队中”也应该继续细分原因。等待配额、等待 GPU、等待数据卷和控制面尚未创建 Job,对使用者来说需要采取不同动作。
把训练任务放进 Kubernetes 链路以后,节点状态与业务状态之间的关系会更清楚:平台提交成功只是开始,调度、运行时、GPU 和存储共同决定任务能否真正执行。排查时沿着“业务状态 vs 运行状态”两条线走,比只盯进程、端口和内存更容易定位问题。
相关阅读
- 从 Docker Compose 到 Kubernetes:AI 数据平台为什么需要统一运行底座
- 机器人训练数据怎样送到 GPU:Kubernetes、JuiceFS 与 Lance 的分工
- 模型推理服务怎样运行在 Kubernetes:版本、KServe、灰度与回滚