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节点,对吧?

🔑 关键点: 加了污点之后,你的GPU Pod必须加上对应的 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了。

⚠️ 注意: Device Plugin依赖NVIDIA Container Toolkit。如果你没装,Pod会报错说找不到nvidia-smi。安装命令很简单:
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调度成功了。

💡 小技巧: 如果你发现Pod一直Pending,用 kubectl describe pod gpu-test 看看事件。常见原因:污点没容忍、节点标签不匹配、或者Device Plugin没装好。

3.6 本章知识体系

下面这张图,帮你理清整个流程的逻辑关系:

K8s GPU集群搭建核心流程 kubeadm init 初始化控制平面 打标签 + 加污点 标识GPU节点 Device Plugin 上报GPU资源 安装containerd + kubelet 安装NVIDIA驱动 + toolkit 验证Pod调度 三个步骤缺一不可,顺序不能乱 关键:标签用于调度选择,污点用于资源隔离,Device Plugin用于资源上报

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集群搭建不是一锤子买卖,后续的监控、扩缩容、多租户隔离,都是建立在今天这个基础之上的。

可可精品资料库