K8S管理GPU等简述

核心铁律:/dev/nvidia0 = 物理 GPU 第 1 块,/dev/nvidia1 = 物理 GPU 第 2 块...... 一个编号文件就对应一块实实在在的 GPU 硬件,程序认这个文件就等于认这块 GPU

以 ** 服务器插了 4 块物理 GPU(对应/dev/nvidia0~nvidia3)** 为例,结合官方文档与实践规范修正细节,完整保留全流程逻辑,新增一站式测试脚本与避坑指南,形成 "原理 + 操作 + 验证 + 排错" 的完整闭环。

1. 宿主机底层准备:先让系统 "看见" GPU 文件

这一步是所有操作的基础,没做好后面全白搭,需严格遵循版本兼容要求:

  • 装 GPU 驱动
    • 要求:安装与 GPU 型号匹配的 NVIDIA 官方驱动,版本≥418.81.07(支持 CUDA 的最低驱动版本, newer 驱动向下兼容旧 CUDA 版本);需先禁用系统自带的 nouveau 内核模块(否则驱动无法加载)。

    • 禁用 nouveau 步骤(必做): bash

      复制代码
      sudo tee /etc/modprobe.d/blacklist-nouveau.conf <<< "blacklist nouveau"
      sudo tee -a /etc/modprobe.d/blacklist-nouveau.conf <<< "options nouveau modeset=0"
      sudo update-initramfs -u && sudo reboot
    • 验证禁用:重启后执行 lsmod | grep nouveau,无输出则禁用成功。

    • 驱动安装后效果:系统自动在 /dev 目录生成两类文件:

      • 核心设备文件:/dev/nvidia0-nvidia3(4 块 GPU 对应 4 个文件,少一个说明识别失败);
      • 辅助控制文件:/dev/nvidiactl(总控制器)、/dev/nvidia-modeset(模式设置)、/dev/nvidia-uvm(统一内存管理)------ 必须与核心文件同时存在。
    • 验证驱动:执行 nvidia-smi,能看到 4 块 GPU 的型号、驱动版本、CUDA 版本,说明驱动安装成功。

  • 装 "桥梁工具":nvidia-container-toolkit
    • 作用:让容器运行时(containerd/CRI-O)能识别并挂载 GPU 设备文件,版本需≥1.7.0。

    • 配置 containerd(关键修正:需注册 NVIDIA 运行时): bash

      复制代码
      # 安装工具后配置运行时
      nvidia-ctk runtime configure --runtime=containerd --set-as-default
      # 验证配置:/etc/containerd/config.toml 中会新增 nvidia 运行时配置
      cat /etc/containerd/config.toml | grep -A 5 "nvidia"
      # 重启containerd生效
      systemctl restart containerd

2. 给 GPU 节点设 "门禁":标签 + 污点

GPU 很贵,需通过 "标签 + 污点" 确保资源不被滥用,新增 K8s 默认识别标签:

  • 第一步:打标签 :除自定义标签外,需保留 K8s 默认 GPU 标签(设备插件依赖此标签调度):

    bash

    复制代码
    # 自定义标签:标记GPU数量和型号
    kubectl label nodes <你的GPU节点名> gpu-count=4 gpu-model=Tesla-T4
    # 默认标签:K8s识别GPU节点的核心标签(必加)
    kubectl label nodes <你的GPU节点名> feature.node.kubernetes.io/pci-10de.present=true
  • 第二步:加污点 :设 "门禁",仅允许带容忍的 Pod 调度:

    bash

    复制代码
    kubectl taint nodes <你的GPU节点名> hardware=gpu:NoSchedule
    • 注意:若 GPU 节点已存在其他 NoSchedule 污点,需在 Pod 中添加对应容忍,否则设备插件 Pod 无法部署。

3. 部署 GPU 设备插件:让 K8s "认识" GPU 资源

K8s 本身不识别 GPU,需部署 NVIDIA Device Plugin("翻译官"),必须用 DaemonSet 方式:

  • 核心要求

    • K8s 集群版本≥1.10,插件与 K8s 版本需兼容(推荐 v0.14.0 及以上);
    • 插件通过 NVML 库扫描 GPU,依赖宿主机驱动和运行时配置正确。
  • 部署命令 (官方稳定版本):

    bash

    复制代码
    kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.14.0/nvidia-device-plugin.yml
  • 关键验证(新增)

    1. 查看插件 Pod 状态:kubectl get pods -n kube-system -l app=nvidia-device-plugin,需为 Running;
    2. 查看插件日志(排查故障核心):kubectl logs -n kube-system <插件Pod名>,无 "CUDA error""connection refused" 等错误;
    3. 验证 K8s 资源注册:kubectl describe node <你的GPU节点名> | grep "nvidia.com/gpu",能看到capacity: nvidia.com/gpu: 4,说明资源已上报。
  • 插件的 3 个核心工作

    1. 扫描节点 /dev/nvidia0~3 及 NVML 库,确认 GPU 数量和健康状态;
    2. 向 K8s APIServer 注册资源 nvidia.com/gpu: 4,纳入集群资源管理;
    3. 实时监控 GPU 状态,若某块 GPU 故障(如驱动崩溃),立即上报 K8s 标记为不可用。

4. 写 Pod 配置:申请 GPU = 要对应文件

Pod 配置需严格遵循 K8s GPU 调度规范,修正环境变量用法与资源声明规则:

4.1 基础版 Pod YAML(随机分配 2 块 GPU)

yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: gpu-2-pod
spec:
  containers:
  - name: cuda-app
    image: nvidia/cuda:12.2.0-runtime
    command: ["nvidia-smi"]
    resources:
      limits:
        nvidia.com/gpu: 2  # 必选:GPU只能在limits中声明,requests默认等于limits
      requests:
        nvidia.com/gpu: 2  # 可选:若指定,必须与limits值相等(K8s强制要求)
    env:
    - name: NVIDIA_DRIVER_CAPABILITIES  # 新增:指定容器所需驱动能力(nvidia-smi依赖utility)
      value: "compute,utility"
  nodeSelector:
    gpu-count: "4"
    gpu-model: Tesla-T4
    feature.node.kubernetes.io/pci-10de.present: "true"  # 匹配默认GPU标签
  tolerations:
  - key: "hardware"
    operator: "Equal"
    value: "gpu"
    effect: "NoSchedule"

4.2 进阶版 Pod YAML(指定 GPU 卡号 / UUID)

NVIDIA_VISIBLE_DEVICES 支持卡号、UUID 两种指定方式(修正原单一用法):

yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: gpu-specify-pod
spec:
  containers:
  - name: cuda-app
    image: nvidia/cuda:12.2.0-runtime
    command: ["nvidia-smi"]
    env:
    - name: NVIDIA_VISIBLE_DEVICES  # 方式1:指定卡号(0和2)
      value: "0,2"
      # 方式2:指定UUID(需先通过nvidia-smi -L获取)
      # value: "GPU-5da6e67e-fd5a-88fb-7a0e-109c3284f7bf,GPU-242b3020-8e5c-813a-42d9-475766d52f9d"
    - name: NVIDIA_DRIVER_CAPABILITIES
      value: "compute,utility"
    resources:
      limits:
        nvidia.com/gpu: 2
  nodeSelector:
    feature.node.kubernetes.io/pci-10de.present: "true"
  tolerations:
  - key: "hardware"
    value: "gpu"
    effect: "NoSchedule"
  • 关键说明:NVIDIA_VISIBLE_DEVICES 还支持 all(所有 GPU)、none(禁用 GPU)等值,需配合 NVIDIA_DRIVER_CAPABILITIES 使用才能生效。

5. K8s 调度 + 挂载:把 GPU 文件 "搬" 到容器里

提交 Pod 配置后,K8s 自动完成 5 个关键步骤,补充核心细节:

  1. 调度器筛选节点:同时满足 3 个条件 ------① 有 feature.node.kubernetes.io/pci-10de.present=true 标签;② 容忍 hardware=gpu 污点;③ nvidia.com/gpu 空闲数≥2;
  2. 分配 GPU 资源:K8s 通过设备插件获取空闲 GPU 列表,随机选择 2 个(如nvidia1nvidia3),并锁定资源防止重复分配;
  3. 设备文件挂载:nvidia-container-toolkit 不仅挂载核心文件(nvidia1nvidia3)和辅助文件,还会挂载驱动依赖的动态链接库(如/usr/local/nvidia/lib);
  4. 资源隔离:通过 cgroup 限制容器仅能访问分配的 GPU,同时通过环境变量 LD_LIBRARY_PATH 自动配置库路径,确保程序能调用 GPU;
  5. 容器启动:nvidia-smi 依赖 NVIDIA_DRIVER_CAPABILITIES=utility 才能运行,否则会提示 "command not found" 或 "no devices found"。

6. 一站式测试脚本:部署→验证→删除

编写 gpu-test-all.sh 脚本,补充错误处理与关键验证步骤,避免手动操作失误:

6.1 脚本内容

bash

复制代码
#!/bin/bash
# K8s GPU测试一键脚本(含错误处理)
# 使用前替换 <你的GPU节点名> 为实际节点名称
set -e  # 遇到错误立即退出,避免资源残留

# 定义变量
POD_NAME="gpu-2-pod"
NODE_NAME="<你的GPU节点名>"
YAML_FILE="gpu-test-pod.yaml"

# 前置检查:确认kubectl能连接集群
if ! kubectl cluster-info &> /dev/null; then
  echo "ERROR: 无法连接K8s集群,请检查kubeconfig配置"
  exit 1
fi

# 前置检查:确认节点存在
if ! kubectl get node ${NODE_NAME} &> /dev/null; then
  echo "ERROR: 节点 ${NODE_NAME} 不存在,请检查节点名"
  exit 1
fi

# 步骤1:生成Pod YAML文件
echo "===== 1. 生成GPU测试Pod YAML文件 ====="
cat > ${YAML_FILE} << EOF
apiVersion: v1
kind: Pod
metadata:
  name: ${POD_NAME}
spec:
  containers:
  - name: cuda-app
    image: nvidia/cuda:12.2.0-runtime
    command: ["nvidia-smi"]
    env:
    - name: NVIDIA_DRIVER_CAPABILITIES
      value: "compute,utility"
    resources:
      limits:
        nvidia.com/gpu: 2
      requests:
        nvidia.com/gpu: 2
  nodeSelector:
    gpu-count: "4"
    gpu-model: Tesla-T4
    feature.node.kubernetes.io/pci-10de.present: "true"
  tolerations:
  - key: "hardware"
    operator: "Equal"
    value: "gpu"
    effect: "NoSchedule"
EOF

# 步骤2:部署Pod
echo -e "\n===== 2. 部署GPU测试Pod ====="
kubectl apply -f ${YAML_FILE}

# 步骤3:等待Pod执行完成(nvidia-smi执行后Pod会变为Completed状态)
echo -e "\n===== 3. 等待Pod执行完毕(最长等待30秒) ====="
if ! kubectl wait pod/${POD_NAME} --for=condition=Completed --timeout=30s; then
  echo -e "\nERROR: Pod执行超时或失败,查看日志:kubectl logs ${POD_NAME}"
  kubectl delete pod ${POD_NAME} --force
  rm -f ${YAML_FILE}
  exit 1
fi

# 步骤4:验证1 - 查看容器内的GPU设备文件
echo -e "\n===== 4. 容器内的GPU设备文件 ====="
kubectl exec ${POD_NAME} -- ls /dev/nvidia*

# 步骤5:验证2 - 查看GPU信息日志(核心验证)
echo -e "\n===== 5. GPU信息日志 ====="
kubectl logs ${POD_NAME} | grep -E "GPU|Driver Version|CUDA Version"

# 步骤6:删除Pod,释放GPU资源
echo -e "\n===== 6. 删除Pod,释放GPU资源 ====="
kubectl delete -f ${YAML_FILE}
rm -f ${YAML_FILE}

echo -e "\n===== 测试完成!所有GPU资源已释放 ====="

6.2 脚本使用方法

  1. 替换脚本中的 <你的GPU节点名> 为实际节点名称;
  2. 赋予执行权限:chmod +x gpu-test-all.sh
  3. 运行脚本:./gpu-test-all.sh

6.3 预期输出

  • 设备文件:2 个核心 GPU 文件(如nvidia1nvidia3)+ 3 个辅助文件;
  • GPU 日志:显示 2 块 GPU 的型号、驱动版本、CUDA 版本,无报错;
  • 最终状态:Pod 被成功删除,kubectl describe node <节点名>nvidia.com/gpu 空闲数恢复为 4。

7. 手动验证 + 回收

若不想用脚本,可手动执行以下操作,新增故障排查命令:

  • 部署 Podkubectl apply -f gpu-test-pod.yaml
  • 查看 Pod 状态kubectl get pods -w(等待状态变为 Completed)
  • 验证 1:容器内 GPU 文件kubectl exec -it ${POD_NAME} -- ls /dev/nvidia*
  • 验证 2:GPU 信息kubectl logs ${POD_NAME}
  • 排错命令(新增)
    • 若 PodPending:kubectl describe pod ${POD_NAME},查看 "Events" 栏(常见原因:资源不足、污点未容忍、节点标签不匹配);
    • 若 PodCrashLoopBackOff:kubectl logs ${POD_NAME} --previous,查看启动错误(常见原因:驱动不兼容、运行时未配置);
  • 手动回收kubectl delete pod ${POD_NAME}

8. 核心细节 + 避坑指南

8.1 关键规范

  1. GPU 资源声明规则 :只能在limits中指定,requests若指定必须与limits相等,K8s 不支持 GPU 资源的弹性调度(因 GPU 是独占设备);
  2. 环境变量必填项NVIDIA_DRIVER_CAPABILITIES 必须指定(至少包含compute,运行nvidia-smi需加utility),否则容器无法调用 GPU 或工具;
  3. 插件部署要求 :必须用 DaemonSet,且 Pod 需能访问 kubelet 的设备插件套接字(/var/lib/kubelet/device-plugins/nvidia.sock),否则无法注册资源。

8.2 常见坑与解决方案

问题现象 根本原因 解决方案
插件 Pod 启动失败,日志显示 "CUDA error: no CUDA-capable device" 驱动未安装或 nouveau 未禁用 重新安装驱动,执行禁用 nouveau 步骤并重启
PodPending,提示 "Insufficient nvidia.com/gpu" 节点未上报 GPU 资源,或资源已被占用 1. 查看插件日志;2. 验证kubectl describe node是否有nvidia.com/gpu;3. 检查节点是否有未删除的 GPU Pod
容器内执行nvidia-smi提示 "command not found" 未配置NVIDIA_DRIVER_CAPABILITIES=utility 在 Pod YAML 中添加该环境变量
运行时配置后仍无法挂载 GPU containerd 未重启或未设为默认运行时
相关推荐
赵文宇(温玉)1 天前
Docker是时代发展的产物
运维·docker·容器
赵文宇(温玉)1 天前
Docker发展时间线(2008~2025)
运维·docker·容器
牛奔1 天前
Kubernetes 节点安全维护全流程:从驱逐 Pod 到彻底清理残留
java·安全·云原生·容器·kubernetes
草木红1 天前
Docker 和 portainer 安装
运维·docker·容器·portainer
伞啊伞1 天前
k8s(三)操作管理
云原生·容器·kubernetes
x10n91 天前
理解K8s动态准入控制器-基于Admission Webhook实现Sidecar自动注入检验等
云原生·容器·kubernetes·k8s准入控制器
LucidX1 天前
Kubernetes集群架构与组件
容器·架构·kubernetes
Qianliwind1 天前
安卓手机作为服务器安装docker安装外网可访问网站
服务器·docker·容器
skywalk81631 天前
FreeBSD系统使用docker-compose使用docker容器(没搞定)
spring cloud·docker·容器