Incipience / Kubernetes

《从0到1搭建K8s GPU调度平台》

Einic Yeo · 11月27日 · 2024年 ·

别再让你的GPU“睡大觉”了,一套完整的调度平台能让算力利用率翻倍。“我们买了GPU,装了驱动,在K8s里也能nvidia-smi了。但为什么AI工程师还是抱怨资源不够用?”

这是我听到最多的困惑。很多人以为,K8s能识别GPU,就等于有了GPU调度能力。大错特错。

识别GPU只是第一步。真正的GPU调度平台,要能解决资源碎片、拓扑感知、任务排队、弹性伸缩等一系列问题。今天,我就带你从0到1,搭建一套生产级的K8s GPU调度平台。

一、 搭建前的准备:明确目标与架构

在动手之前,我们先明确:我们要搭的到底是什么?

1.1 基本能力

一套完整的GPU调度平台,应该具备以下能力:

  1. 硬件抽象:屏蔽底层GPU型号差异,统一暴露资源
  2. 批量调度:支持AI训练任务的排队、优先级、抢占
  3. 拓扑感知:理解NVLink、RDMA等高速互联拓扑
  4. 弹性推理:支持大模型推理服务的自动伸缩
  5. 可观测性:实时监控GPU利用率、显存、温度

1.2 所需技术栈

基于以上目标,我们采用以下技术栈:

  1. 底层:NVIDIA GPU Operator(驱动+Device Plugin)
  2. 调度层:Volcano(批量调度+拓扑感知)
  3. 推理层:KServe + vLLM(模型服务)
  4. 监控层:DCGM Exporter + Prometheus + Grafana

二、 搭建三步走

2.1 底层环境搭建与GPU资源暴露

描述:这是搭建的第一步,也是最容易踩坑的一步。我们需要在K8s集群中正确安装GPU Operator,让每个GPU节点都能被K8s识别和调度。

详细注解:

  1. 驱动安装:GPU Operator最大的价值在于将驱动容器化。你不需要在宿主机上手动安装驱动,Operator会自动在每个GPU节点上启动一个特权容器,加载驱动内核模块。这大大简化了驱动版本管理。
  2. 设备暴露:Device Plugin是K8s调度GPU的核心机制。它会定期向Kubelet上报节点上的GPU数量,并以nvidia.com/gpu这个扩展资源的形式暴露给API Server。
  3. 验证确认:这一步最容易出问题。一定要通过kubectl describe node确认节点上有nvidia.com/gpu: X,然后创建一个测试Pod执行nvidia-smi,确保容器内能正常访问GPU。

2.2 批量调度引擎Volcano的部署与配置

描述:有了底层GPU资源,接下来要解决“怎么分”的问题。Volcano是专为AI/大数据设计的批量调度器,支持队列管理、Pod组调度、拓扑感知。

说明:

  1. 调度器部署:Volcano可以与K8s默认调度器共存。你只需要在Pod中指定schedulerName: volcano,该Pod就会被Volcano调度。其他Pod仍由默认调度器处理,互不影响。
  2. Pod组调度:这是Volcano的核心能力。通过PodGroup定义一组Pod(比如8个训练Worker),Volcano保证它们要么全部调度成功,要么一个都不调度,避免了部分Pod卡住导致的死锁。
  3. 拓扑感知:Volcano可以通过Node Annotation读取GPU的NVLink拓扑版权声明:本文遵循 CC 4.0 BY-SA 版权协议,若要转载请务必附上原文出处链接及本声明,谢谢合作!信息。当你提交一个需要8卡的任务时,它会优先寻找一个节点上的8卡(最高带宽),其次才考虑跨节点的组合。

2.3 推理服务层KServe的部署与伸缩配置

描述:训练之外,推理是版权声明:本文遵循 CC 4.0 BY-SA 版权协议,若要转载请务必附上原文出处链接及本声明,谢谢合作!GPU调度平台的另一大场景。KServe提供了标准化的推理服务框架,支持模型版本管理、自动伸缩、金丝雀发布。

说明:

  1. 模型缓存:这是解决推理冷启动的关键。将常用模型预加载到基于JuiceFS或RDMA的高速共享存储中,新Pod启动时直接从缓存加载模型到显存,时间从分钟级降到秒级。
  2. 弹性伸缩:KEDA(Kubernetes Event-driven Autoscaling)监听GPU利用率或每秒请求数(RPS),触发HPA进行伸缩。配置合理的阈值(如GPU利用率>70%时扩容),可以在保证性能的同时最大化资源利用率。
  3. 流量路由:KServe支持按请求头或权重进行流量分发。当你需要上线新模型版本时,可以先让10%的流量走新版本,观察无误后再全量切换,实现零宕机发布。

三、 关键配置

3.1 GPU节点的污点与容忍

为了避免非GPU工作负载占用GPU节点,建议给GPU节点打上污点:

# 给GPU节点打污点
kubectl taint nodes gpu-node-1 nvidia.com/gpu=present:NoSchedule

# 需要GPU的Pod配置容忍
tolerations:
- key: nvidia.com/gpu
 operator: Equal
 value: present
 effect: NoSchedule

3.2 Volcano队列配置

apiVersion: scheduling.volcano.sh/v1beta1
kind: Queue
metadata:
 name: training-queue
spec:
 weight: 10
 capability:
  nvidia.com/gpu: 16 # 该队列最多使用16张GPU
 reclaimable:true  # 空闲资源可被其他队列借用

3.3 KServe InferenceService配置(LLM部署)





apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
 name: llama3-service
spec:
 predictor:
  minReplicas: 0
  maxReplicas: 5
  scaleMetrics:
  -type: gpu_utilization
   targetValue: 70
  containers:
  - name: kserve-container
   image: vllm/vllm-openai:latest
   args:
   - --model
   - meta-llama/Meta-Llama-3-8B
   resources:
    limits:
     nvidia.com/gpu: 1

四、 验证与调优:确保平台真正可用

搭建完成不是终点,验证和调优才是关键。

4.1 验证清单

  1. 资源暴露验证:kubectl describe node 确认每个GPU节点都有nvidia.com/gpu资源。
  2. 调度验证:提交一个需要多卡的训练任务,观察是否调度成功,且Pod集中在同一节点或高速互联节点版权声明:本文遵循 CC 4.0 BY-SA 版权协议,若要转载请务必附上原文出处链接及本声明,谢谢合作!上。
  3. 推理验证:部署一个推理服务,发送请求,观察冷启动时间和伸缩行为。
  4. 监控验证:打开Grafana,确认能看到每张GPU的利用率、显存、温度等指标。

4.2 常见调优点

  1. 驱动版本:确保驱动版本与CUDA版本、容器运行时版本兼容。建议使用最新稳定版。
  2. 队列配额:根据业务优先级合理分配队列权重,避免一个部门占满所有GPU。
  3. 伸缩阈值:推理服务的伸缩阈值需要根据业务SLA调整。过低的阈值会导致频繁伸缩,过高的阈值会导致响应延迟。
  4. 模型缓存大小:根据常用模型数量规划缓存空间,确保热门模型都能被缓存。

五、总结

从0到1搭建一套K8s GPU调度平台,听起来复杂,但拆解开来,无非是“底层暴露、中层调度、上层服务”三个环节。

  1. 底层:GPU Operator让硬件抽象化
  2. 中层:Volcano让调度智能
  3. 上层:KServe让推理服务标准化

当你完成这套平台的搭建,你会发现:AI工程师不再抱怨资源不够,训练任务不再卡在Pending,推理服务能够丝滑伸缩,GPU利用率从30%跃升到80%。

这才是K8s GPU调度平台的版权声明:本文遵循 CC 4.0 BY-SA 版权协议,若要转载请务必附上原文出处链接及本声明,谢谢合作!真正价值——让每一分算版权声明:本文遵循 CC 4.0 BY-SA 版权协议,若要转载请务必附上原文出处链接及本声明,谢谢合作!力投入,都产生应有的回报。

0 条回应