关于NVIDIA DRA Driver#gpu-kubelet-plugin
这里主要探讨GPU allocation side,即关于GPU资源动态分配的部分(cmd/gpu-kubelet-plugin)。另外一部分ComputeDomain端主要针对Multi-Node NVLink的拓扑与Pod间资源隔离实现。
对于gpu-kubelet-plugin,其核心作用是在节点上,响应Kubelet的请求,为Pod准备和释放GPU资源。整体的模块执行流程如下:
- 启动和注册 (main.go)
- 用户(或部署脚本)在每个需要 GPU 的 K8s节点上启动
gpu-kubelet-plugin进程。 main.go中的代码执行创建一个 gRPC 服务器。- 插件通过 Unix Domain Socket 向 Kubelet 的插件管理器注册自己为一个
dra.k8s.io/v1alpha3类型的插件,作为处理gpu.dra.nvidia.com这个驱动的插件。
- 用户(或部署脚本)在每个需要 GPU 的 K8s节点上启动
- Kubelet 发起资源准备请求
- 当一个声明了需要 GPU 资源的 Pod 被调度到这个 Node 上时,Kubelet 会通过之前注册的 Socket 调用
gpu-kubelet-plugin的NodePrepareResourcegRPC 方法。 - 这个请求会携带一个
ClaimUID,它唯一标识了这次资源请求。
- 当一个声明了需要 GPU 资源的 Pod 被调度到这个 Node 上时,Kubelet 会通过之前注册的 Socket 调用
- 插件处理资源准备 (plugin.go)
plugin.go中的NodePrepareResource方法被触发。- 它首先会从
PreparedClaims自定义资源中获取该ClaimUID对应的具体 GPU 分配信息(比如分配了哪些 GPU 的 UUID)。这个信息是由另一个控制器(dra-controller)在调度时写入的。 - 插件根据获取到的 GPU UUIDs,调用
cdi/模块的功能。
- 生成 CDI 设备规范 (cdi/)
cdi/模块的逻辑被调用,它的任务是为这次资源分配动态生成一个 CDI JSON Spec 文件。- 这个 JSON 文件会放在一个特定的目录(如
/var/run/cdi/),容器运行时会监控这个目录。 - 文件内容会描述一个唯一的 CDI Device Name(例如
gpu.dra.nvidia.com/claim-xxxxx=gpu-uuid-1,gpu-uuid-2),并指明当容器引用这个设备名时,需要注入哪些设备节点(/dev/nvidia0)、库文件和环境变量。
- 返回 CDI 句柄给 Kubelet
- CDI Spec 生成成功后,
plugin.go的NodePrepareResource方法会将这个唯一的 CDI Device Name 作为结果返回给 Kubelet。
- CDI Spec 生成成功后,
- Kubelet 更新 Pod 并启动容器
- Kubelet 收到这个 CDI Device Name 后,会将其注入到 Pod 的运行时规范(Runtime Spec)中。
- 当容器运行时(如 containerd)启动该 Pod 的容器时,它会看到这个 CDI 设备引用,然后根据 CDI 规范去查找对应的 JSON Spec 文件,并按照文件中的描述来正确配置容器的运行环境(即把 GPU “插”进容器里)。
- 资源释放
- 当 Pod 结束后,Kubelet 会调用插件的
NodeUnprepareResource方法。 plugin.go中的NodeUnprepareResource逻辑会触发,它会调用cdi/模块去删除之前为该 Pod 生成的 CDI JSON Spec 文件,从而完成资源的清理。
- 当 Pod 结束后,Kubelet 会调用插件的
该插件能否实现动态修改Pod运行时资源配置?
不能,该插件创建的CDI Spec是在容器启动时刻被读取并注册到容器运行时的配置中。
目前KEP中有一个关于Pod资源动态修改的Proposal,不过没有提到关于GPU资源,主要是CPU和内存资源。