训练工程与训练平台入门 31 安装 Kubeflow Trainer,并跑第一个 TrainJob

这一节我们真正把:

复制代码
python train.py

变成:

复制代码
Kubernetes
→ Kubeflow Trainer
→ TrainJob
→ Pod
→ PyTorch

先跑 CPU,不碰 GPU。

目前官方安装文档给出的稳定 Trainer 版本是 v2.1.0,要求 Kubernetes 和 kubectl ≥ 1.31;官方也直接推荐没有集群时使用 Kind 或 Minikube。 Kubeflow培训师

1. 先确认本地 Kubernetes

上一节你已经知道需要 Docker、Kind、kubectl。

执行:

css 复制代码
docker --version
kubectl version --client
kind version

如果还没创建 Kind 集群:

lua 复制代码
kind create cluster

然后:

arduino 复制代码
kubectl get nodes

目标是看到:

复制代码
NAME                 STATUS
kind-control-plane   Ready

这里实际上已经完成:

复制代码
Mac
 ↓
Docker
 ↓
Kind Node
 ↓
Kubernetes

注意,此时还没有 Kubeflow。


2. 安装 Helm

当前官方 Trainer 安装方式之一就是 Helm。

Mac 上如果没有:

复制代码
brew install helm

检查:

复制代码
helm version

然后安装 Kubeflow Trainer:

arduino 复制代码
export VERSION=v2.1.0

helm install kubeflow-trainer \
  oci://ghcr.io/kubeflow/charts/kubeflow-trainer \
  --namespace kubeflow-system \
  --create-namespace \
  --version ${VERSION#v} \
  --wait
  
 kubectl apply --server-side -k \
  "https://github.com/kubeflow/trainer.git/manifests/overlays/runtimes?ref=v2.1.0"

最后这个:

lua 复制代码
kubectl apply --server-side -k \
  "https://github.com/kubeflow/trainer.git/manifests/overlays/runtimes?ref=v2.1.0"

很重要。

它除了安装 Trainer Controller,还安装默认的 ClusterTrainingRuntime,这样我们后面可以直接使用现成的 PyTorch Runtime。官方当前安装文档支持这种方式。 Kubeflow培训师


3. 检查安装结果

执行:

sql 复制代码
kubectl get pods -n kubeflow-system

应该能看到类似:

复制代码
jobset-controller-manager
kubeflow-trainer-controller-manager

状态最终应该是:

sql 复制代码
Running

官方也是通过这两个 Controller Pod 来验证 Trainer 控制面的安装。 Kubeflow培训师

再执行:

arduino 复制代码
kubectl get clustertrainingruntime

这里应该能看到默认 Runtime。

例如其中会有 Torch 相关 Runtime。

到这里,你的环境已经变成:

复制代码
Mac
 ↓
Docker
 ↓
Kind
 ↓
Kubernetes
 ↓
Kubeflow Trainer Controller
 ↓
ClusterTrainingRuntime

但还没有真正的训练任务。


4. Runtime 到底是什么?

这里停一下,因为这是 Trainer v2 最值得训练平台工程师理解的设计。

你马上要创建:

复制代码
TrainJob

但 TrainJob 不需要自己描述所有底层 Kubernetes 细节。

它引用:

复制代码
ClusterTrainingRuntime

关系是:

markdown 复制代码
Platform Admin
      ↓
ClusterTrainingRuntime
      ↓
规定训练任务怎么运行

AI Engineer
      ↓
TrainJob
      ↓
描述这一次训练什么

官方对 Runtime 的定位就是可复用的训练模板/蓝图,由平台管理员管理,TrainJob 引用它。 Kubeflow

这其实非常像企业训练平台的设计。

平台团队提前准备:

objectivec 复制代码
PyTorch Runtime
DeepSpeed Runtime
MPI Runtime
...

用户只提交:

复制代码
我要用 PyTorch Runtime
跑这个 Image
执行这个 Command
需要这些资源

5. 提交我们的第一个 TrainJob

我们先不用自己的 MNIST Image。

原因很简单:如果现在同时引入:

css 复制代码
Dockerfile
Image Build
Kind load
MNIST Code
TrainJob

一次变量太多。

先用 Kubeflow 官方示例镜像,把 TrainJob 链路跑通

官方 Trainer v2 的典型 TrainJob 是这样的结构:runtimeRef + trainer + image + commandKubeflow培训师

创建:

yaml 复制代码
cat > mnist-trainjob.yaml <<'EOF'
apiVersion: trainer.kubeflow.org/v1alpha1
kind: TrainJob
metadata:
  name: mnist-demo
spec:
  runtimeRef:
    name: torch-distributed
    kind: ClusterTrainingRuntime
    apiGroup: trainer.kubeflow.org

  trainer:
    numNodes: 1
    image: docker.io/kubeflowkatib/pytorch-mnist:v1beta1-45c5727
    command:
      - python3
      - /opt/pytorch-mnist/mnist.py
      - --epochs=1
EOF

然后:

复制代码
kubectl apply -f mnist-trainjob.yaml

如果创建成功:

bash 复制代码
trainjob.trainer.kubeflow.org/mnist-demo created

不过这里提醒一下:Kubeflow Trainer 近期 API 正在持续演进,例如 v2.2 已引入 v2alpha1 和 breaking changes,因此如果你本机安装的不是这里使用的 v2.1.0,YAML 字段要跟对应版本文档走。 Kubeflow


6. 这一条 apply 背后发生了什么?

这是本节最关键的地方。

你执行:

复制代码
kubectl apply -f mnist-trainjob.yaml

第一步,Kubernetes API Server 收到:

ini 复制代码
kind = TrainJob
name = mnist-demo

但普通 Kubernetes 本身不知道:

复制代码
TrainJob

是什么。

为什么现在它认识?

因为我们刚才安装 Trainer 时,同时安装了:

复制代码
CRD

也就是:

复制代码
CustomResourceDefinition

Trainer 给 Kubernetes 增加了新的资源类型:

复制代码
TrainJob
TrainingRuntime
ClusterTrainingRuntime

官方 Helm Chart 默认会安装这些 CRD。 Kubeflow培训师

所以:

diff 复制代码
原生 Kubernetes

Pod
Deployment
Job
Service
...

安装 Trainer 后

+
TrainJob
TrainingRuntime
ClusterTrainingRuntime

这就是 Kubernetes Operator 体系非常核心的思想。


7. Controller 开始工作

Trainer Controller 会监听:

复制代码
TrainJob

发现:

复制代码
mnist-demo

然后读取:

yaml 复制代码
runtimeRef:
  name: torch-distributed

相当于:

我要使用平台预先定义好的 Torch Runtime。

然后结合:

yaml 复制代码
trainer:
  numNodes: 1
  image: ...
  command: ...

生成真正的 Kubernetes 工作负载。

最终 Kubernetes 创建:

复制代码
Pod

并运行这个 Image。

完整链路变成:

arduino 复制代码
kubectl apply
      ↓
Kubernetes API
      ↓
TrainJob
      ↓
Kubeflow Trainer Controller
      ↓
读取 ClusterTrainingRuntime
      ↓
生成训练工作负载
      ↓
Kubernetes Scheduler
      ↓
Pod
      ↓
Container
      ↓
python3 mnist.py
      ↓
PyTorch

这条链是你作为训练平台工程师真正应该掌握的。


8. 看任务,而不是盯 YAML

执行:

arduino 复制代码
kubectl get trainjob

然后:

arduino 复制代码
kubectl get pods

你应该能看到 TrainJob 最终产生的 Pod。

可以持续观察:

arduino 复制代码
kubectl get pods -w

Pod 状态可能经历:

sql 复制代码
Pending
↓
ContainerCreating
↓
Running
↓
Completed

这其实就是训练平台页面里的:

复制代码
创建中
排队中
运行中
成功

底层来源之一。


9. 看训练日志

找到对应 Pod 后:

xml 复制代码
kubectl logs <pod-name>

你最终看到的还是熟悉的:

erlang 复制代码
Train Epoch ...
Loss ...
Accuracy ...

这一刻非常关键。

因为我们绕了一大圈:

复制代码
Kubeflow
Kubernetes
CRD
Controller
Runtime
TrainJob
Pod
Container

最终里面干的还是:

复制代码
Dataset
↓
Forward
↓
Loss
↓
Backward
↓
Optimizer

也就是我们第一阶段学的东西。


10. 把 YAML 和训练平台页面一一对应

现在再看:

yaml 复制代码
trainer:
  numNodes: 1

相当于训练平台上的:

复制代码
节点数量 = 1
arduino 复制代码
image:

对应:

复制代码
运行镜像
bash 复制代码
command:

对应:

复制代码
启动命令
makefile 复制代码
runtimeRef:

可以对应:

复制代码
训练框架 / Runtime 模板

以后页面上可能不会把:

复制代码
ClusterTrainingRuntime

这个 Kubernetes 名字直接暴露给用户。

可能包装成:

复制代码
PyTorch 2.x

DeepSpeed

LLM Training Runtime

但底层思路是一致的。


11. 为什么 Runtime 设计对平台很有价值?

假设没有 Runtime。

100 个用户,每次都得知道:

bash 复制代码
JobSet
Pod Template
Torch distributed env
restart policy
network
launcher
...

这显然不适合训练平台。

有 Runtime:

swift 复制代码
平台管理员

定义一次:
torch-distributed
        ↓
包含基础设施模板


普通用户

TrainJob A → torch-distributed
TrainJob B → torch-distributed
TrainJob C → torch-distributed

于是平台把:

基础设施复杂度

从算法/训练用户那里拿走了。

这就是 Trainer v2 的一个核心设计目标:把基础设施配置和具体训练任务定义分开。 Kubeflow

这和你以后理解企业内部训练平台会非常接近。


本节总结

今天我们第一次真正把:

复制代码
python train.py

变成了:

复制代码
TrainJob
   ↓
Runtime
   ↓
Trainer Controller
   ↓
Kubernetes workload
   ↓
Pod
   ↓
Container
   ↓
python train.py
   ↓
PyTorch

其中你需要真正记住四个东西:

TrainJob 表示"一次训练任务"。

ClusterTrainingRuntime / TrainingRuntime 表示"平台预先准备的训练运行模板"。

Trainer Controller 负责把 TrainJob + Runtime 转换成真正可运行的 Kubernetes 工作负载。

Pod / Container 才是最后真正执行 python train.py 的地方。

所以训练平台用户提交的:

复制代码
训练任务

最终一定会逐渐落到非常具体的东西:

diff 复制代码
程序
+
环境
+
资源
+
数据
+
启动命令
相关推荐
用户938515635071 小时前
从 0 拆解一个 Next.js 笔记系统:npx、App Router、RSC 与组件规划全记录
前端·后端·全栈
fatcoder2 小时前
玩转Docker 06 — 容器网络
前端·后端·docker
feng尘2 小时前
深入浅出 Java:ThreadLocal 为什么会产生内存泄漏?
后端
懒人wsh3 小时前
不上悲观锁也不上 Redis:一个 AI 平台的钱包并发是怎么搞的
后端
神奇小汤圆3 小时前
记一次线上翻车:加了Redisson分布式锁,数据还是被并发打穿了
后端
南雨北斗3 小时前
ThinkPHP6 设置响应 `Content-Type: application/json`
后端
用户3945071778244 小时前
Git 安装与 SSH 公钥配置教程
后端