资讯详情

资讯详情

从零搭建一个 AI Infra 实验室⑮:GPU Operator——AI 集群为什么不能靠手工装驱动

上一篇我们终于让 Kubernetes 真正认识了一张 GPU。从RTX 3060 ↓ NVIDIA Driver ↓ NVIDIA Device Plugin ↓ kubelet ↓ nvidia.com/gpu: 1到 Pod 里写resources: limits: nvidia.com/gpu: 1Kubernetes 就可以把 GPU 当成一种资源参与调度。而且我们已经把两个很容易混淆的组件分清楚NVIDIA Device Plugin ↓ 让 Kubernetes 知道这里有 GPU NVIDIA Container Toolkit ↓ 让 Container 真正访问 GPU这部分上一篇已经完整实验过这一篇不再重复。再往前我们也已经知道 Kubernetes 的 Pod 最终走的是kubelet ↓ CRI ↓ containerd ↓ runc真正变成 Linux Container。到了这里单机 GPU Kubernetes 已经基本跑通。但回头看看我们做过的事情会发现一个新的问题安装 NVIDIA Driver 安装 NVIDIA Container Toolkit 配置 containerd 安装 NVIDIA Device Plugin 以后还要 GPU Feature Discovery DCGM 监控 升级 维护 ...一台实验服务器当然可以手工做。如果以后是一套真正的 AI Cluster10 台 GPU Node 50 台 GPU Node 100 台 GPU Node还准备一台一台 SSH 上去装吗这就是这一篇真正要解决的问题GPU 从“单机硬件”进入 Kubernetes 集群以后整套 GPU 软件栈到底应该由谁维护答案就是NVIDIA GPU Operator一、问题已经从“GPU 能不能用”变成了“GPU 集群怎么管”单机时代我们习惯这样维护机器Ubuntu ↓ apt install NVIDIA Driver ↓ 安装 Container Toolkit ↓ 修改 containerd ↓ 部署 Device Plugin这种方式最大的问题并不是麻烦而是无法保证整个 Cluster 长期保持一致假设以后有三台 GPU NodeNode A Driver A Toolkit A Device Plugin A Node B Driver B Toolkit B Device Plugin B Node C Driver C Toolkit C Device Plugin C刚开始可能都能跑。但运行半年以后Node A 升过 Driver Node B 升过 Kernel Node C 换过 Toolkit整个集群很容易逐渐变成Configuration Drift也就是配置漂移。更麻烦的是GPU Node 上需要维护的东西其实远远不只有 Driver。一套比较完整的 Kubernetes GPU Software Stack 大致包括NVIDIA Driver ↓ NVIDIA Container Toolkit ↓ NVIDIA Device Plugin ↓ GPU Feature Discovery ↓ DCGM / DCGM Exporter还可能继续出现MIG Manager Validator Driver Upgrade vGPU GPUDirect ...如果这些东西全部靠SSH Shell Script 手工 YAML维护那么 GPU Node 越多问题越明显。所以 GPU Operator 真正解决的不是帮我们少敲几条安装命令。而是把 GPU Node 的软件栈变成 Kubernetes 自己可以持续管理的 Desired State。二、GPU Operator 到底是什么Operator 并不是 NVIDIA 特有的东西。Kubernetes Operator 可以先粗略理解成Controller Custom Resource Reconciliation普通安装脚本更像运行一次 ↓ 安装完成 ↓ 结束而 Operator 的思路是Desired State │ ▼ Operator │ ├── 当前状态正确 │ ↓ │ 保持 │ └── 当前状态不正确 ↓ Reconcile也就是说我们不再只告诉系统安装 Device Plugin而是告诉它Device Plugin 应该一直存在不再只是安装 GPU Monitoring而是每个 GPU Node 都应该有 Monitoring 能力GPU Operator 就是站在这个层面管理 NVIDIA GPU Software Stack。它本身是GPU Operator Controller然后根据ClusterPolicy创建并管理下面需要的各种组件。可以简单画成Kubernetes │ ▼ GPU Operator │ ▼ ClusterPolicy │ ┌────────────┼────────────┐ │ │ │ ▼ ▼ ▼ Driver Toolkit Device Plugin │ ┌─────────────┼─────────────┐ ▼ ▼ ▼ GFD DCGM Validator所以GPU Operator 自己并不是 Driver也不是 Device Plugin。它更像GPU Software Stack 的管理员三、先看五个最核心的组件GPU Operator 能管理的东西很多。这一篇先抓住最核心的五个Driver Toolkit Device Plugin GPU Feature Discovery DCGM这五个已经足够构成一个非常完整的 GPU Node。1. NVIDIA Driver最底层仍然是Linux Kernel ↓ NVIDIA Driver ↓ GPU没有 Drivernvidia-smi都不会正常工作。GPU Operator 可以通过 Driver Container 帮 GPU Node 安装和维护 NVIDIA Driver。这里最值得理解的是Driver Container并不意味着Driver 只存在 Container 里面。最终真正工作的 NVIDIA Kernel Module 仍然需要和Host Linux Kernel结合。所以 Driver 管理本质上仍然涉及Kernel Kernel Module Driver Version GPU Hardware这也是 GPU Software Stack 里比较特殊的一层。2. NVIDIA Container Toolkit这一层我们在⑫已经专门研究过。普通 Container 默认不会自动获得/dev/nvidia* NVIDIA Driver Libraries所以需要 NVIDIA Container Toolkit 把 GPU 能力正确注入 Container。在 Kubernetes 环境里它主要和containerd CDI NVIDIA Runtime这些东西打交道。这一篇不再展开 Toolkit 原理只需要记住Driver 解决 Host 怎么控制 GPU Container Toolkit 解决 Container 怎么使用 GPU3. NVIDIA Device Plugin这个就是上一篇的主角。它负责GPU ↓ Device Plugin ↓ kubelet ↓ nvidia.com/gpu最终kubectl describe node才能看到Capacity: nvidia.com/gpu: 1 Allocatable: nvidia.com/gpu: 1GPU Operator 并没有取代 Device Plugin。而是从我们手工部署 Device Plugin变成GPU Operator ↓ 管理 Device Plugin资源模型仍然没有变化。Pod 还是resources: limits: nvidia.com/gpu: 14. GPU Feature DiscoveryDevice Plugin 解决的是这里有几张 GPU但真正的 AI Cluster 还会遇到另外一个问题。假设Node A → A100 80GB Node B → H100 80GB Node C → L40S 48GB Node D → RTX 3060 12GB如果 Kubernetes 只知道nvidia.com/gpu: 1那么它看到的仍然只是GPU GPU GPU GPU至于什么型号 多少显存 什么架构 Compute Capability 是多少 支不支持 MIG它并不知道。这就是GPU Feature Discovery也就是 GFD 要解决的问题。GFD 会把 GPU 的一些硬件属性变成Node Labels例如nvidia.com/gpu.count nvidia.com/gpu.product nvidia.com/gpu.memory nvidia.com/gpu.family nvidia.com/gpu.compute.major nvidia.com/gpu.compute.minor nvidia.com/mig.capable于是 Kubernetes 对 GPU 的认识从有 GPU进一步变成这是什么 GPU这一点以后做GPU-aware Scheduling非常重要。5. DCGM / DCGM Exporter最后一个重要组件是DCGM也就是 NVIDIA Data Center GPU Manager。一张 GPU 能运行并不代表我们只需要知道Running / Not Running实际 AI Infra 还会关心GPU Utilization 显存占用 Temperature Power Clock Health Error这些信息。DCGM 负责获取 GPU Telemetry。而DCGM Exporter进一步把这些数据变成Prometheus Metrics默认通过/metrics暴露监听端口为 9400。所以可以简单记Device Plugin ↓ 告诉 Kubernetes “GPU 能不能分配” GPU Feature Discovery ↓ 告诉 Kubernetes “这是什么 GPU” DCGM ↓ 告诉监控系统 “这张 GPU 现在怎么样”到这里GPU Node 才开始真正具备运行 调度 识别 监控四种能力。四、把完整架构串起来现在可以把 GPU Operator 这一篇的架构画完整一点。GPU Operator │ ▼ ClusterPolicy │ ┌──────────────────────┼──────────────────────┐ │ │ │ ▼ ▼ ▼ NVIDIA Driver NVIDIA Container Toolkit Device Plugin │ │ │ ▼ ▼ ▼ Linux Kernel containerd kubelet │ │ │ ▼ │ ▼ GPU ◄───────────────────┘ nvidia.com/gpu │ ├────────────────────────────┐ │ │ ▼ ▼ GPU Feature Discovery DCGM │ │ ▼ ▼ nvidia.com/* Labels DCGM Exporter │ ▼ Prometheus Metrics上一篇解决的是其中一小段Device Plugin ↓ nvidia.com/gpu这一篇开始看到完整的GPU Node Lifecycle五、实验环境继续使用前几篇的 AI Infra 实验机Ubuntu 24.04 Server Intel Core i5-10400F NVIDIA GeForce RTX 3060 12GB VRAM Kubernetes 1.37.x containerd Single-node Kubernetes前几篇已经完成NVIDIA Driver NVIDIA Container Toolkit containerd Kubernetes NVIDIA Device Plugin GPU Pod所以这里有一个现实问题Driver 已经装好了 Toolkit 也已经装好了如果现在为了演示 GPU Operator全部卸掉 然后再重新装意义并不大而且容易把已经稳定的实验环境搞乱。GPU Operator 官方本身就支持Pre-installed Driver以及Pre-installed Driver Pre-installed Container Toolkit的场景。所以这次实验采取Host 已经管理 Driver Container Toolkit GPU Operator 开始管理 Device Plugin GPU Feature Discovery DCGM Exporter Validator ...也就是说我们不是重装整个环境。而是把已经搭好的单机 GPU Kubernetes逐步迁移到 Operator 管理模式。六、实验一先看 GPU Operator 版本先确认 helmhelm version如果没有 helm就安装sudo apt-get install curl gpg apt-transport-https -y curl -fsSL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey \ | gpg --dearmor \ | sudo tee /usr/share/keyrings/helm.gpg /dev/null echo deb [signed-by/usr/share/keyrings/helm.gpg] https://packages.buildkite.com/helm-linux/helm-debian/any/ any main \ | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list sudo apt update sudo apt install helm然后添加 NVIDIA Helm Repositoryhelm repo add nvidia \ https://helm.ngc.nvidia.com/nvidia helm repo update然后helm search repo \ nvidia/gpu-operator \ --versions \ | head写这篇文章时最新稳定版本已经是v26.7.1其中包括 NVIDIA Container Toolkit 1.20.1、Device Plugin 0.20.1、GPU Feature Discovery 0.20.1 和新的 DCGM / DCGM Exporter 版本。实际操作时当然还是以 helm search repo 看到的当前版本为准七、实验二删除上一篇手工部署的 Device Plugin上一篇我们已经手工部署过NVIDIA Device Plugin DaemonSet现在准备让GPU Operator成为它的管理者所以最好先把原来的独立版本删除。如果上一篇 Pod 残留kubectl delete -f gpu-pod.yaml按上一篇使用的是对应的 Static DaemonSet 文件删除kubectl delete -f \ https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.20.1/deployments/static/nvidia-device-plugin.yml然后kubectl get pods -n kube-system \ | grep nvidia确认原来的 Device Plugin 已经消失。这个动作的核心不是GPU Operator 安装前 必须把所有 NVIDIA 组件删掉而是一个很重要的原则一个组件最好只有一个 Lifecycle Owner。DriverHost 管ToolkitHost 管Device Plugin接下来交给 GPU Operator 管边界清楚系统才不会乱。八、实验三Helm 安装 GPU Operator因为当前服务器已经有NVIDIA Driver NVIDIA Container Toolkit所以使用helm install \ --wait \ gpu-operator \ -n gpu-operator \ --create-namespace \ nvidia/gpu-operator \ --versionv26.7.1 \ --set driver.enabledfalse \ --set toolkit.enabledfalse这里最关键的就是driver.enabledfalse表示不要重新安装 Driver而toolkit.enabledfalse表示继续使用 Host 现有的 Container Toolkit这也是 NVIDIA 官方提供的预装 Driver Toolkit 场景。如果以后有一批全新的 GPU Node没有 Driver 没有 Toolkit则可以直接helm install \ --wait \ gpu-operator \ -n gpu-operator \ --create-namespace \ nvidia/gpu-operator \ --versionv26.7.1让 GPU Operator 接管更多 GPU Software Stack。这才是它在真正集群环境里最有价值的地方。九、实验四GPU Operator 到底部署了什么安装完成后kubectl get pods \ -n gpu-operator \ -o wide应该能看到多种 NVIDIA 组件。重点关注gpu-operator-... nvidia-device-plugin-... gpu-feature-discovery-... nvidia-dcgm-exporter-... nvidia-operator-validator-...另外还可能看到 Node Feature Discovery 等辅助组件。因为这次设置了driver.enabledfalse toolkit.enabledfalse所以我们重点观察的不是 Driver Pod。而是GPU Operator ↓ Device Plugin GFD DCGM Exporter Validator这一套组件是不是已经自动出现。以前我们是一个组件 装一个组件现在第一次变成Helm 安装 GPU Operator ↓ Operator 根据 ClusterPolicy ↓ 创建整套 GPU Software Stack这就是实验中最重要的变化。十、实验五看 ClusterPolicy执行kubectl get clusterpolicy正常情况下应该看到NAME STATUS cluster-policy readyGPU Operator 官方安装验证同样会检查 ClusterPolicy 是否进入 Ready 状态。这个状态和某个 Pod Running并不完全一样。Pod Running 只能说明这个 Container 活着而ClusterPolicy Ready更接近GPU Operator 判断 当前 GPU Software Stack 已经达到了期望状态这就是Operator和普通kubectl apply YAML最大的思维差别之一。十一、实验六nvidia.com/gpu回来了没有上一篇我们已经验证Device Plugin会把 GPU 注册给 kubelet。现在原来的手工 Device Plugin 已经删除。再执行kubectl get node \ -o jsonpath{.items[0].status.capacity.nvidia\.com/gpu}{\n}期待1再看kubectl get node \ -o jsonpath{.items[0].status.allocatable.nvidia\.com/gpu}{\n}同样应该1这说明新的链路已经变成GPU Operator ↓ NVIDIA Device Plugin ↓ kubelet ↓ nvidia.com/gpu: 1这里很值得注意Kubernetes GPU Resource Model 没有改变上一篇学到的resources: limits: nvidia.com/gpu: 1仍然完全有效。GPU Operator 改变的只是谁负责维护 Device Plugin十二、实验七第一次看看 GPU Feature Discovery这一部分就开始出现上一篇没有的新东西了。先取得 Node NameNODE$(kubectl get nodes \ -o jsonpath{.items[0].metadata.name})然后kubectl get node $NODE \ --show-labels如果觉得内容太多可以kubectl get node $NODE \ --show-labels \ | tr , \n \ | grep nvidia.com/这时候会发现很多nvidia.com/...形式的 Label。例如可能看到nvidia.com/gpu.presenttrue nvidia.com/gpu.count1 nvidia.com/gpu.familyampere nvidia.com/gpu.memory12288 nvidia.com/gpu.compute.major8 nvidia.com/gpu.compute.minor6 nvidia.com/mig.capablefalse具体字段和值以实际环境为准。这一组数据非常值得截图。因为上一篇 Kubernetes 对 RTX 3060 的认识只有nvidia.com/gpu: 1也就是我这里有一张 GPU而现在变成GPU Count GPU Family GPU Memory Compute Capability MIG Capability ...也就是我不仅知道这里有 GPU 还开始知道 这到底是一张什么 GPU这就是Device Plugin和GPU Feature Discovery最直观的区别Device Plugin ↓ Resource GPU Feature Discovery ↓ Metadata十三、实验八看看 DCGM Exporter再执行kubectl get pods \ -n gpu-operator \ | grep dcgm应该能看到类似nvidia-dcgm-exporter-xxxxx找到这个 PodDCGM_POD$(kubectl get pod \ -n gpu-operator \ -l appnvidia-dcgm-exporter \ -o jsonpath{.items[0].metadata.name})然后kubectl port-forward \ -n gpu-operator \ pod/$DCGM_POD \ 9400:9400另开 Terminalcurl localhost:9400/metrics \ | grep ^DCGM_ \ | head -n 30这时候就可以看到 GPU Metrics。例如可能包括DCGM_FI_DEV_GPU_UTIL DCGM_FI_DEV_FB_USED DCGM_FI_DEV_GPU_TEMP DCGM_FI_DEV_POWER_USAGE DCGM_FI_DEV_SM_CLOCK不同 GPU 和 Collector 实际支持的指标可能不同。DCGM Exporter 的作用就是把 DCGM Telemetry 转换成 Prometheus 格式并通过/metrics暴露。到这里变化已经非常明显上一篇GPU ↓ nvidia.com/gpu ↓ Scheduler这一篇又多了一条GPU ↓ DCGM ↓ DCGM Exporter ↓ Prometheus Metrics于是同一张 GPU 同时进入了两个系统Kubernetes Resource System Observability System以后只要接上Prometheus Grafana这些指标自然就可以变成 GPU Dashboard。十四、这次实验最值得观察的四组数据所以这一篇其实不用做大量复杂测试。我觉得最值得保留的就是四组结果。第一组kubectl get pods -n gpu-operator证明GPU Operator 已经自动部署了一整套 GPU Components第二组kubectl get clusterpolicy证明ClusterPolicy 已经进入 Ready第三组nvidia.com/gpu: 1 nvidia.com/* Labels证明Device Plugin GPU Feature Discovery都已经工作。第四组DCGM_FI_DEV_...证明GPU Telemetry 已经进入 Prometheus Metrics 世界如果把四组现象放到一起GPU Operator │ ├── Device Plugin │ ↓ │ nvidia.com/gpu │ ├── GPU Feature Discovery │ ↓ │ Node Labels │ └── DCGM Exporter ↓ GPU Metrics这篇实验的目的就已经完成了。十五、唯一需要特别注意的坑到底谁在管理组件这一篇不做大篇幅排障。但有一个问题非常值得保留同一个 NVIDIA 组件到底由谁负责管理比如我们当前机器已经有Host Driver Host Container Toolkit所以 Helm 明确--set driver.enabledfalse --set toolkit.enabledfalse原来的独立 Device Plugin 又准备交给 Operator所以先删除。最终形成Driver ↓ Host 管理 Container Toolkit ↓ Host 管理 Device Plugin GFD DCGM Exporter Validator ↓ GPU Operator 管理这比Host 装一套 Helm 装一套 Operator 又管一套清晰得多。以后如果新建真正的 GPU Cluster也可以进一步变成Driver Toolkit Device Plugin GFD DCGM ↓ 全部交给 GPU Operator所以安装 Operator 前最值得先想清楚的不是命令。而是Lifecycle Owner十六、所以 GPU Operator 真正解决了什么现在回到文章最开始的问题。一台机器手工装 Driver 手工装 Toolkit 手工装 Device Plugin当然可以。甚至对于个人实验可能还更简单但当机器变成Node 01 Node 02 Node 03 ... Node 100问题已经不再是Driver 怎么装而变成哪些 Node Driver 正常 哪些 Node Toolkit 正常 哪些 Node 有 Device Plugin 哪些 GPU 是 Ampere 哪些 GPU 有多少显存 哪些 GPU 正在高负载 哪些 GPU 温度异常 整个 GPU Stack 是不是处于统一状态这就是单机和集群思维最大的变化单机 Command 集群 StateGPU Operator 本质上就是把 GPU Software Stack 从“逐台服务器执行命令”变成“由 Kubernetes 持续维护状态”。十七、把⑫⑮真正串起来现在回头看最近四篇就已经形成了一条比较完整的 GPU Infra 主线。⑫解决Container 怎样访问 GPU对应NVIDIA Container Toolkit⑬解决Kubernetes Pod 到底怎样变成 Container对应kubelet ↓ CRI ↓ containerd ↓ runc⑭解决Kubernetes 怎样知道 Node 有 GPU对应NVIDIA Device Plugin ↓ nvidia.com/gpu到了⑮这么多 GPU Software Components 以后到底由谁维护答案就是GPU Operator而且 Operator 进一步带来了GPU Feature Discovery ↓ GPU Metadata DCGM ↓ GPU Telemetry所以我们已经从GPU 能不能运行慢慢走向GPU Cluster 怎样被管理这才越来越接近真正的AI Infrastructure十八、下一篇为什么出现但做到这里一个问题又马上出现了。我们现在的 RTX 3060nvidia.com/gpu: 1如果一个 Pod 请求resources: limits: nvidia.com/gpu: 1那么从 Kubernetes 的默认资源模型来看整张 GPU 已经分给这个 Pod第二个 Pod 再申请nvidia.com/gpu: 1就可能因为Insufficient nvidia.com/gpu进入 Pending。但现实中的 AI Workload 并不一定能把 GPU 永远跑到100%可能GPU Utilization 20% GPU Utilization 40% 大量时间等待 CPU / IO / Request于是一个很自然的问题出现一张 GPU 为什么不能同时给多个 Pod 使用这就会继续引出几个 AI Infra 里很重要的概念Time-Slicing MPS MIG它们都在解决GPU Sharing但方式完全不同。RTX 3060 虽然不支持 MIG却正好可以先实验Time-Slicing而 A100、H100 这样的 Data Center GPU又可以进一步使用MIG把一张物理 GPU 真正切成多个具有硬件隔离能力的 GPU Instance。所以下一篇就继续往下拆。看看一张 GPU 怎样从独占资源一步一步变成可以被集群更高效利用的算力资源
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →