3. Kubernetes集群搭建:kubeadm部署K8s集群、配置GPU节点标签与污点、安装NVIDIA Device Plugin
好,咱们进入正题。这一章要解决的核心问题就一个:怎么让Kubernetes认识你的GPU。
你可能已经搭过K8s集群,但加上GPU之后,事情就变得微妙了。我最早踩的坑就是——集群跑起来了,Pod也调度上去了,结果一看日志,CUDA说找不到设备。嗯,那种感觉,就像你给赛车加满了油,结果发现没装发动机。
所以这一章,我会带你一步步搞定三件事:
1. 用kubeadm搭一个能用的K8s集群
2. 给GPU节点打标签、加污点,让调度器知道“这机器有宝贝”
3. 安装NVIDIA Device Plugin,让Pod真正能用上GPU
3.1 环境准备:你得先有个“干净”的机器
我个人习惯,所有节点都装Ubuntu 20.04或22.04 LTS。内核版本别太老,5.4以上就行。为啥?因为NVIDIA驱动和containerd对内核有要求,老内核容易出幺蛾子。
每台机器需要:
- Docker或containerd作为容器运行时(我推荐containerd,更轻量)
- kubeadm、kubelet、kubectl(版本保持一致,比如1.28.x)
- NVIDIA驱动(建议用官方runfile装,别用系统源里的)
3.2 用kubeadm初始化集群
初始化命令其实不复杂,但有几个参数你得留心:
# 在master节点执行
kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--apiserver-advertise-address=192.168.1.100 \
--kubernetes-version=v1.28.2
这里我解释一下:
--pod-network-cidr:Pod的网段,Flannel默认用10.244.0.0/16,你要是用Calico可以换别的--apiserver-advertise-address:master节点的IP,别写错了--kubernetes-version:指定版本,避免自动拉取最新版导致不兼容
初始化成功后,会输出一段kubeadm join命令,记得保存好。我一般直接贴到记事本里,因为后面加worker节点要用。
--control-plane-endpoint 加一个虚拟IP,或者直接用单节点模式。但生产环境别这么干。
3.3 配置GPU节点标签与污点
集群跑起来了,接下来要让K8s知道:哪些节点有GPU。
你想想看,如果没有标签和污点,调度器可能会把普通Pod调度到GPU节点上,或者把GPU任务调度到没有GPU的节点上。结果就是资源浪费,或者任务跑不起来。
我的做法是两步走:
3.3.1 打标签
kubectl label node gpu-node-01 accelerator=nvidia
这个标签可以自定义,但业界惯例用accelerator=nvidia。你可以在Pod的nodeSelector里引用它。
3.3.2 加污点
kubectl taint nodes gpu-node-01 nvidia.com/gpu=:NoSchedule
污点的作用是什么?说白了,就是告诉调度器:“这机器有GPU,但只有能容忍这个污点的Pod才能上来”。
为什么要加污点?因为GPU是稀缺资源。你肯定不希望一个只跑Nginx的Pod占着GPU节点,对吧?
tolerations,否则调度不上去。我见过有人忘了加,结果Pod一直Pending,查了半天才发现。
3.4 安装NVIDIA Device Plugin
好,现在节点有了标签和污点,但K8s还是不知道节点上有多少GPU、什么型号。这时候就需要NVIDIA Device Plugin了。
它本质上是一个DaemonSet,在每个GPU节点上运行,负责:
- 向Kubelet上报GPU资源(比如
nvidia.com/gpu: 1) - 在Pod启动时,把GPU设备挂载进去
3.4.1 安装步骤
# 创建命名空间
kubectl create namespace gpu-operator
# 部署Device Plugin
kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.14.0/nvidia-device-plugin.yml
部署完之后,检查一下Pod状态:
kubectl get pods -n gpu-operator
如果看到Running状态,说明成功了。这时候你再看看节点资源:
kubectl describe node gpu-node-01 | grep -A5 "Capacity"
你应该能看到类似这样的输出:
nvidia.com/gpu: 1
嗯,看到这个就放心了。K8s终于知道你有GPU了。
sudo apt install nvidia-container-toolkit
sudo systemctl restart containerd
3.5 验证:跑一个GPU测试Pod
光说不练假把式。我们来跑一个测试Pod,看看GPU到底能不能用:
apiVersion: v1
kind: Pod
metadata:
name: gpu-test
spec:
containers:
- name: cuda-vector-add
image: nvidia/cuda:12.2.0-base-ubuntu22.04
command: ["nvidia-smi"]
resources:
limits:
nvidia.com/gpu: 1
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
nodeSelector:
accelerator: nvidia
保存为gpu-test.yaml,然后:
kubectl apply -f gpu-test.yaml
kubectl logs gpu-test
如果看到nvidia-smi的输出,恭喜你,集群GPU调度成功了。
kubectl describe pod gpu-test 看看事件。常见原因:污点没容忍、节点标签不匹配、或者Device Plugin没装好。
3.6 本章知识体系
下面这张图,帮你理清整个流程的逻辑关系:
3.7 避坑指南
最后,分享几个我实际项目中踩过的坑:
- 驱动版本不匹配:CUDA 11.8的驱动不能跑CUDA 12.x的容器。我建议统一用最新LTS驱动,省心。
- containerd配置:默认的containerd不启用NVIDIA runtime。你需要在
/etc/containerd/config.toml里加上default_runtime_name = "nvidia"。 - 节点重启后:kubelet可能不会自动加载NVIDIA模块。我习惯在
/etc/modules-load.d/nvidia.conf里写上nvidia、nvidia_uvm、nvidia_drm。
嗯,这一章的内容就到这里。记住,GPU集群搭建不是一锤子买卖,后续的监控、扩缩容、多租户隔离,都是建立在今天这个基础之上的。