这份文档先补 Kubernetes 基础概念。训练平台、推理平台、MLOps 平台最终都要落到 Kubernetes 对象上,所以必须先知道这些对象是什么、解决什么问题、彼此怎么关联。
一句话理解 Kubernetes:Kubernetes 是一个管理容器的集群操作系统。
它不直接管理你的 Python 脚本,而是管理这些对象:
| 对象 | 可以先理解成 | 主要作用 |
|---|---|---|
| Node | 机器 | 承载 Pod 和容器 |
| Namespace | 项目空间 | 做团队、项目、租户隔离 |
| Container | 运行中的程序环境 | 真正执行训练、推理或服务进程 |
| Pod | 最小调度单元 | Kubernetes 调度和管理的基本单位 |
| Job | 一次性任务 | 管训练、数据处理、离线任务 |
| Deployment | 长期服务 | 管 API、控制器、推理服务等常驻副本 |
| Service | 稳定访问入口 | 给一组 Pod 提供固定访问地址 |
| ConfigMap | 普通配置 | 保存非敏感配置 |
| Secret | 敏感配置 | 保存密码、token、密钥、证书 |
| PVC | 存储声明 | 给 Pod 申请持久化存储 |
1. 总览图
text
Cluster
├── Node:集群里的机器
│ ├── kubelet
│ ├── containerd
│ └── Pod
│ └── Container
│
└── Namespace:逻辑隔离空间
├── Job -> Pod -> Container
├── Deployment -> ReplicaSet -> Pod -> Container
├── Service
├── ConfigMap
├── Secret
└── PVC
最重要的三条关系:
- 训练任务:
Job -> Pod -> Container -> python train.py - 平台服务:
Deployment -> ReplicaSet -> Pod -> Container -> api server - 推理服务:
Deployment/CRD -> Pod -> Container -> model server -> Service
2. Node:集群里的机器
Node 是 Kubernetes 集群里的机器,可以是物理机,也可以是云主机。你可以先简单理解为:Node = 一台服务器。
AI Infra 里常见节点类型:
| 节点类型 | 作用 |
|---|---|
| CPU 节点 | 跑平台 API、控制器、普通服务 |
| GPU 节点 | 跑训练任务、推理服务 |
| 存储节点 | 提供数据、缓存或并行存储能力 |
| 控制面节点 | 跑 apiserver、scheduler、controller-manager 等核心组件 |
每个工作节点通常会有这些组件:
kubelet:节点代理,负责管理本机 Pod。containerd:容器运行时,负责拉镜像、启动容器。CNI:容器网络插件。CSI/Volume plugin:存储挂载插件。NVIDIA driver:GPU 驱动,GPU 节点才有。NVIDIA Device Plugin:把 GPU 上报给 Kubernetes。
常用命令:
bash
kubectl get node
kubectl get node -o wide
kubectl describe node <node-name>
GPU 节点重点看:
Allocatable里有没有nvidia.com/gpu。- 节点是否
Ready。 - 节点是否有
taint。 - 节点
label是否符合任务要求。 - CPU、内存、GPU 是否足够。
3. Namespace:逻辑隔离空间
Namespace 是 Kubernetes 里的逻辑隔离空间。你可以理解为:Namespace = 项目空间 / 团队空间 / 租户空间。
例如:team-a、team-b、lpai、monitoring、kube-system。
不同 namespace 里可以有同名 Pod,不冲突。AI 平台通常会用 namespace 做团队隔离、项目隔离、权限隔离、资源配额隔离,以及日志和任务归属区分。
常用命令:
bash
kubectl get ns
kubectl get pod -n <namespace>
kubectl get all -n <namespace>
注意:如果你不加 -n,kubectl 默认查 default namespace,排障时很容易查错地方。
4. Container:真正运行程序的地方
Container 是真正运行程序的环境。比如训练容器里可能执行:
bash
python train.py
或者分布式训练命令:
bash
torchrun --nproc_per_node=8 train.py
容器来自镜像:
| 概念 | 含义 |
|---|---|
| Image | 模板,包含文件系统、依赖、代码、启动环境 |
| Container | 镜像运行起来后的实例 |
训练容器可能包含 Ubuntu/CentOS、CUDA、cuDNN、Python、PyTorch、训练代码、业务依赖和启动脚本。
推理容器可能包含 Triton、vLLM、TensorRT-LLM、模型加载逻辑、HTTP/gRPC server、模型文件下载逻辑。
关键点:Kubernetes 不直接调度单个 Container,而是调度 Pod。
5. Pod:Kubernetes 最小调度单元
Pod 是 Kubernetes 里最小的调度和运行单元。你可以理解为:Pod = 一个或多个 Container 的组合。
大多数业务场景下,一个 Pod 里只有一个主容器。但有时也会有多个容器。
同一个 Pod 里的容器共享:
- 同一个 Pod IP。
- 同一个网络命名空间。
- 可以共享 volume。
- 一定被调度到同一台 Node。
- 生命周期强相关。
Pod 里常见容器类型:
| 类型 | 作用 |
|---|---|
| 主容器 | 真正跑业务,例如训练进程、推理服务 |
| init container | 主容器启动前先执行,例如准备目录、下载配置 |
| sidecar container | 辅助容器,例如日志采集、代理、service mesh sidecar |
训练平台里的 Pod 可能长这样:
text
Pod: train-resnet-xxxxx
├── main container: pytorch-training
│ └── command: python train.py
├── volume: training-data
├── env: NCCL_DEBUG=INFO
└── resources: cpu / memory / nvidia.com/gpu
常用命令:
bash
kubectl get pod -n <namespace>
kubectl get pod -n <namespace> -o wide
kubectl describe pod <pod> -n <namespace>
kubectl logs <pod> -n <namespace>
kubectl exec -it <pod> -n <namespace> -- bash
如果 Pod 里有多个容器,需要指定容器名:
bash
kubectl logs <pod> -n <namespace> -c <container-name>
kubectl exec -it <pod> -n <namespace> -c <container-name> -- bash
6. Pod 生命周期和状态判断
学 Kubernetes 排障时,光知道 Pod 是什么还不够,还要知道 Pod 从创建到运行经历哪些阶段。Pod 状态不是简单的"排队、运行、失败",它是在告诉你 Pod 卡在生命周期的哪一步。
一个 Pod 的典型链路是:
text
创建 Pod -> 等待调度 -> 分配节点 -> 节点准备环境 -> 拉镜像 -> 挂载卷 -> 启动容器 -> Running -> Succeeded/Failed
Pending 不一定等于排队
Pending 有两种常见情况。
第一种是还没有调度到节点。这时 Node 为空,Events 里通常能看到 FailedScheduling。常见原因是 CPU、内存、GPU 不足,队列未准入,配额不足,亲和性不满足,节点污点不容忍,或者 PVC 没绑定。
第二种是已经调度到节点,但容器还没启动。这时 Node 已经有值,Events 里可能出现 FailedMount、FailedCreatePodSandBox、Pulling image 等事件。这种不是还在排队,而是节点准备阶段失败。
判断方式:
bash
kubectl get pod <pod> -n <namespace> -o wide
kubectl describe pod <pod> -n <namespace>
重点看 Node 和 Events。
ContainerCreating:容器启动前准备阶段
ContainerCreating 表示 Pod 已经到节点上了,但容器还没有真正跑起来。这一阶段通常在做网络准备、volume 挂载、Secret/ConfigMap 准备、镜像准备、runtime 创建容器。
常见事件和含义:
| 事件 | 常见原因 |
|---|---|
| FailedMount | PVC、Secret、ConfigMap、CSI、存储系统问题 |
| FailedCreatePodSandBox | CNI 网络插件、pause 容器、containerd sandbox 问题 |
| CreateContainerConfigError | ConfigMap/Secret 不存在,环境变量引用错误 |
| CreateContainerError | runtime 创建容器失败,权限、挂载、runtime 配置问题 |
如果看到 Unable to attach or mount volumes,一般说明 Pod 已经调度到节点,但 kubelet 挂载 volume 失败或超时,不是还在调度排队。
ImagePullBackOff:镜像拉取问题
ImagePullBackOff 或 ErrImagePull 表示卡在拉镜像。
常见原因:镜像地址错误,tag 不存在,镜像仓库无权限,imagePullSecret 缺失,节点到仓库网络不通,镜像太大拉取超时,节点磁盘满。
Events 里常见线索:
| 线索 | 含义 |
|---|---|
| manifest unknown | 镜像 tag 不存在 |
| pull access denied | 镜像仓库权限问题 |
| i/o timeout | 网络或 registry 访问问题 |
| no space left on device | 节点磁盘满 |
Running:只代表容器进程活着
Running 不代表业务一定正常。它只说明至少有容器已经启动。
训练任务里常见情况包括:Pod Running 但训练没开始,GPU 利用率为 0,没有训练日志,卡在 torchrun rendezvous,或者 NCCL 初始化卡住。
这时才开始看业务日志和容器内部状态:
bash
kubectl logs <pod> -n <namespace>
kubectl exec -it <pod> -n <namespace> -- ps -ef
kubectl exec -it <pod> -n <namespace> -- nvidia-smi
CrashLoopBackOff:容器启动后反复崩
CrashLoopBackOff 表示容器启动了,但很快退出,Kubernetes 按退避策略反复重启。
排查时要看当前日志和上一轮日志:
bash
kubectl logs <pod> -n <namespace>
kubectl logs <pod> -n <namespace> --previous
--previous 很重要,因为上一轮崩溃容器的日志往往才是真正原因。
OOMKilled:容器内存超限
OOMKilled 表示容器 CPU 内存超过 limit,被 cgroup 杀掉。它不是 GPU 显存 OOM。
区别如下:
| 类型 | 表现 |
|---|---|
| 容器内存 OOM | K8s 里看到 OOMKilled,退出码常见 137,Pod 可能重启 |
| GPU 显存 OOM | 训练日志里看到 CUDA out of memory,Pod 不一定重启 |
Succeeded 和 Failed
对于 Job 或训练任务,Succeeded 表示容器正常退出,退出码通常是 0;Failed 表示容器异常退出,退出码非 0,或者被系统杀掉。
常见退出码:
| 退出码 | 常见含义 |
|---|---|
| 0 | 正常退出 |
| 1 | 应用普通错误 |
| 126 | 命令不可执行 |
| 127 | 命令不存在 |
| 137 | SIGKILL,常见 OOMKilled |
| 143 | SIGTERM,常见被删除、驱逐、优雅终止 |
最小判断顺序
看到 Pod 异常时,先按这个顺序判断:
- Pod 有没有 Node。没有 Node,优先看调度;有 Node,优先看节点准备或容器运行。
- Events 里是什么。
FailedScheduling看调度,FailedMount看存储/volume,FailedCreatePodSandBox看网络/CNI/sandbox,ImagePullBackOff看镜像,CrashLoopBackOff看容器日志,OOMKilled看内存。 - 容器有没有真正启动。没启动时不要先看业务日志,先查 Events、kubelet、containerd;启动后再看 logs、previous logs、进程、端口和 GPU。
7. Job:一次性任务
Job 是 Kubernetes 里表示"一次性任务"的对象。你可以理解为:Job = 管理一次性 Pod 的控制器。
Job 的目标是创建 Pod,等待 Pod 成功结束;如果失败,根据策略重试;最终 Job 进入 Complete 或 Failed。
Job 适合这些场景:
- 训练任务。
- 数据处理任务。
- 模型转换任务。
- 离线评估任务。
- 批处理脚本。
这些任务的共同特点是:开始、运行一段时间、成功或失败、结束。
Job 和 Pod 的关系:Job -> Pod -> Container -> python train.py。
Job 不直接跑代码,它负责创建和管理 Pod。Pod 里的 Container 才真正执行命令。
常用命令:
bash
kubectl get job -n <namespace>
kubectl describe job <job> -n <namespace>
kubectl get pod -n <namespace> --selector=job-name=<job-name>
常见问题:
- Job 创建了但 Pod 没生成。
- Pod 失败后 Job 不断重试。
backoffLimit达到上限,JobFailed。- Job
Complete但平台状态没同步。
8. Deployment:长期运行服务
Deployment 用来管理长期运行的服务。你可以理解为:Deployment = 管理常驻服务副本的控制器。
它的目标是保证始终有指定数量的 Pod 在运行。例如声明 replicas = 3,如果一个 Pod 挂了,Deployment 会再创建一个新的 Pod,让副本数回到 3。
Deployment 适合这些场景:
- 平台 API 服务。
- Web 后端。
- Controller 服务。
- 推理服务。
- 日志服务。
- 普通常驻服务。
Deployment 和 Job 的区别:
| 对象 | 适合场景 | 行为 |
|---|---|---|
| Job | 一次性任务 | 跑完就结束 |
| Deployment | 长期服务 | 一直保持副本运行 |
训练任务通常用 Job 或训练 CRD。平台 API 和推理服务通常用 Deployment 或更高层 CRD。
常用命令:
bash
kubectl get deploy -n <namespace>
kubectl describe deploy <deploy> -n <namespace>
kubectl rollout status deploy/<deploy> -n <namespace>
kubectl rollout history deploy/<deploy> -n <namespace>
9. ReplicaSet:Deployment 背后的副本控制器
ReplicaSet 负责保证某个 Pod 模板有指定数量的副本。
通常你不会直接操作 ReplicaSet,因为 Deployment 会自动管理它。它们的关系是:Deployment -> ReplicaSet -> Pod。
为什么要知道它?因为排查 Deployment 时经常会看到 ReplicaSet。滚动发布时,Deployment 会创建新的 ReplicaSet,并逐渐替换旧的 ReplicaSet。
常用命令:
bash
kubectl get rs -n <namespace>
kubectl describe rs <replicaset> -n <namespace>
10. Service:稳定访问入口
Pod 的 IP 是临时的。Pod 删除重建后,IP 可能变化。
Service 用来给一组 Pod 提供稳定访问入口。你可以理解为:Service = 一组 Pod 的固定访问地址。
比如有 3 个推理 Pod:
| Pod | IP |
|---|---|
| model-pod-1 | 10.1.1.1 |
| model-pod-2 | 10.1.1.2 |
| model-pod-3 | 10.1.1.3 |
Service 提供一个稳定名字:model-service.default.svc.cluster.local。调用方访问 Service,Service 再把请求转发到后端 Pod。
在 AI 平台里的作用:
- 训练场景:分布式训练可能用 Service 做 master/rendezvous 地址。
- 推理场景:在线请求通过 Service 访问模型服务。
- 平台场景:Web/API/controller 之间通过 Service 互相访问。
常用命令:
bash
kubectl get svc -n <namespace>
kubectl describe svc <svc> -n <namespace>
kubectl get endpoints -n <namespace>
kubectl get endpointslice -n <namespace>
常见问题:
- Service 存在但 endpoints 为空。
- selector 配错,选不到 Pod。
- Pod readiness 失败,不进入 endpoints。
- 端口映射错误。
- DNS 解析失败。
- 网络策略阻断。
11. ConfigMap:普通配置
ConfigMap 用来保存普通配置,例如配置文件、启动参数、环境变量、非敏感开关、模型服务配置、训练参数模板。
Pod 可以把 ConfigMap 注入为环境变量、配置文件或挂载目录。
常用命令:
bash
kubectl get cm -n <namespace>
kubectl describe cm <configmap> -n <namespace>
kubectl get cm <configmap> -n <namespace> -o yaml
注意:ConfigMap 不适合放密码、token、AK/SK。敏感信息应该放 Secret。
12. Secret:敏感配置
Secret 用来保存敏感信息,例如数据库密码、对象存储 AK/SK、token、证书、镜像仓库拉取密钥。
Pod 可以通过环境变量或文件挂载使用 Secret。
常用命令:
bash
kubectl get secret -n <namespace>
kubectl describe secret <secret> -n <namespace>
kubectl get secret <secret> -n <namespace> -o yaml
Secret 比 ConfigMap 更适合放敏感信息,但它不是绝对安全。生产环境还需要结合 RBAC 权限控制、etcd 加密、审计日志、密钥轮转和最小权限原则。
13. PVC:持久化存储声明
PVC 全称 PersistentVolumeClaim,表示 Pod 向 Kubernetes 申请一块持久化存储。你可以理解为:PVC = Pod 申请一块可挂载的存储。
Pod 是临时的。Pod 删除后,容器里的临时文件也会消失。训练任务通常需要持久化训练数据、checkpoint、模型输出、评估结果和共享工作目录,所以需要 PVC、对象存储或并行文件系统。
常用命令:
bash
kubectl get pvc -n <namespace>
kubectl describe pvc <pvc> -n <namespace>
常见问题:
- PVC
Pending:没有绑定到 PV。 MountVolume failed:挂载失败。- 权限问题:容器内无法读写。
- 容量不足:写 checkpoint 失败。
- 存储慢:训练数据读取慢、checkpoint 慢。
14. Label 和 Selector
Label 是 Kubernetes 对象上的键值对标签,例如:
yaml
labels:
app: training-api
task: train-resnet
user: zhangsan
Selector 用来选择带有某些 label 的对象。
为什么重要:
- Service 通过 selector 找后端 Pod。
- Deployment 通过 selector 管理自己的 Pod。
- 平台经常用 label 标记任务、用户、队列、项目。
常用命令:
bash
kubectl get pod -n <namespace> --show-labels
kubectl get pod -n <namespace> -l app=training-api
常见问题:
- Service selector 配错,导致 endpoints 为空。
- Deployment selector 和 Pod label 不匹配,导致副本管理异常。
15. Taint 和 Toleration
Taint 是节点上的排斥标记,Toleration 是 Pod 对这种排斥的容忍。
简单理解:Node 有 taint 时,默认不让普通 Pod 上来;Pod 有对应 toleration 时,才允许调度到这个 Node。
AI Infra 里常见用途:
- GPU 节点打 taint,避免普通服务占用 GPU 节点。
- 故障节点打 taint,禁止新任务调度。
- 专属队列节点打 taint,只允许特定团队使用。
常用命令:
bash
kubectl describe node <node> | grep -i taint
如果 Pod Pending,Events 里看到 had untolerated taint,说明 Pod 没有对应 toleration。
16. Resource Request 和 Limit
Kubernetes 通过 request 和 limit 管理资源:
| 字段 | 含义 |
|---|---|
| request | 调度时承诺需要多少资源 |
| limit | 运行时最多能使用多少资源 |
例子:
yaml
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: "1"
limits:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: "1"
Scheduler 主要看 request 来决定能不能调度。cgroup 会用 limit 来限制容器资源。
常见问题:
- request 太大:Pod Pending,调度不上。
- limit 太小:容器 OOMKilled。
- 没有设置 GPU request:容器拿不到 GPU。
- CPU limit 太低:数据加载慢,GPU 利用率低。
17. 训练任务对象关系例子
一个普通训练任务可能长这样:
text
Namespace: team-a
└── Job: train-resnet
└── Pod: train-resnet-xxxxx
├── Container: pytorch-training
│ └── Command: python train.py
├── ConfigMap: training-config
├── Secret: object-storage-secret
├── PVC: training-data
└── Resources: cpu=8, memory=64Gi, nvidia.com/gpu=1
如果是分布式训练,可能是:
text
PyTorchJob: bert-pretrain
├── master Pod -> Container: rank 0
├── worker Pod 1 -> Container: rank 1
├── worker Pod 2 -> Container: rank 2
└── worker Pod 3 -> Container: rank 3
18. 平台服务对象关系例子
平台 API 服务可能长这样:
text
Namespace: ai-platform
├── Deployment: training-api
│ └── ReplicaSet
│ ├── Pod: training-api-xxx1
│ ├── Pod: training-api-xxx2
│ └── Pod: training-api-xxx3
├── Service: training-api-service
│ └── selects pods with app=training-api
├── ConfigMap: training-api-config
└── Secret: training-api-secret
Deployment 保证 API Pod 数量稳定,Service 给这些 Pod 提供稳定访问入口。
19. 推理服务对象关系例子
推理服务可能长这样:
text
Namespace: model-serving
├── Deployment: llama-serving
│ └── Pod: llama-serving-xxxxx
│ └── Container: vllm-runtime
│ └── Command: start model server
├── Service: llama-serving-svc
│ └── exposes model server
├── PVC or object storage
│ └── model files
└── ConfigMap / Secret
└── model config and credentials
推理服务更关注服务是否 Ready、Service endpoints 是否正常、模型是否加载成功、GPU 显存是否够、请求延迟和错误率是否正常。
20. 日常最常用命令
查 namespace:
bash
kubectl get ns
查 Pod:
bash
kubectl get pod -n <namespace>
kubectl get pod -n <namespace> -o wide
kubectl describe pod <pod> -n <namespace>
kubectl logs <pod> -n <namespace>
进入容器:
bash
kubectl exec -it <pod> -n <namespace> -- bash
查 Job:
bash
kubectl get job -n <namespace>
kubectl describe job <job> -n <namespace>
查 Deployment:
bash
kubectl get deploy -n <namespace>
kubectl describe deploy <deploy> -n <namespace>
查 Service:
bash
kubectl get svc -n <namespace>
kubectl get endpoints -n <namespace>
查配置、密钥和存储:
bash
kubectl get cm -n <namespace>
kubectl get secret -n <namespace>
kubectl get pvc -n <namespace>
kubectl describe pvc <pvc> -n <namespace>
查事件:
bash
kubectl get events -n <namespace> --sort-by=.lastTimestamp
21. 最终记忆版
先把这些关系背下来:
| 对象 | 记忆方式 |
|---|---|
| Node | 集群里的机器 |
| Namespace | 项目/团队/租户隔离空间 |
| Container | 真正跑程序的地方 |
| Pod | Kubernetes 最小调度单元,里面放 Container |
| Job | 管一次性任务,适合训练、数据处理、离线任务 |
| Deployment | 管长期服务,适合 API、控制器、推理服务 |
| Service | 给一组 Pod 提供稳定访问入口 |
| ConfigMap | 普通配置 |
| Secret | 敏感配置 |
| PVC | 持久化存储声明 |
| Label/Selector | 给对象打标签并选择对象 |
| Taint/Toleration | 控制 Pod 能不能上某些节点 |
| Request/Limit | 管理资源申请和资源上限 |
再记三条对象链路:
- 训练任务:
Job -> Pod -> Container -> python train.py - 平台服务:
Deployment -> ReplicaSet -> Pod -> Container -> API Server - 推理服务:
Deployment/CRD -> Pod -> Container -> Model Server -> Service
后续学习 Kubernetes 排障时,所有状态和事件都围绕这些对象展开。