05 - AI 行业 K8s 最佳实践
AI 工作负载 vs 传统 Web 工作负载
| 特性 | 传统 Web 服务 | AI 训练/推理 |
|---|---|---|
| 生命周期 | 长期运行 | 训练是临时的,推理是长期的 |
| 资源类型 | CPU + 内存 | GPU + 大内存 + 高速存储 + 高速网络 |
| 成本 | 相对低 | 极高(GPU 按小时上百元) |
| 弹性 | 逐步扩缩 | 训练前申请大量资源,完成后立即释放 |
| 数据量 | MB-GB 级 | TB-PB 级 |
| 容错 | 无状态重启即可 | 需要 Checkpoint 恢复 |
一、MLOps 平台架构
┌──────────────────────────────────────────────────────────────────┐
│ ML Platform on K8s │
│ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌──────────────┐ │
│ │ Notebook │ │ Training │ │ Model │ │ Inference │ │
│ │ Server │ │ Pipeline │ │ Registry │ │ Service │ │
│ │ │ │ │ │ │ │ │ │
│ │ JupyterHub│ │ Kubeflow │ │ MLflow / │ │ TF Serving / │ │
│ │ on K8s │ │ Pipelines │ │ ModelScope│ │ Triton / │ │
│ │ │ │ / Argo │ │ │ │ vLLM │ │
│ └───────────┘ └───────────┘ └───────────┘ └──────────────┘ │
│ │ │ │ │ │
│ └──────────────┴──────────────┴──────────────┘ │
│ │ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ K8s Cluster (ACK) │ │
│ │ GPU Node Pool │ CPU Node Pool │ Spot/抢占式 Node Pool │ │
│ └──────────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Storage: NAS (数据集) │ OSS (模型/日志) │ 云盘 (缓存) │ │
│ └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘二、GPU 资源管理最佳实践
节点池分层设计
yaml
# 节点池 1:GPU 训练池(按需/预留实例)
# - 大 GPU 规格(A100/V100)
# - 用于大规模训练
# - 标签: pool=gpu-training
# 节点池 2:GPU 推理池(按需实例)
# - 中等 GPU 规格(A10/T4)
# - 用于模型推理
# - 标签: pool=gpu-inference
# 节点池 3:GPU Spot 池(抢占式实例)
# - 低成本 GPU
# - 用于可容错的训练任务
# - 标签: pool=gpu-spot
# 节点池 4:CPU 池
# - 数据预处理、调度组件、监控等
# - 标签: pool=cpuGPU 调度策略
yaml
# 训练任务:使用专用 GPU 节点
spec:
nodeSelector:
pool: gpu-training
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
containers:
- name: train
resources:
limits:
nvidia.com/gpu: 8 # 整机独占
---
# 推理任务:可以共享 GPU
spec:
nodeSelector:
pool: gpu-inference
containers:
- name: inference
resources:
limits:
aliyun.com/gpu-mem: 8 # cGPU 共享 8GB 显存GPU 监控
bash
# DCGM Exporter(NVIDIA 官方 GPU 监控)
helm install dcgm-exporter gpu-helm-charts/dcgm-exporter
# 关键指标
# DCGM_FI_DEV_GPU_UTIL - GPU 利用率
# DCGM_FI_DEV_FB_USED - 显存使用
# DCGM_FI_DEV_GPU_TEMP - GPU 温度
# DCGM_FI_DEV_POWER_USAGE - 功耗yaml
# Grafana 告警示例
# GPU 利用率持续 30 分钟低于 10%(浪费资源)
expr: avg_over_time(DCGM_FI_DEV_GPU_UTIL[30m]) < 10
# GPU 显存使用率超过 95%(可能 OOM)
expr: DCGM_FI_DEV_FB_USED / DCGM_FI_DEV_FB_FREE > 0.95三、分布式训练最佳实践
训练任务生命周期管理
代码提交 → 镜像构建 → 数据准备 → 训练启动 → 监控 → Checkpoint → 模型评估 → 模型注册
│
┌────────┴────────┐
│ │
训练成功 训练失败
│ │
模型评估 自动重试/通知
│
模型注册
│
推理部署Checkpoint 策略(关键!)
GPU 资源昂贵,断点续训是必须的:
python
# 训练代码中的 Checkpoint 最佳实践
import torch
import os
def save_checkpoint(model, optimizer, epoch, loss, path):
"""定期保存 Checkpoint 到共享存储"""
torch.save({
'epoch': epoch,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'loss': loss,
'rng_state': torch.random.get_rng_state(),
'cuda_rng_state': torch.cuda.get_rng_state_all(),
}, path)
def load_checkpoint(path, model, optimizer):
"""从 Checkpoint 恢复训练"""
if os.path.exists(path):
ckpt = torch.load(path)
model.load_state_dict(ckpt['model_state_dict'])
optimizer.load_state_dict(ckpt['optimizer_state_dict'])
torch.random.set_rng_state(ckpt['rng_state'])
torch.cuda.set_rng_state_all(ckpt['cuda_rng_state'])
return ckpt['epoch'], ckpt['loss']
return 0, float('inf')
# 训练循环中
for epoch in range(start_epoch, total_epochs):
train_one_epoch(model, dataloader, optimizer)
# 每 N 个 epoch 保存一次
if epoch % save_interval == 0:
save_checkpoint(model, optimizer, epoch, loss,
f'/output/checkpoint_epoch_{epoch}.pt')
# 保留最新的 Checkpoint
save_checkpoint(model, optimizer, epoch, loss,
'/output/checkpoint_latest.pt')yaml
# PyTorchJob 配置:共享存储 + 自动恢复
spec:
pytorchReplicaSpecs:
Worker:
replicas: 4
restartPolicy: OnFailure # 失败自动重启
template:
spec:
containers:
- name: train
command:
- python
- train.py
- --resume=/output/checkpoint_latest.pt # 自动恢复
volumeMounts:
- name: data
mountPath: /data
readOnly: true
- name: output
mountPath: /output # Checkpoint 存这里
volumes:
- name: data
persistentVolumeClaim:
claimName: training-data # NAS RWX
- name: output
persistentVolumeClaim:
claimName: training-output # NAS RWX通信优化
yaml
# 大规模训练通信优化
env:
# NCCL 优化
- name: NCCL_ALGO
value: "Ring" # Ring AllReduce(适合中等规模)
# value: "Tree" # Tree AllReduce(适合大规模)
- name: NCCL_IB_DISABLE
value: "0" # 启用 InfiniBand/RoCE
- name: NCCL_NET_GDR_LEVEL
value: "5" # GPU Direct RDMA(最高性能)
- name: NCCL_SOCKET_IFNAME
value: "eth0" # 指定网卡
- name: NCCL_DEBUG
value: "WARN" # 生产用 WARN,调试用 INFO
# PyTorch DataLoader 优化
- name: OMP_NUM_THREADS
value: "4"数据加载优化
┌──────────────────────────────────────────────────────────┐
│ 数据管道设计 │
│ │
│ OSS (海量原始数据) │
│ │ 预处理 Job │
│ ▼ │
│ NAS (处理后的训练数据) │
│ │ 训练 Pod 直接读取 │
│ ▼ │
│ 本地 SSD 缓存 (热数据) │
│ │ 极速读取 │
│ ▼ │
│ GPU 显存 │
└──────────────────────────────────────────────────────────┘yaml
# 数据缓存策略:使用 emptyDir (SSD) 做本地缓存
spec:
initContainers:
- name: data-cache
image: busybox
command: ["cp", "-r", "/data/hot-subset", "/cache/"]
volumeMounts:
- name: data
mountPath: /data
- name: cache
mountPath: /cache
containers:
- name: train
volumeMounts:
- name: cache
mountPath: /fast-data # 训练读取本地缓存
volumes:
- name: data
persistentVolumeClaim:
claimName: training-data
- name: cache
emptyDir:
sizeLimit: 100Gi # 本地 SSD 缓存四、模型推理最佳实践
推理框架选择
| 框架 | 特点 | 适用场景 |
|---|---|---|
| vLLM | 高性能 LLM 推理,PagedAttention | 大语言模型 |
| Triton | NVIDIA 出品,多框架支持 | 通用模型推理 |
| TF Serving | TensorFlow 模型 | TF 生态 |
| TorchServe | PyTorch 模型 | PyTorch 生态 |
| Ollama | 简单易用的 LLM 运行 | 小规模/本地 |
vLLM 部署示例
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: llm-inference
spec:
replicas: 2
selector:
matchLabels:
app: llm-inference
template:
metadata:
labels:
app: llm-inference
spec:
nodeSelector:
pool: gpu-inference
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
containers:
- name: vllm
image: vllm/vllm-openai:latest
command:
- python
- -m
- vllm.entrypoints.openai.api_server
- --model=/models/Qwen2-7B
- --tensor-parallel-size=1
- --max-model-len=4096
- --gpu-memory-utilization=0.9
ports:
- containerPort: 8000
resources:
limits:
nvidia.com/gpu: 1
volumeMounts:
- name: models
mountPath: /models
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 120 # 模型加载需要时间
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 180
periodSeconds: 30
volumes:
- name: models
persistentVolumeClaim:
claimName: model-store
---
apiVersion: v1
kind: Service
metadata:
name: llm-inference
spec:
selector:
app: llm-inference
ports:
- port: 8000
targetPort: 8000
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: llm-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: llm-inference
minReplicas: 1
maxReplicas: 8
metrics:
- type: Pods
pods:
metric:
name: gpu_utilization # 自定义 GPU 指标
target:
type: AverageValue
averageValue: "70" # GPU 利用率超过 70% 扩容推理服务优化
yaml
# 1. 模型预加载(initContainer 预热)
initContainers:
- name: model-warmup
image: curlimages/curl
command: ["curl", "-X", "POST", "http://localhost:8000/v1/completions",
"-d", '{"model":"Qwen2-7B","prompt":"Hello","max_tokens":1}']
# 2. 请求队列和限流
# 通过 Ingress annotation 限制
annotations:
nginx.ingress.kubernetes.io/limit-rps: "50"
nginx.ingress.kubernetes.io/limit-connections: "20"
# 3. 自动扩缩容
# 基于自定义 GPU 利用率指标
# 需要 Prometheus Adapter 将 GPU 指标暴露为 K8s metrics五、AI 平台成本优化
成本分布(典型 AI 团队)
GPU 计算: 60-70% ← 最大优化空间
存储: 15-20%
网络: 5-10%
CPU/管理: 5-10%优化策略
| 策略 | 节约 | 方法 |
|---|---|---|
| Spot/抢占式实例 | 60-90% | 训练任务 + Checkpoint 容错 |
| GPU 利用率提升 | 20-50% | cGPU 共享 / 在离线混部 / 时间片调度 |
| 训练效率优化 | 间接 | 混合精度(FP16/BF16)、梯度累积、优化数据加载 |
| 及时释放资源 | 直接 | 训练完成后自动缩容节点(Cluster Autoscaler) |
| 模型蒸馏/量化 | 推理成本降 50-80% | 大模型 → 小模型 / INT8 量化 |
| 按需购买 | 30-60% | 预留实例券用于稳定负载 |
抢占式实例 + Checkpoint 方案
yaml
# 抢占式节点池配置(阿里云)
# ACK 控制台 → 节点池 → 创建
# 实例类型选择"抢占式实例"
# 开启"补偿型实例"(被回收时自动创建新节点)
# 训练 Job 配置
apiVersion: kubeflow.org/v1
kind: PyTorchJob
metadata:
name: spot-training
spec:
pytorchReplicaSpecs:
Worker:
replicas: 4
restartPolicy: OnFailure
template:
spec:
nodeSelector:
pool: gpu-spot # 使用 Spot 节点池
tolerations:
- key: china.alibabacloud.com/spot
operator: Exists
containers:
- name: train
command:
- python
- train.py
- --checkpoint-interval=300 # 每 5 分钟保存一次
- --resume=auto # 自动从最新 Checkpoint 恢复六、Kubeflow 全家桶
Kubeflow 是 Google 开源的 ML 平台,在 K8s 上提供完整 ML 工作流:
| 组件 | 功能 |
|---|---|
| Kubeflow Notebooks | 在线 Jupyter 环境 |
| Kubeflow Pipelines | ML 工作流编排(DAG) |
| Training Operator | 分布式训练(PyTorchJob/TFJob) |
| KServe | 模型推理服务 |
| Katib | 超参数调优(AutoML) |
简化安装(只装需要的组件)
bash
# 只安装 Training Operator(分布式训练)
kubectl apply -k "github.com/kubeflow/training-operator/manifests/overlays/standalone"
# 只安装 KServe(推理服务)
kubectl apply -f https://github.com/kserve/kserve/releases/latest/download/kserve.yaml
# 安装 Kubeflow Pipelines
kubectl apply -k "github.com/kubeflow/pipelines/manifests/kustomize/cluster-scoped-resources"
kubectl apply -k "github.com/kubeflow/pipelines/manifests/kustomize/env/dev"七、实际案例:完整 AI 训练到部署流程
┌─────────────────────────────────────────────────────┐
│ 1. 开发阶段 │
│ Jupyter Notebook (K8s Pod + GPU) │
│ 实验 → 确认模型和超参 │
├─────────────────────────────────────────────────────┤
│ 2. 训练阶段 │
│ PyTorchJob (4 Worker × 4 GPU = 16 GPU) │
│ 数据: NAS → 本地缓存 → GPU │
│ Checkpoint: 每 1000 步保存到 NAS │
│ 监控: GPU 利用率 + 训练 loss + TensorBoard │
├─────────────────────────────────────────────────────┤
│ 3. 评估阶段 │
│ K8s Job: 在测试集上评估模型 │
│ 对比指标 → 决定是否上线 │
├─────────────────────────────────────────────────────┤
│ 4. 注册阶段 │
│ 模型推送到 OSS / Model Registry │
│ 记录模型版本、指标、超参 │
├─────────────────────────────────────────────────────┤
│ 5. 部署阶段 │
│ Deployment + HPA (GPU 指标扩缩容) │
│ 灰度发布: 10% → 50% → 100% │
│ 推理优化: 量化 / TensorRT / vLLM │
├─────────────────────────────────────────────────────┤
│ 6. 监控阶段 │
│ 延迟 P99 < 200ms │
│ GPU 利用率 > 60% │
│ 模型效果监控 (数据漂移检测) │
└─────────────────────────────────────────────────────┘