kubernetes GPU管理与Device Plugin机制
一. kubernetes中如何管理GPU
AI基础设施变革:
- 2016年TensorFlow等框架兴起催生分布式训练需求
- 云原生场景下GPU管理的核心挑战:
- 设备隔离性(避免多容器争抢)
- 驱动兼容性(主机驱动 vs 容器内驱动)
- 资源可见性(调度器感知设备状态)
以 NVIDIA 的 GPU 设备为例
节点准备要求:
代码语言:bash复制# 验证节点GPU就绪状态
nvidia-smi -L
# 输出示例:
GPU 0: xxxx
容器运行时配置:
代码语言:toml复制# /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri"]
enable_gpu = true
[plugins."io.containerd.grpc.v1.cri".device_plugin]
config_path = "/var/lib/kubelet/device-plugins"
Extended Resource配置
Kubernetes 在 Pod 的 API 对象里,并没有为 GPU 专门设置一个资源类型字段,而是使用了一种叫作 Extended Resource(ER)的特殊字段来负责传递 GPU 的信息。
代码语言:yaml复制apiVersion: v1
kind: Pod
metadata:
name: cuda-training
spec:
containers:
- name: trainer
image: nvcr.io/nvidia/tensorflow:22.07-tf2-py3
resources:
limits:
nvidia/gpu: 1 # 必须为整数
volumeMounts:
- name: nvidia-driver
mountPath: /usr/local/nvidia
readOnly: true
volumes:
- name: nvidia-driver
hostPath:
path: /usr/local/nvidia
可以看到,在上述 Pod 的 limits 字段里,这个资源的名称是nvidia/gpu,它的值是 1。也就是说,这个 Pod 声明了自己要使用一个 NVIDIA 类型的 GPU。
而在 kube-scheduler 里面,它其实并不关心这个字段的具体含义,只会在计算的时候,一律将调度器里保存的该类型资源的可用量,直接减去 Pod 声明的数值即可。所以说,Extended Resource,其实是 Kubernetes 为用户设置的一种对自定义资源的支持。
GPU资源注册流程
- Device Plugin通过gRPC注册资源
- Kubelet更新Node对象
kubectl get node <node> -o jsonpath='{.status.capacity}'
# 输出示例:{"nvidia/gpu":"8"}
二. kubernetes的 Device Plugin 的插件
核心机制
代码语言:bash复制Device Plugin --gRPC--> Kubelet
Kubelet -->|上报| API-Server
Scheduler -->|查询| API-Server
Kubelet -->|分配| CRI(Container Runtime)
通信协议:通过 Unix socket (/var/lib/kubelet/device-plugins/
) 使用 gRPC 通信
关键接口:
代码语言:protobuf复制service DevicePlugin {
rpc ListAndWatch(Empty) returns (stream ListAndWatchResponse) {}
rpc Allocate(AllocateRequest) returns (AllocateResponse) {}
rpc GetPreferredAllocation(PreferredAllocationRequest) returns (PreferredAllocationResponse) {}
}
工作流程:
- 注册阶段:插件启动后向 kubelet 注册自身
- 发现阶段:
ListAndWatch
上报设备列表及状态 - 分配阶段:Pod 创建时调用
Allocate
注入设备资源
三. Device Plugin的局限性
调度层级缺陷
- 调度器仅基于
nvidia/gpu: 2
这样的整数资源判断 - 无法处理以下场景:
- 选择特定架构 GPU(如 A100 或 T4)
- 避免跨 NUMA 节点访问
- 优先选择空闲设备
# 用户无法表达如下需求:
resources:
limits:
nvidia/gpu.performance: "high" # 期望高性能GPU
nvidia/gpu.memory: "32Gi" # 需要大显存
设备属性缺失
ListAndWatch
仅返回设备 ID 和健康状态
type Device struct {
ID string
Health string
// 无厂商/型号/性能等字段
}
- 用户无法通过配置调度至指定的设备属性
- 调度器无法实现拓扑感知等高级策略
四. 新兴方案
Device Scheduling Framework (Kubernetes 1.26+)
代码语言:go复制// 自定义调度插件示例
func (p *GPUScheduler) Filter(ctx context.Context, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
gpuDevices := getNodeGPUs(nodeInfo)
if !matchesRequirements(pod, gpuDevices) {
return framework.NewStatus(framework.Unschedulable)
}
return nil
}
- 支持设备属性过滤
- 可集成厂商特定逻辑
Dynamic Resource Allocation (DRA) Kubernetes 1.26+
- DRA 是为了解决设备资源分配的灵活性问题。它允许设备资源的动态请求和分配,尤其适用于 GPU、FPGA 等异构资源。
- 相比于传统的设备插件模式,DRA 支持多阶段的资源协商,并且能够与调度器进行更好的协作。
Volcano
Volcano是CNCF下首个也是唯一的基于Kubernetes的容器批量计算平台,主要用于高性能计算场景。它提供了包括异构设备调度,网络拓扑感知调度,多集群调度,在离线混部调度等多种调度能力。