AI Infra实战01:GPU Operator实战,让Kubernetes学会调度GPU

发布时间:2026/9/2 17:01:32
AI Infra实战01:GPU Operator实战,让Kubernetes学会调度GPU AI Infra实战01GPU Operator实战,让Kubernetes学会调度GPU本篇配套的全部脚本、YAML、Helm Chart、预检工具和 Terraform 配置已开源在 GitHub:https://github.com/Jich1123/gpu-k8s-lab 。clone 下来按00-lab/execution-checklist.md的顺序执行即可复现全部实验(仓库不含任何真实 IP、密钥或账号信息)。本篇目标在一台带 NVIDIA T4 的真实云主机上,从零搭建单节点 k3s,部署 NVIDIA GPU Operator,让 Kubernetes 能够识别、调度并把 GPU 分配给 Pod,最后用一个 CUDA 程序验证 GPU 真的被容器用起来了。学完本篇你将掌握:GPU Operator 到底装了哪些组件、各自做什么从驱动就绪到 GPU 可被 K8s 调度的完整链路如何验证 GPU 调度成功(而不是看起来装好了)几个真实会踩的坑及处理证据等级:B级实验复现。本篇所有命令和输出来自一次真实执行(AWS g4dn.xlarge / T4),日志与截图已留存。少量长输出为篇幅做了裁剪,不改变结论。实操环境配置值平台AWS EC2 g4dn.xlarge(临时实例,用完即销毁)GPUTesla T4(16GB显存)CPU4 vCPU内存16GB系统盘100GB gp3系统Ubuntu 22.04.5 LTS驱动595.84CUDA13.2k3sv1.34.10k3s1GPU OperatorNVIDIA 官方 Helm Chart费用约 $0.526/小时,本篇实操约 $0.3一、先想清楚:为什么需要 GPU OperatorKubernetes 默认只认识 CPU 和内存,它压根不知道GPU是什么。你在 Pod 里写nvidia.com/gpu: 1,调度器会一脸茫然,因为没人告诉它节点上有这个资源。要让 K8s 认识并调度 GPU,一台节点上至少需要这几样东西各就各位:组件作用NVIDIA 驱动让操作系统能驱动 GPU 硬件container toolkit让容器运行时(containerd)能把 GPU 透传进容器device plugin向 kubelet 注册nvidia.com/gpu这个可调度资源feature discovery给节点打上 GPU 型号等标签,便于调度DCGM exporter采集 GPU 指标(下一篇监控会用到)以前这些要一个个手动装、手动配,版本还容易对不上。NVIDIA GPU Operator 把它们打包成一个 Operator,用一条 Helm 命令统一部署和管理,这就是它存在的意义。二、准备:宿主机预检与驱动就绪2.1 驱动装好后必须重启一次云主机开机脚本里用ubuntu-drivers autoinstall装了驱动,但第一次nvidia-smi却报错:NVIDIA-SMI has failed because it couldnt communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.诊断一下:dpkg-l|grep-cnvidia-driver# 输出 1驱动包已安装lsmod|grep-cnvidia# 输出 0内核模块未加载结论很清楚:驱动包装了,但内核模块没加载。原因是装完驱动没重启。处理方式就是重启一次:sudoreboot重启重连后再看:nvidia-smi----------------------------------------------------------------------------------------- | NVIDIA-SMI 595.84 Driver Version: 595.84 CUDA Version: 13.2 | | 0 Tesla T4 Off | 00000000:00:1E.0 Off | 0 | | N/A 35C P8 13W / 70W | 0MiB / 15360MiB | 0% Default | -----------------------------------------------------------------------------------------看到 Tesla T4、显存 15360MiB、空闲状态,驱动就绪。坑点1:在 g4dn 这类实例上,用ubuntu-drivers autoinstall装驱动后一定要reboot,否则内核模块不会加载,nvidia-smi会一直报通信失败。三、安装单节点 k3s用 k3s 是因为它够轻,一条命令起一个完整的单节点集群,适合做实验。sudobashinstall-k3s.sh脚本的核心就一条 k3s 官方安装命令,关键在几个参数:curl-sfLhttps://get.k3s.io|\INSTALL_K3S_VERSIONv1.34.10k3s1\INSTALL_K3S_EXECserver --write-kubeconfig-mode 0644 --disable traefik\sh-INSTALL_K3S_VERSION固定版本:GPU Operator、KServe 等对 K8s 版本有兼容矩阵,固定版本避免踩兼容坑(本系列固定 1.34)--write-kubeconfig-mode 0644:让非 root 用户也能读 kubeconfig,后面 helm 要用--disable traefik:k3s 默认装 Traefik Ingress,实验用不到,关掉省内存(16GB 内存要精打细算)脚本随后用kubectl wait --forconditionReady node等节点就绪,避免装完立刻操作却报 not ready。关键输出:安装k3s v1.34.10k3s1 [INFO] systemd: Starting k3s 等待节点Ready node/ip-172-31-16-110 condition met验证节点:sudok3s kubectl get nodesNAME STATUS ROLES AGE VERSION ip-172-31-16-110 Ready control-plane 55s v1.34.10k3s1节点 Ready,容器运行时是 containerd。四、安装 GPU Operator4.1 先装 helmk3s 自带 kubectl,但不含 helm,而 GPU Operator 是通过 Helm Chart 部署的。先装 helm:curl-fsSLhttps://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3|bashhelm version然后把 KUBECONFIG 指向 k3s:exportKUBECONFIG/etc/rancher/k3s/k3s.yamlsudochmod644/etc/rancher/k3s/k3s.yaml kubectl get nodes坑点2:k3s 不含 helm,需要单独安装;且 k3s 的 kubeconfig 默认是 root 权限,普通用户要读需要放开权限或用 sudo。4.2 部署 GPU Operatorbashinstall-gpu-operator.sh脚本的核心是一条helm upgrade --install,但有几个专门为 k3s 和驱动已装场景准备的关键参数,这是最容易踩坑的地方:helm upgrade--installgpu-operator nvidia/gpu-operator\--namespacegpu-operator--version版本--wait\--setdriver.enabledfalse\--settoolkit.enabledfalse\--setdcgmExporter.enabledtrue\--set-string toolkit.env[0].nameCONTAINERD_CONFIG\--set-string toolkit.env[0].value/var/lib/rancher/k3s/agent/etc/containerd/config.toml\--set-string toolkit.env[1].nameCONTAINERD_SOCKET\--set-string toolkit.env[1].value/run/k3s/containerd/containerd.sock逐个说明为什么这么设:driver.enabledfalse:我们已经在宿主机装了 NVIDIA 驱动(第二节),不需要 GPU Operator 再装一遍。如果这里设 true,Operator 会尝试装自己的驱动容器,和宿主机驱动冲突。这是最常见的坑:云主机通常预装了驱动,一定要关掉 Operator 的驱动安装。toolkit.enabledfalse视情况:如果宿主机已有 container toolkit 就关,否则由 Operator 装。CONTAINERD_CONFIG/CONTAINERD_SOCKET:k3s 专属。GPU Operator 默认按标准 containerd 路径找配置,但 k3s 的 containerd 配置和 socket 在/var/lib/rancher/k3s/和/run/k3s/下,不指定这两个路径,toolkit 配不进 k3s 的 containerd,GPU Pod 会起不来。用标准 K8s(kubeadm)不需要这两行,用 k3s 必须加。dcgmExporter.enabledtrue:顺便把 DCGM Exporter 装上,下一篇监控直接用。脚本前面还做了两件准备:创建 gpu-operator 命名空间,并打上pod-security.kubernetes.io/enforceprivileged标签(GPU Operator 的组件需要特权容器,否则会被 Pod Security 拦截)。关键输出:namespace/gpu-operator created Release gpu-operator does not exist. Installing it now. STATUS: deployed装完的一瞬间,组件还在初始化,大多是Init状态,这是正常的,因为 GPU Operator 的组件有依赖顺序(container-toolkit → device-plugin → validator)。等待约 2-3 分钟后:kubectl get pods-ngpu-operatorNAME READY STATUS RESTARTS AGE gpu-feature-discovery-jc65c 1/1 Running 0 2m36s gpu-operator-... 1/1 Running 1 2m53s nvidia-container-toolkit-daemonset-trg6m 1/1 Running 0 2m42s nvidia-cuda-validator-nt5fr 0/1 Completed 0 2m13s nvidia-dcgm-exporter-msdw9 1/1 Running 0 2m37s nvidia-device-plugin-daemonset-rvw7d 1/1 Running 0 2m39s nvidia-operator-validator-djlxf 1/1 Running 0 2m41s看两个关键 Pod:nvidia-cuda-validator是Completed(CUDA 验证通过)nvidia-device-plugin-daemonset是Running(GPU 已注册到 K8s)gpu-operator 和 nfd-master 各重启过一次,是初始化期间的正常抖动,稳定后即 Running,不影响结果。五、验证:GPU 真的能被调度和使用了吗Pod 起来不代表 GPU 真的能用。真正的验证要看三件事:GPU 是否成为可调度资源、Pod 能否申请到 GPU、容器里能否跑 CUDA。5.1 GPU 成为可调度资源kubectl get nodes-ocustom-columnsNAME:.metadata.name,\GPU-CAPACITY:.status.capacity.nvidia\.com/gpu,\GPU-ALLOCATABLE:.status.allocatable.nvidia\.com/gpuNAME GPU-CAPACITY GPU-ALLOCATABLE ip-172-31-16-110 1 1Capacity1、Allocatable1,说明 device plugin 成功把这张 T4 注册给了调度器,现在 K8s 认识nvidia.com/gpu了。5.2 ClusterPolicy readykubectl get clusterpolicyNAME STATUS AGE cluster-policy ready5.3 跑一个 CUDA 程序验证这是最硬的证据。跑一个官方的 VectorAdd(向量加法)CUDA 程序,看它能不能在 GPU 上算出正确结果:kubectl apply-fcuda-vectoradd.yaml kubectl logs cuda-vectoradd[Vector addition of 50000 elements] Copy input data from the host memory to the CUDA device CUDA kernel launch with 196 blocks of 256 threads Copy output data from the CUDA device to the host memory Test PASSEDTest PASSED,Pod 被调度到 GPU、CUDA kernel 成功在 T4 上执行、结果正确。到这一步才敢说 GPU 调度真的通了。5.4 容器内 nvidia-smi再起一个带 GPU 的 Pod,在容器里看 GPU:kubectl logs nvidia-smi容器内成功看到 Tesla T4、驱动 595.84、CUDA 13.2,说明 GPU 已经透传进容器。六、完整链路回顾把这一篇的证据链串起来,就是K8s 调度 GPU的完整闭环:驱动就绪(nvidia-smi 看到 T4) ↓ k3s 节点 Ready ↓ GPU Operator 部署(device-plugin/toolkit/validator 就绪) ↓ ClusterPolicy ready ↓ 节点 Allocatable 出现 nvidia.com/gpu 1 ↓ VectorAdd Test PASSED(CUDA 在 GPU 上执行) ↓ 容器内 nvidia-smi 看到 GPU每一环都有命令和输出佐证,少任何一环都不能算GPU 调度成功。七、踩过的坑小结坑现象处理驱动装完没重启nvidia-smi 报couldn’t communicatedpkg 有驱动、lsmod 无模块 → sudo rebootk3s 无 helm装 GPU Operator 报缺少 helm单独装 helm,并设置 KUBECONFIG组件初始化中刚装完 Pod 全是 Init正常,等 2-3 分钟按依赖顺序就绪小结这一篇做的事情不复杂,但它是 AI Infra 在 Kubernetes 上的地基:没有 GPU 调度,后面的模型部署、推理服务、监控都无从谈起。下一篇(实验02)会在这套环境上接入 DCGM Exporter、Prometheus 和 Grafana,把这张 GPU 的利用率、显存、温度、功耗都监控起来,并留下空闲和满载的对比图。环境是临时的 g4dn 实例,实验做完立刻terraform destroy释放,单节点 T4 环境成本极低。所有脚本、日志和验证记录都可复现。参考链接本系列开源仓库(脚本 Helm Chart Terraform):https://github.com/Jich1123/gpu-k8s-labNVIDIA GPU Operator 官方文档:https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/index.htmlk3s 官方文档:https://docs.k3s.io/Kubernetes 调度 GPU(Schedule GPUs):https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/

相关新闻