找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1863

积分

0

好友

242

主题
发表于 昨天 04:40 | 查看: 4| 回复: 0

一、概述

1.1 背景介绍

AI/ML 工作负载(大模型训练、推理服务、LoRA 微调)对 GPU 算力的需求呈指数级增长,GPU 集群已成为基础设施核心组件。裸机环境下,GPU 软件栈的管理是一项繁重工作——从底层驱动到容器运行时,层层依赖关系如下:

NVIDIA Driver → CUDA Toolkit → NVIDIA Container Toolkit → Device Plugin → GPU Operator

手动维护这条链路意味着:驱动版本与内核耦合、节点扩容时重复劳动、升级时逐台操作。NVIDIA GPU Operator 将整个软件栈封装为 Kubernetes Operator,通过 DaemonSet 自动完成驱动安装、容器运行时配置、设备插件注册和监控组件部署,实现 GPU 节点的"即插即用"。

1.2 GPU 型号与适用场景

型号 架构 FP16 TFLOPS 显存 适用场景 TDP 功耗 价格区间(美元)
A100 80GB Ampere 312 80GB HBM2e 大模型训练、科学计算 300W $10,000-15,000
H100 SXM Hopper 990 80GB HBM3 超大规模训练、高吞吐推理 700W $25,000-40,000
L40S Ada Lovelace 362 48GB GDDR6X 推理、微调、图形渲染 350W $7,000-10,000
T4 Turing 65 16GB GDDR6 轻量推理、边缘部署 70W $2,000-3,000
A10G Ampere 125 24GB GDDR6X 云端推理、视频编码 150W $3,000-5,000

1.3 GPU 共享技术对比

共享方式 隔离性 GPU 利用率 适用场景 支持型号
独占(Exclusive) 完全隔离 低(常空闲) 大模型训练 全部
MIG 硬件级隔离 多租户推理 A100/H100
Time-Slicing 无隔离(时间片轮转) 开发测试、轻量推理 全部
MPS 进程级共享 多进程并行计算 Volta+
vGPU 虚拟化隔离 虚拟机场景 需 vGPU 许可证

1.4 适用场景

  • AI 训练集群:大模型预训练、分布式训练(多机多卡 NCCL 通信)
  • 推理服务集群:Triton / vLLM 推理服务,需要 GPU 共享与弹性伸缩
  • 混合工作负载:训练与推理混部,通过 MIG / Time-Slicing 提升利用率
  • 科学计算:HPC 场景,CUDA 并行计算、分子动力学模拟

1.5 环境要求

组件 版本要求 说明
Kubernetes 1.31+ 需启用 DevicePlugin feature gate
GPU Operator 24.x Helm Chart 部署
NVIDIA Driver 550+ Operator 自动安装或预装
Linux 内核 6.x 推荐 6.1 LTS 或 6.5+
容器运行时 containerd 1.7+ 需支持 CDI(Container Device Interface)
Helm 3.12+ 用于部署 Operator

二、详细步骤

2.1 GPU 节点准备

2.1.1 硬件检查

# 确认 GPU 设备已被系统识别
lspci | grep -i nvidia

# 查看 GPU 详细信息(如已安装驱动)
nvidia-smi

# 检查 GPU 拓扑结构(多卡场景关注 NVLink 连接)
nvidia-smi topo -m

2.1.2 内核与驱动兼容性

# 查看当前内核版本
uname -r

# 确认内核头文件已安装(Operator 编译驱动需要)
apt list --installed 2>/dev/null | grep linux-headers-$(uname -r)
# 或 RHEL 系
rpm -qa | grep kernel-devel-$(uname -r)

2.1.3 Secure Boot 与 Nouveau 处理

# 检查 Secure Boot 状态(开启时 Operator 需签名驱动模块)
mokutil --sb-state

# 禁用 Nouveau 开源驱动(与 NVIDIA 官方驱动冲突)
cat /etc/modprobe.d/blacklist-nouveau.conf
# 内容应为:
# blacklist nouveau
# options nouveau modeset=0

# 重建 initramfs 后重启
sudo update-initramfs -u && sudo reboot

2.1.4 BIOS 设置要点

  • IOMMU:启用(Intel VT-d / AMD-Vi),GPU 直通和 vGPU 场景必需
  • Above 4G Decoding:启用,多 GPU 节点必须开启,否则部分 GPU 无法寻址
  • SR-IOV:如使用 vGPU 或网络直通,需启用
  • PCIe Gen4/Gen5:确认 BIOS 中 PCIe 链路速度设置为 Auto 或最高代

2.2 GPU Operator 部署

2.2.1 Helm 安装

# 添加 NVIDIA Helm 仓库
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update

# 部署 GPU Operator(生产环境推荐指定版本)
helm install gpu-operator nvidia/gpu-operator \
  --namespace gpu-operator \
  --create-namespace \
  --version v24.9.0 \
  --values values-gpu-operator.yaml

2.2.2 组件说明

GPU Operator 部署后会在 gpu-operator 命名空间创建以下 DaemonSet / Deployment:

组件 类型 作用
nvidia-driver-daemonset DaemonSet 自动编译安装 NVIDIA 驱动
nvidia-container-toolkit DaemonSet 配置容器运行时的 GPU 支持
nvidia-device-plugin DaemonSet 向 K8s 注册 nvidia.com/gpu 资源
nvidia-dcgm DaemonSet GPU 管理守护进程
nvidia-dcgm-exporter DaemonSet 采集 GPU 指标暴露给 Prometheus
node-feature-discovery DaemonSet 检测节点硬件特征并打标签
gpu-feature-discovery DaemonSet 检测 GPU 型号、驱动版本等特征

2.2.3 验证部署

# 检查所有组件 Pod 状态
kubectl get pods -n gpu-operator -o wide

# 确认 GPU 资源已注册到节点
kubectl describe node <gpu-node> | grep -A5 "Allocatable" | grep nvidia

# 运行测试 Pod 验证 GPU 可用
kubectl run gpu-test --rm -it --restart=Never \
  --image=nvcr.io/nvidia/cuda:12.6.0-base-ubuntu22.04 \
  --limits=nvidia.com/gpu=1 -- nvidia-smi

2.2.4 预装驱动场景

部分环境(云厂商 GPU 实例、已有驱动的裸金属)无需 Operator 安装驱动:

# values.yaml 中禁用驱动安装
driver:
  enabled: false  # 使用宿主机预装驱动
toolkit:
  enabled: true   # 仍需配置容器运行时

2.3 MIG(Multi-Instance GPU)配置

2.3.1 MIG 原理

MIG 是 A100/H100 的硬件级 GPU 分区技术,将一块物理 GPU 切分为最多 7 个独立实例,每个实例拥有独立的显存、缓存和计算单元,故障隔离互不影响。

2.3.2 MIG 策略配置

# 在节点上打标签指定 MIG 策略
# single: 所有 GPU 使用相同 MIG 配置
# mixed: 不同 GPU 可使用不同配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: mig-parted-config
  namespace: gpu-operator
data:
  config.yaml: |
    version: v1
    mig-configs:
      # 7 个 1g.10gb 实例(A100 80GB)—— 最大化推理并发
      all-1g.10gb:
        - device-filter: ["0x20B210DE"]    # A100 80GB PCI ID
          devices: all
          mig-enabled: true
          mig-devices:
            "1g.10gb": 7
      # 混合切分:2 个大实例 + 1 个小实例
      mixed-strategy:
        - device-filter: ["0x20B210DE"]
          devices: all
          mig-enabled: true
          mig-devices:
            "3g.40gb": 2
            "1g.10gb": 1

2.3.3 K8s 中 MIG 资源声明

# Pod 请求 MIG 实例
resources:
  limits:
    nvidia.com/mig-1g.10gb: 1  # 请求 1 个 1g.10gb MIG 实例

2.4 时间片共享(Time-Slicing)配置

2.4.1 ConfigMap 定义

apiVersion: v1
kind: ConfigMap
metadata:
  name: time-slicing-config
  namespace: gpu-operator
data:
  any: |-
    version: v1
    flags:
      migStrategy: none
    sharing:
      timeSlicing:
        renameByDefault: false
        failRequestsGreaterThanOne: false
        resources:
          - name: nvidia.com/gpu
            replicas: 4    # 每块 GPU 虚拟为 4 份,无硬件隔离

2.4.2 GPU Operator 引用配置

# 部署时指定时间片配置
helm upgrade gpu-operator nvidia/gpu-operator \
  --namespace gpu-operator \
  --set devicePlugin.config.name=time-slicing-config \
  --set devicePlugin.config.default=any

2.4.3 MIG vs Time-Slicing 选型

维度 MIG Time-Slicing
隔离性 硬件级,显存/算力完全隔离 无隔离,共享显存
支持型号 仅 A100/H100 所有 NVIDIA GPU
配置复杂度 高(需重启 GPU) 低(ConfigMap 即可)
适用场景 生产推理、多租户 开发测试、CI/CD

2.5 DCGM Exporter 监控部署

2.5.1 DCGM 架构

DCGM(Data Center GPU Manager)是 NVIDIA 官方的 GPU 管理框架,DCGM Exporter 将其指标转换为 Prometheus 格式。GPU Operator 默认部署 DCGM Exporter,也可独立部署。

2.5.2 自定义采集指标

# 自定义 DCGM Exporter 采集字段
apiVersion: v1
kind: ConfigMap
metadata:
  name: dcgm-exporter-csv
  namespace: gpu-operator
data:
  counters.csv: |
    # 格式: DCGM字段ID, Prometheus指标类型, 指标描述
    DCGM_FI_DEV_GPU_UTIL,       gauge, GPU 核心利用率(%)
    DCGM_FI_DEV_MEM_COPY_UTIL,  gauge, 显存带宽利用率(%)
    DCGM_FI_DEV_FB_USED,        gauge, 已用显存(MB)
    DCGM_FI_DEV_FB_FREE,        gauge, 空闲显存(MB)
    DCGM_FI_DEV_GPU_TEMP,       gauge, GPU 温度(℃)
    DCGM_FI_DEV_POWER_USAGE,    gauge, 实时功耗(W)
    DCGM_FI_DEV_PCIE_TX_THROUGHPUT,  gauge, PCIe 发送吞吐(KB/s)
    DCGM_FI_DEV_PCIE_RX_THROUGHPUT,  gauge, PCIe 接收吞吐(KB/s)
    DCGM_FI_DEV_ECC_SBE_VOL_TOTAL,  gauge, ECC 单比特纠错计数
    DCGM_FI_DEV_ECC_DBE_VOL_TOTAL,  gauge, ECC 双比特错误计数(严重)
    DCGM_FI_DEV_XID_ERRORS,     gauge, XID 错误事件
    DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL, gauge, NVLink 总带宽(MB/s)
    DCGM_FI_PROF_GR_ENGINE_ACTIVE,   gauge, 图形引擎活跃比例
    DCGM_FI_PROF_SM_ACTIVE,     gauge, SM 活跃比例
    DCGM_FI_PROF_SM_OCCUPANCY,  gauge, SM 占用率

2.5.3 ServiceMonitor 配置

# Prometheus Operator 自动发现 DCGM Exporter
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: dcgm-exporter
  namespace: gpu-operator
  labels:
    release: kube-prometheus-stack  # 匹配 Prometheus Operator 的 serviceMonitorSelector
spec:
  selector:
    matchLabels:
      app: nvidia-dcgm-exporter
  endpoints:
  - port: gpu-metrics
    interval: 15s  # 采集间隔 15 秒
    path: /metrics
  namespaceSelector:
    matchNames:
    - gpu-operator

2.5.4 Grafana 仪表盘

# 导入 NVIDIA 官方 Grafana Dashboard
# Dashboard ID: 12239(NVIDIA DCGM Exporter Dashboard)
# 在 Grafana UI 中:Dashboards → Import → 输入 12239 → 选择 Prometheus 数据源

# 或通过 ConfigMap 自动导入(适用于 Grafana Operator / Sidecar 模式)
kubectl create configmap grafana-dashboard-gpu \
  --from-file=nvidia-dcgm-dashboard.json \
  -n monitoring
kubectl label configmap grafana-dashboard-gpu \
  grafana_dashboard=1 -n monitoring

三、示例代码和配置

3.1 GPU Operator 生产级 Helm values.yaml

3.1.1 完整配置文件

# 文件路径:values-gpu-operator.yaml
# GPU Operator 生产环境配置 —— 适用于 v24.9.0

# --- 全局配置 ---
operator:
  defaultRuntime: containerd  # 容器运行时,生产环境统一用 containerd
  initContainer:
    image: nvcr.io/nvidia/cuda
    version: 12.6.0-base-ubuntu22.04  # init 容器基础镜像

# --- NVIDIA 驱动管理 ---
driver:
  enabled: true  # 由 Operator 自动安装驱动(预装驱动设为 false)
  version: "550.127.05"  # 锁定驱动版本,避免自动升级导致不兼容
  repository: nvcr.io/nvidia
  image: driver
  rdma:
    enabled: false  # RDMA/GPUDirect 按需开启(InfiniBand 场景)
  licensingConfig:
    nlsEnabled: false  # vGPU 许可证,非 vGPU 场景关闭
  upgradePolicy:
    autoUpgrade: false  # 生产环境禁止自动升级驱动
    maxParallelUpgrades: 1  # 升级时最多同时处理 1 个节点
  drain:
    enabled: true  # 升级前驱逐 Pod
    force: false
    podSelector: ""
    timeoutSeconds: 300
    deleteEmptyDir: false

# --- NVIDIA Container Toolkit ---
toolkit:
  enabled: true
  version: v1.16.2-ubuntu20.04  # 容器工具包版本

# --- Device Plugin(设备插件) ---
devicePlugin:
  enabled: true
  version: v0.16.2
  config:
    name: time-slicing-config  # 引用时间片 ConfigMap(不需要时注释掉)
    default: any
  env:
  - name: PASS_DEVICE_SPECS  # 传递设备信息给容器
    value: "true"
  - name: DEVICE_LIST_STRATEGY  # 设备列表策略
    value: envvar
  - name: DEVICE_ID_STRATEGY  # 使用 UUID 标识设备
    value: uuid

# --- DCGM ---
dcgm:
  enabled: true  # 启用 DCGM 守护进程

# --- DCGM Exporter(监控指标采集) ---
dcgmExporter:
  enabled: true
  version: 3.3.8-3.6.0-ubuntu22.04
  env:
  - name: DCGM_EXPORTER_LISTEN  # 监听地址
    value: ":9400"
  - name: DCGM_EXPORTER_KUBERNETES  # 启用 K8s Pod 信息关联
    value: "true"
  - name: DCGM_EXPORTER_COLLECTORS  # 自定义指标配置文件路径
    value: "/etc/dcgm-exporter/counters.csv"
  serviceMonitor:
    enabled: true  # 自动创建 ServiceMonitor
    interval: 15s
    additionalLabels:
      release: kube-prometheus-stack  # 匹配 Prometheus Operator 选择器

# --- Node Feature Discovery ---
nfd:
  enabled: true  # 自动检测节点硬件特征

# --- GPU Feature Discovery ---
gfd:
  enabled: true  # 自动检测 GPU 型号并打标签
  version: v0.8.2

# --- MIG Manager ---
migManager:
  enabled: true  # MIG 管理器(A100/H100 场景)
  config:
    name: mig-parted-config  # 引用 MIG 分区配置

# --- 节点选择器(仅在 GPU 节点部署) ---
daemonsets:
  labels: {}
  annotations: {}
  tolerations:
  - key: nvidia.com/gpu
    operator: Exists
    effect: NoSchedule
  nodeSelector: {}  # 可指定 node-role.kubernetes.io/gpu: ""

# --- 资源限制 ---
resources:
  operator:
    limits:
      cpu: 500m
      memory: 512Mi
    requests:
      cpu: 200m
      memory: 256Mi

3.2 GPU 健康检查与巡检脚本

3.2.1 集群 GPU 巡检脚本

#!/bin/bash
set -euo pipefail
# 文件名:gpu-health-check.sh
# 功能:遍历所有 GPU 节点,检查 GPU 状态、温度、ECC 错误、利用率
# 用法:./gpu-health-check.sh [温度告警阈值,默认 80]

TEMP_THRESHOLD="${1:-80}"  # GPU 温度告警阈值(℃)
ECC_DBE_THRESHOLD=0            # 双比特 ECC 错误容忍值(出现即告警)
REPORT_FILE="/tmp/gpu-health-report-$(date +%Y%m%d-%H%M%S).txt"

# 获取所有 GPU 节点列表
GPU_NODES=$(kubectl get nodes -l nvidia.com/gpu.present=true \
  -o jsonpath='{.items
  • .metadata.name}') if [[ -z "${GPU_NODES}" ]]; then echo "[错误] 未发现 GPU 节点,请检查节点标签" >&2 exit 1 fi echo "========================================" | tee "${REPORT_FILE}" echo " GPU 集群健康巡检报告" | tee -a "${REPORT_FILE}" echo " 时间:$(date '+%Y-%m-%d %H:%M:%S')" | tee -a "${REPORT_FILE}" echo " 温度阈值:${TEMP_THRESHOLD}℃" | tee -a "${REPORT_FILE}" echo "========================================" | tee -a "${REPORT_FILE}" TOTAL_GPUS=0 WARN_COUNT=0 ERROR_COUNT=0 for NODE in ${GPU_NODES}; do echo "" | tee -a "${REPORT_FILE}" echo "--- 节点:${NODE} ---" | tee -a "${REPORT_FILE}" # 通过 DaemonSet Pod 在目标节点执行 nvidia-smi   POD=$(kubectl get pods -n gpu-operator -l app=nvidia-driver-daemonset \     --field-selector spec.nodeName="${NODE}" \     -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true) if [[ -z "${POD}" ]]; then echo "  [警告] 未找到驱动 Pod,节点可能异常" | tee -a "${REPORT_FILE}"     ((WARN_COUNT++)) continue fi # 采集 GPU 信息:索引、名称、温度、利用率、显存使用、ECC 错误   GPU_INFO=$(kubectl exec -n gpu-operator "${POD}" -- \     nvidia-smi --query-gpu=index,name,temperature.gpu,utilization.gpu,\ memory.used,memory.total,ecc.errors.uncorrected.volatile.total \     --format=csv,noheader,nounits 2>/dev/null || echo "EXEC_FAILED") if [[ "${GPU_INFO}" == "EXEC_FAILED" ]]; then echo "  [错误] nvidia-smi 执行失败" | tee -a "${REPORT_FILE}"     ((ERROR_COUNT++)) continue fi while IFS=',' read -r IDX NAME TEMP UTIL MEM_USED MEM_TOTAL ECC_DBE; do     # 去除前后空格     IDX=$(echo "${IDX}" | xargs)     TEMP=$(echo "${TEMP}" | xargs)     UTIL=$(echo "${UTIL}" | xargs)     ECC_DBE=$(echo "${ECC_DBE}" | xargs)     ((TOTAL_GPUS++))     STATUS="正常" # 温度检查 if [[ "${TEMP}" -ge "${TEMP_THRESHOLD}" ]]; then       STATUS="[高温告警]"       ((WARN_COUNT++)) fi # ECC 双比特错误检查(出现即为硬件故障前兆) if [[ "${ECC_DBE}" != "N/A" && "${ECC_DBE}" -gt "${ECC_DBE_THRESHOLD}" ]]; then       STATUS="[ECC 错误 - 建议更换]"       ((ERROR_COUNT++)) fi printf "  GPU %s | %-20s | %s℃ | 利用率 %s%% | 显存 %s/%s MiB | ECC: %s | %s\n" \ "${IDX}" "${NAME}" "${TEMP}" "${UTIL}" "${MEM_USED}" "${MEM_TOTAL}" "${ECC_DBE}" "${STATUS}" \       | tee -a "${REPORT_FILE}" done <<< "${GPU_INFO}" done echo "" | tee -a "${REPORT_FILE}" echo "========================================" | tee -a "${REPORT_FILE}" echo " 汇总:共 ${TOTAL_GPUS} 块 GPU | 告警 ${WARN_COUNT} | 错误 ${ERROR_COUNT}" \   | tee -a "${REPORT_FILE}" echo " 报告已保存:${REPORT_FILE}" | tee -a "${REPORT_FILE}" echo "========================================" | tee -a "${REPORT_FILE}" # 存在错误时返回非零退出码(便于 CI/CD 集成) [[ "${ERROR_COUNT}" -eq 0 ]] || exit 1
  • 3.3 GPU 资源使用报告脚本

    3.3.1 按命名空间统计 GPU 分配与利用率

    #!/bin/bash
    set -euo pipefail
    # 文件名:gpu-usage-report.sh
    # 功能:按命名空间和用户统计 GPU 分配数量与实际利用率
    # 依赖:kubectl、jq、nvidia-smi(通过 DCGM Exporter 指标)
    
    METRICS_URL="${DCGM_EXPORTER_URL:-http://localhost:9400/metrics}"
    
    echo "============================================"
    echo " GPU 资源使用报告"
    echo " 时间:$(date '+%Y-%m-%d %H:%M:%S')"
    echo "============================================"
    
    # --- 第一部分:K8s 层面 GPU 分配统计 ---
    echo ""
    
    echo "【一、GPU 分配统计(按命名空间)】"
    echo "--------------------------------------------"
    printf "%-30s %-10s %-10s\n" "命名空间" "已请求" "Limit"
    echo "--------------------------------------------"
    
    # 获取所有请求了 GPU 的 Pod,按命名空间汇总
    kubectl get pods --all-namespaces -o json | jq -r '
      .items[]
      | select(.status.phase == "Running")
      | select(.spec.containers[].resources.limits["nvidia.com/gpu"] != null)
      | {
          ns: .metadata.namespace,
          req: (.spec.containers[].resources.requests["nvidia.com/gpu"] // "0"),
          lim: (.spec.containers[].resources.limits["nvidia.com/gpu"] // "0")
        }
    ' | jq -s '
      group_by(.ns)
      | map({
          namespace: .[0].ns,
          total_req: (map(.req | tonumber) | add),
          total_lim: (map(.lim | tonumber) | add)
        })
      | sort_by(-.total_lim)
      | .[]
      | "\(.namespace)\t\(.total_req)\t\(.total_lim)"
    ' -r | while IFS=$'\t' read -r NS REQ LIM; do
    printf "%-30s %-10s %-10s\n" "${NS}" "${REQ}" "${LIM}"
    done
    
    # --- 第二部分:集群 GPU 容量概览 ---
    echo ""
    
    echo "【二、集群 GPU 容量概览】"
    echo "--------------------------------------------"
    
    TOTAL_CAPACITY=$(kubectl get nodes -l nvidia.com/gpu.present=true \
      -o jsonpath='{range .items
  • }{.status.capacity.nvidia\.com/gpu}{"\n"}{end}' \   | awk '{s+=$1} END {print s+0}') TOTAL_ALLOCATABLE=$(kubectl get nodes -l nvidia.com/gpu.present=true \   -o jsonpath='{range .items
  • }{.status.allocatable.nvidia\.com/gpu}{"\n"}{end}' \   | awk '{s+=$1} END {print s+0}') TOTAL_REQUESTED=$(kubectl get pods --all-namespaces -o json | jq '   [.items[]    | select(.status.phase == "Running")    | .spec.containers[]    | .resources.requests["nvidia.com/gpu"] // "0"    | tonumber   ] | add // 0') AVAILABLE=$((TOTAL_ALLOCATABLE - TOTAL_REQUESTED)) if [[ "${TOTAL_ALLOCATABLE}" -gt 0 ]]; then   USAGE_PCT=$((TOTAL_REQUESTED * 100 / TOTAL_ALLOCATABLE)) else   USAGE_PCT=0 fi printf "  总容量:%s 块 GPU\n" "${TOTAL_CAPACITY}" printf "  可分配:%s 块 GPU\n" "${TOTAL_ALLOCATABLE}" printf "  已分配:%s 块 GPU\n" "${TOTAL_REQUESTED}" printf "  空闲:  %s 块 GPU\n" "${AVAILABLE}" printf "  分配率:%s%%\n" "${USAGE_PCT}" # --- 第三部分:Top GPU 消费者 --- echo "" echo "【三、Top 10 GPU 消费 Pod】" echo "--------------------------------------------" printf "%-40s %-20s %-5s\n" "Pod 名称" "命名空间" "GPU" echo "--------------------------------------------" kubectl get pods --all-namespaces -o json | jq -r '   [.items[]    | select(.status.phase == "Running")    | select(.spec.containers[].resources.limits["nvidia.com/gpu"] != null)    | {        name: .metadata.name,        ns: .metadata.namespace,        gpu: (.spec.containers[].resources.limits["nvidia.com/gpu"] | tonumber)      }   ]   | sort_by(-.gpu)   | .[0:10]   | .[]   | "\(.name)\t\(.ns)\t\(.gpu)" ' | while IFS=$'\t' read -r NAME NS GPU; do printf "%-40s %-20s %-5s\n" "${NAME}" "${NS}" "${GPU}" done echo "" echo "============================================" echo " 报告生成完毕" echo "============================================"
  • 四、最佳实践和注意事项

    4.1 最佳实践

    4.1.1 GPU 资源规划

    GPU 集群的资源规划直接决定了硬件投资回报率。实际生产中,训练任务和推理任务对 GPU 的需求差异很大,需要分池管理。

    训练 vs 推理 GPU 配比参考

    维度 训练集群 推理集群
    GPU 型号偏好 A100 80GB / H100 SXM A30 / L4 / T4
    显存需求 大模型需 40GB+,多卡并行 单模型通常 8-24GB
    网络要求 NVLink + InfiniBand,低延迟 普通 25GbE 即可
    利用率目标 70-85%(长时间满载) 40-60%(按请求波动)
    调度策略 Gang Scheduling,整机分配 Bin Packing,碎片利用
    典型配比 集群 GPU 总量的 60-70% 集群 GPU 总量的 30-40%

    显存碎片化管理

    推理场景下多个小模型共享 GPU 时,显存碎片化是个隐蔽问题。PyTorch 默认的 CUDA 内存分配器会导致显存无法被其他进程复用。

    # 查看各 GPU 显存碎片情况
    nvidia-smi --query-gpu=index,memory.total,memory.used,memory.free --format=csv,noheader,nounits | \
      awk -F', ' '{
        total=$2; used=$3; free=$4;
        frag_ratio = (free > 0 && used > 0) ? (free/(total)*100) : 0;
        printf "GPU %s: 总计 %sMiB, 已用 %sMiB, 空闲 %sMiB, 碎片率 %.1f%%\n", $1, total, used, free, frag_ratio
      }'
    
    # 设置 PyTorch 使用 CUDA 内存池,减少碎片
    # 在训练/推理脚本启动前设置环境变量
    export PYTORCH_CUDA_ALLOC_CONF="expandable_segments:True,max_split_size_mb:128"

    GPU 池化策略

    通过 Node Label 和 Taint 将 GPU 节点划分为不同资源池,配合 K8s 调度实现隔离:

    # 标记训练节点池
    kubectl label nodes gpu-node-{01..08} gpu-pool=training
    kubectl taint nodes gpu-node-{01..08} gpu-pool=training:NoSchedule
    
    # 标记推理节点池
    kubectl label nodes gpu-node-{09..12} gpu-pool=inference
    kubectl taint nodes gpu-node-{09..12} gpu-pool=inference:NoSchedule
    
    # 标记开发/调试节点池(允许抢占)
    kubectl label nodes gpu-node-{13..14} gpu-pool=dev
    kubectl taint nodes gpu-node-{13..14} gpu-pool=dev:PreferNoSchedule

    4.1.2 散热与功耗管理

    GPU 是数据中心里最大的热源之一。A100 SXM 单卡 TDP 400W,一台 8 卡机器仅 GPU 就 3.2kW,加上 CPU 和其他组件,单机功耗轻松突破 6kW。散热跟不上,GPU 会触发热保护降频,训练任务直接变慢。

    温度阈值与告警策略

    温度范围 状态 处理措施
    < 70°C 正常 无需干预
    70-80°C 偏高 检查风扇转速和机房温度
    80-85°C 警告 降低功耗限制,排查散热
    > 85°C 持续 5min 严重 立即告警,准备迁移负载
    > 90°C 危险 GPU 自动降频,需紧急处理
    #!/bin/bash
    set -euo pipefail
    # GPU 功耗限制脚本 - 高温时自动降低功耗
    # 适用场景:夏季机房温度偏高时的临时保护措施
    
    TEMP_THRESHOLD=83
    POWER_LIMIT_NORMAL=400    # 正常功耗限制(瓦)
    POWER_LIMIT_THROTTLE=300   # 降温功耗限制(瓦)
    
    gpu_count=$(nvidia-smi --query-gpu=count --format=csv,noheader,nounits | head -1)
    
    for ((i=0; i<gpu_count; i++)); do
        temp=$(nvidia-smi -i "$i" --query-gpu=temperature.gpu --format=csv,noheader,nounits)
        current_pl=$(nvidia-smi -i "$i" --query-gpu=power.limit --format=csv,noheader,nounits | cut -d'.' -f1)
    
    if [ "$temp" -ge "$TEMP_THRESHOLD" ] && [ "$current_pl" -gt "$POWER_LIMIT_THROTTLE" ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] GPU $i 温度 ${temp}°C 超阈值,降低功耗至 ${POWER_LIMIT_THROTTLE}W"
            sudo nvidia-smi -i "$i" -pl "$POWER_LIMIT_THROTTLE"
    elif [ "$temp" -lt $((TEMP_THRESHOLD - 10)) ] && [ "$current_pl" -lt "$POWER_LIMIT_NORMAL" ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] GPU $i 温度 ${temp}°C 已恢复,恢复功耗至 ${POWER_LIMIT_NORMAL}W"
            sudo nvidia-smi -i "$i" -pl "$POWER_LIMIT_NORMAL"
    fi
    done

    4.1.3 驱动与固件管理

    GPU 驱动版本不统一是集群运维中最常见的坑。节点 A 跑的 535.129.03,节点 B 跑的 545.23.08,训练任务调度到不同节点时 CUDA 行为可能不一致,排查起来非常痛苦。

    驱动版本统一策略

    • 选定一个经过验证的驱动版本作为基线(如 535.183.01 LTS),全集群统一
    • 通过 GPU Operator 的 driver.version 参数锁定版本,避免自动升级
    • 新驱动先在 dev 池灰度验证 2 周,再推到 inference 池,最后推 training 池

    滚动升级流程

    #!/bin/bash
    set -euo pipefail
    # GPU 驱动滚动升级脚本
    # 逐节点执行:cordon → drain → 升级 → uncordon
    
    NODE_LIST="gpu-node-09 gpu-node-10 gpu-node-11 gpu-node-12"
    TARGET_DRIVER="535.183.01"
    DRAIN_TIMEOUT=600  # 排空超时时间(秒)
    
    for node in $NODE_LIST; do
    echo "========== 开始升级节点: $node =========="
    
    # 1. 标记节点不可调度
    echo "[1/5] Cordon 节点 $node"
        kubectl cordon "$node"
    
    # 2. 排空节点上的 Pod(跳过 DaemonSet)
    echo "[2/5] Drain 节点 $node(超时 ${DRAIN_TIMEOUT}s)"
        kubectl drain "$node" \
            --ignore-daemonsets \
            --delete-emptydir-data \
            --timeout="${DRAIN_TIMEOUT}s" \
            --force
    
    # 3. 远程执行驱动升级(假设已配置 SSH 免密)
    echo "[3/5] 升级驱动至 $TARGET_DRIVER"
        ssh "$node" "sudo /opt/scripts/upgrade-gpu-driver.sh $TARGET_DRIVER"
    
    # 4. 验证驱动版本
    echo "[4/5] 验证驱动版本"
        actual_version=$(ssh "$node" "nvidia-smi --query-gpu=driver_version --format=csv,noheader | head -1")
    if [ "$actual_version" != "$TARGET_DRIVER" ]; then
    echo "错误:驱动版本不匹配!期望 $TARGET_DRIVER,实际 $actual_version"
    echo "节点 $node 保持 cordon 状态,请人工介入"
    continue
    fi
    
    # 5. 恢复节点调度
    echo "[5/5] Uncordon 节点 $node"
        kubectl uncordon "$node"
    
    echo "节点 $node 升级完成,等待 60s 后继续下一个节点"
        sleep 60
    done

    CUDA 兼容性矩阵(常用组合):

    GPU Driver CUDA Toolkit PyTorch 适用 GPU
    535.183.x (LTS) 12.2 2.1.x - 2.3.x A100/A30/V100
    545.23.x 12.3 2.2.x - 2.4.x A100/H100/L4
    550.54.x 12.4 2.4.x - 2.5.x H100/H200/L40S
    560.35.x 12.6 2.5.x+ H100/H200/B200

    关键原则:CUDA Toolkit 版本不能高于驱动支持的最大 CUDA 版本。用 nvidia-smi 右上角显示的 CUDA Version 是驱动支持的上限,不是实际安装的 Toolkit 版本。

    4.1.4 多租户 GPU 隔离

    多团队共享 GPU 集群时,隔离和计费是绕不开的问题。K8s 原生的 ResourceQuota 只能做数量限制,真正的硬件级隔离需要 MIG 或 vGPU。

    ResourceQuota 限制 GPU 配额

    # 限制 ml-training 命名空间最多使用 16 块 GPU
    apiVersion: v1
    kind: ResourceQuota
    metadata:
      name: gpu-quota
      namespace: ml-training
    spec:
      hard:
        requests.nvidia.com/gpu: "16"
        limits.nvidia.com/gpu: "16"
    ---
    # 限制 ml-inference 命名空间最多使用 8 块 GPU
    apiVersion: v1
    kind: ResourceQuota
    metadata:
      name: gpu-quota
      namespace: ml-inference
    spec:
      hard:
        requests.nvidia.com/gpu: "8"
        limits.nvidia.com/gpu: "8"

    MIG 硬隔离 vs 时间片软隔离选型

    对比维度 MIG(Multi-Instance GPU) 时间片(Time-Slicing)
    隔离级别 硬件级,独立显存和计算单元 软件级,共享显存和计算单元
    支持 GPU A100、A30、H100(Ampere+) 所有 NVIDIA GPU
    显存隔离 完全隔离,互不影响 无隔离,OOM 风险互相传染
    故障隔离 一个实例崩溃不影响其他 一个进程崩溃可能影响全卡
    性能损耗 几乎无损耗 上下文切换有 5-15% 损耗
    灵活性 切分粒度固定(需 GPU Reset) 任意数量共享,动态调整
    适用场景 生产推理、SLA 要求高 开发调试、批量小任务
    运维复杂度 高(需提前规划切分方案) 低(配置 Device Plugin 即可)

    GPU 使用计费方案

    #!/bin/bash
    set -euo pipefail
    # GPU 使用量统计脚本 - 按命名空间汇总 GPU·小时
    # 建议通过 CronJob 每小时执行一次,结果写入数据库
    
    OUTPUT_FILE="/var/log/gpu-billing/$(date '+%Y-%m-%d').csv"
    mkdir -p "$(dirname "$OUTPUT_FILE")"
    
    # 写入 CSV 表头(文件不存在时)
    if [ ! -f "$OUTPUT_FILE" ]; then
    echo "timestamp,namespace,pod,gpu_count,gpu_util_avg,mem_util_avg" > "$OUTPUT_FILE"
    fi
    
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    
    # 遍历所有使用 GPU 的 Pod
    kubectl get pods --all-namespaces -o json | \
      jq -r '.items[] |
        select(.spec.containers[].resources.limits["nvidia.com/gpu"] != null) |
        select(.status.phase == "Running") |
        "\(.metadata.namespace)\t\(.metadata.name)\t\(.spec.containers[0].resources.limits["nvidia.com/gpu"])"' | \
    while IFS=$'\t' read -r ns pod gpu; do
    echo "${TIMESTAMP},${ns},${pod},${gpu}" >> "$OUTPUT_FILE"
    done
    
    echo "计费数据已写入: $OUTPUT_FILE"

    4.2 注意事项

    4.2.1 配置注意事项

    ⚠️ 警告:ECC 错误累积是 GPU 硬件故障的前兆

    ECC(Error Correcting Code)错误分为可纠正(Correctable)和不可纠正(Uncorrectable)两种。可纠正错误偶尔出现是正常的,但如果短时间内大量累积,说明显存正在老化。不可纠正错误一旦出现,该 GPU 应立即下线排查。

    # 检查所有 GPU 的 ECC 错误计数
    nvidia-smi --query-gpu=index,ecc.errors.corrected.volatile.total,ecc.errors.uncorrected.volatile.total,ecc.errors.corrected.aggregate.total,ecc.errors.uncorrected.aggregate.total --format=csv
    
    # 重置 volatile 计数器(不影响 aggregate 累计值)
    sudo nvidia-smi -i 0 --reset-ecc-errors=volatile

    ⚠️ 驱动升级必须先排空节点:直接在运行 GPU 任务的节点上升级驱动,会导致所有使用 GPU 的进程立即崩溃(CUDA Error: driver shutting down)。务必先 kubectl drain

    ⚠️ MIG 模式切换需要 GPU Reset:启用或关闭 MIG 模式时,GPU 上不能有任何活跃进程。切换过程中 GPU 会短暂不可用,必须提前迁移负载。

    # 检查 GPU 是否有活跃进程(切换 MIG 前必须确认为空)
    nvidia-smi -i 0 --query-compute-apps=pid,name,used_memory --format=csv
    # 如果有进程,先排空再操作

    4.2.2 常见错误

    错误现象 原因分析 解决方案
    Pod 处于 Pending,事件显示 Insufficient nvidia.com/gpu 1) GPU 资源确实不足;2) Device Plugin 未正常运行;3) 节点有 Taint 未配置 Toleration kubectl describe node <node> 检查 Allocatable GPU 数量;kubectl get pods -n gpu-operator 确认 device-plugin Pod 状态
    nvidia-smiNVML: Driver/library version mismatch 内核模块版本与用户态库版本不一致,通常是升级驱动后未重启 重启节点,或 sudo rmmod nvidia_uvm nvidia_drm nvidia_modeset nvidia && sudo modprobe nvidia 重新加载模块
    训练报错 CUDA error: CUBLAS_STATUS_EXECUTION_FAILED Xid 错误导致 GPU 进入异常状态,常见 Xid 31(GPU 内存页错误)、Xid 79(GPU 掉卡) dmesg | grep -i "xid" 查看具体错误码;Xid 79 需要重置 GPU 或重启节点
    MIG 配置失败 Unable to create GPU instance 1) GPU 上有活跃进程;2) 请求的 MIG Profile 与已有切分冲突;3) GPU 不支持 MIG 先确认 nvidia-smi mig -lgi 当前切分状态;清理进程后用 nvidia-smi mig -dci && nvidia-smi mig -dgi 重置
    GPU Operator 安装后节点 nvidia.com/gpu: 0 1) 驱动未正确安装;2) Container Toolkit 未就绪;3) Device Plugin 启动失败 按顺序检查:nvidia-driver Pod 日志 → nvidia-container-toolkit Pod 日志 → nvidia-device-plugin Pod 日志
    RuntimeError: CUDA out of memorynvidia-smi 显示有空闲显存 PyTorch 内存分配器的碎片化问题,已分配的显存块无法被新请求复用 设置 PYTORCH_CUDA_ALLOC_CONF="expandable_segments:True";或在代码中调用 torch.cuda.empty_cache()

    4.2.3 兼容性问题

    GPU Operator 版本与 K8s 版本

    GPU Operator 支持的 K8s 版本 默认驱动版本 备注
    v23.9.x 1.25 - 1.28 535.129.03 LTS 驱动分支
    v24.3.x 1.27 - 1.30 550.54.15 支持 H100 NVL
    v24.6.x 1.28 - 1.31 560.35.03 支持 B200
    v24.9.x 1.29 - 1.32 565.57.01 支持 GH200

    不同 Linux 发行版支持差异

    发行版 GPU Operator 支持 注意事项
    Ubuntu 22.04 LTS 完整支持 推荐选择,社区测试最充分
    RHEL 8.x / 9.x 完整支持 需要额外配置 SELinux 策略
    Rocky Linux 8/9 完整支持 RHEL 兼容,配置相同
    SLES 15 SP4+ 基本支持 部分功能需手动配置
    Debian 12 社区支持 非官方验证,生产慎用

    五、故障排查和监控

    5.1 故障排查

    5.1.1 日志查看

    GPU 集群出问题时,日志是第一手线索。需要关注三个层面:GPU Operator 组件日志、内核日志、nvidia-smi 输出。

    # GPU Operator 各组件日志 - 按排查优先级排列
    
    # 1. 驱动容器日志(驱动加载失败是最常见的根因)
    kubectl logs -n gpu-operator -l app=nvidia-driver-daemonset --tail=100
    
    # 2. Device Plugin 日志(GPU 无法被 K8s 识别时查看)
    kubectl logs -n gpu-operator -l app=nvidia-device-plugin-daemonset --tail=100
    
    # 3. Container Toolkit 日志(容器内无法访问 GPU 时查看)
    kubectl logs -n gpu-operator -l app=nvidia-container-toolkit-daemonset --tail=100
    
    # 4. GPU Feature Discovery 日志(节点 Label 异常时查看)
    kubectl logs -n gpu-operator -l app=gpu-feature-discovery --tail=100
    
    # 5. DCGM Exporter 日志(监控指标缺失时查看)
    kubectl logs -n gpu-operator -l app=nvidia-dcgm-exporter --tail=100
    # 内核日志中的 GPU 相关信息
    # Xid 错误是 NVIDIA GPU 的硬件/驱动级错误码,非常关键
    dmesg | grep -iE "(nvrm|nvidia|xid|gpu)" | tail -30
    
    # 持续监控内核 GPU 日志(排查间歇性问题时使用)
    dmesg -wH | grep -iE "(nvrm|nvidia|xid)"
    
    # 检查 PCIe 总线错误(GPU 掉卡的常见原因)
    dmesg | grep -iE "(pcie|aer|error.*[0-9a-f]{4}:[0-9a-f]{2})" | tail -20

    5.1.2 常见问题排查

    问题一:GPU 掉卡(Xid 79 错误)

    Xid 79 是 GPU has fallen off the bus,意味着 GPU 与 PCIe 总线失去通信。这是最严重的 GPU 故障之一,可能原因包括:PCIe 插槽接触不良、电源供电不稳、GPU 硬件故障。

    # 确认 Xid 79 错误
    dmesg | grep "Xid.*79"
    
    # 检查 GPU PCIe 链路状态
    nvidia-smi -q -d PERFORMANCE | grep -A5 "Pcie"
    
    # 检查 PCIe 链路速度是否降级(正常应为 Gen4 x16)
    lspci -vvv -s $(nvidia-smi --query-gpu=pci.bus_id --format=csv,noheader | head -1) 2>/dev/null | grep -i "lnksta:"

    解决方案

    1. 尝试 GPU Reset:sudo nvidia-smi -i <gpu_id> -r
    2. 如果 Reset 失败,需要重启节点
    3. 重启后仍然复现,检查 PCIe 物理连接,必要时更换 GPU 或 Riser Card
    4. 反复出现 Xid 79 的 GPU 应送 RMA

    问题二:ECC 不可纠正错误

    # 查看 ECC 错误详情
    nvidia-smi -i 0 -q -d ECC
    
    # 关键字段解读:
    # Volatile - 本次启动以来的计数
    # Aggregate - 累计历史计数(跨重启保留)
    # Single Bit (Correctable) - 已自动纠正,偶发正常
    # Double Bit (Uncorrectable) - 无法纠正,数据已损坏
    
    # 如果 Aggregate Uncorrectable > 0,该 GPU 需要重点关注
    nvidia-smi --query-gpu=index,ecc.errors.uncorrected.aggregate.total --format=csv

    解决方案

    1. 单次 Uncorrectable 错误:记录并观察,可能是宇宙射线等偶发因素
    2. 多次 Uncorrectable 错误:立即将节点标记为不可调度,迁移负载
    3. 联系 NVIDIA 支持,提供 nvidia-bug-report.sh 输出,申请 RMA

    问题三:GPU 利用率持续偏低

    GPU 利用率长期低于 30%,说明计算资源被浪费。常见原因是数据加载瓶颈(CPU/IO 跟不上 GPU 计算速度)、batch size 设置过小、模型太小不足以填满 GPU。

    # 同时观察 GPU 利用率和显存利用率
    watch -n 1 'nvidia-smi --query-gpu=index,utilization.gpu,utilization.memory,memory.used,memory.total --format=csv'
    
    # 如果 GPU Util 低但 Memory Util 高 → 可能是数据加载瓶颈
    # 如果 GPU Util 低且 Memory Util 也低 → batch size 太小或模型太小
    
    # 检查 CPU 是否成为瓶颈(数据预处理占满 CPU)
    top -bn1 | head -5
    # 检查磁盘 IO 是否成为瓶颈(数据读取慢)
    iostat -x 1 3

    问题四:驱动崩溃恢复

    # 检查驱动是否处于异常状态
    nvidia-smi
    # 如果报 "Unable to determine the device handle for GPU",驱动已崩溃
    
    # 尝试重新加载驱动模块(需要先停止所有 GPU 进程)
    sudo fuser -v /dev/nvidia*  # 查看占用 GPU 设备的进程
    sudo lsof /dev/nvidia*      # 另一种方式查看
    
    # 确认无进程后,重新加载模块
    sudo rmmod nvidia_uvm nvidia_drm nvidia_modeset nvidia
    sudo modprobe nvidia
    nvidia-smi  # 验证恢复

    5.1.3 nvidia-smi 高级诊断

    nvidia-smi -q-d 参数可以按类别输出详细诊断信息,比默认输出丰富得多:

    # 性能状态诊断 - 查看是否降频、节流原因
    nvidia-smi -q -d PERFORMANCE
    # 关注 Performance State(P0=最高性能,P8=空闲)
    # 关注 Clocks Throttle Reasons(降频原因)
    
    # ECC 错误诊断 - 详细的错误计数和位置
    nvidia-smi -q -d ECC
    
    # 温度诊断 - 各传感器温度和阈值
    nvidia-smi -q -d TEMPERATURE
    # 关注 GPU Shutdown Temp(强制关机温度,通常 96°C)
    # 关注 GPU Slowdown Temp(降频温度,通常 92°C)
    
    # 功耗诊断 - 实时功耗和限制
    nvidia-smi -q -d POWER
    # 关注 Power Draw vs Power Limit
    # 关注 Current Power Limit vs Max Power Limit
    
    # 一次性输出所有诊断信息(生成完整报告时使用)
    nvidia-smi -q -d ALL > /tmp/gpu-diag-$(hostname)-$(date +%Y%m%d).txt
    
    # 生成 NVIDIA 官方 Bug Report(提交工单时必须附带)
    sudo nvidia-bug-report.sh
    # 输出文件:/tmp/nvidia-bug-report.log.gz

    5.2 性能监控

    5.2.1 关键指标

    GPU 集群监控需要覆盖计算、显存、温度、功耗、硬件健康五个维度。单看 GPU 利用率是不够的——一块温度 90°C、ECC 错误不断累积的 GPU,即使利用率正常也需要立即关注。

    # 一行命令持续监控所有关键指标(每 2 秒刷新)
    watch -n 2 'nvidia-smi --query-gpu=index,name,temperature.gpu,power.draw,power.limit,utilization.gpu,utilization.memory,memory.used,memory.total,ecc.errors.uncorrected.volatile.total,pcie.link.gen.current,pcie.link.width.current --format=csv'

    5.2.2 监控指标说明

    指标名称 正常范围 告警阈值 说明
    GPU 利用率 训练 70-100%,推理 30-70% 训练 <50% 持续 10min 过低说明存在瓶颈或资源浪费
    显存使用率 60-90% >95% 持续 5min 接近满载时 OOM 风险高
    GPU 温度 40-80°C >85°C 持续 5min 持续高温加速硬件老化
    功耗 TDP 的 50-95% >TDP 的 100% 超过 Power Limit 会触发降频
    ECC 可纠正错误 0-10/天 >100/小时 快速累积预示显存退化
    ECC 不可纠正错误 0 >0 一旦出现必须立即处理
    PCIe 带宽 Gen4 x16 降级到 Gen3 或 x8 链路降级影响多卡通信性能
    NVLink 带宽 接近理论值 <理论值 50% 影响多卡并行训练效率

    5.2.3 DCGM Exporter + Prometheus + Grafana 告警规则

    DCGM Exporter 是 NVIDIA 官方的 GPU 指标采集器,直接对接 Prometheus。以下是生产环境验证过的告警规则:

    # 文件路径:prometheus/rules/gpu-alerts.yml
    groups:
    - name: gpu_hardware_alerts
      rules:
      # GPU 温度告警
      - alert: GPUTemperatureHigh
        expr: DCGM_FI_DEV_GPU_TEMP > 85
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "GPU {{ $labels.gpu }} 温度过高: {{ $value }}°C"
          description: "节点 {{ $labels.instance }} 的 GPU {{ $labels.gpu }} 温度持续超过 85°C 达 5 分钟"
          runbook: "检查机房温度和风扇状态,必要时执行 nvidia-smi -pl 降低功耗"
    
      - alert: GPUTemperatureCritical
        expr: DCGM_FI_DEV_GPU_TEMP > 90
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "GPU {{ $labels.gpu }} 温度危险: {{ $value }}°C"
          description: "节点 {{ $labels.instance }} 的 GPU {{ $labels.gpu }} 即将触发硬件降频保护"
    
      # ECC 错误告警
      - alert: GPUECCUncorrectableError
        expr: DCGM_FI_DEV_ECC_DBE_VOL_TOTAL > 0
        for: 0m
        labels:
          severity: critical
        annotations:
          summary: "GPU {{ $labels.gpu }} 出现不可纠正 ECC 错误"
          description: "节点 {{ $labels.instance }} 的 GPU {{ $labels.gpu }} 检测到 Double Bit ECC 错误,需立即隔离排查"
    
      - alert: GPUECCCorrectableRateHigh
        expr: rate(DCGM_FI_DEV_ECC_SBE_VOL_TOTAL[1h]) > 100
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "GPU {{ $labels.gpu }} 可纠正 ECC 错误率偏高"
          description: "节点 {{ $labels.instance }} 的 GPU {{ $labels.gpu }} 每小时可纠正错误超过 100 次,显存可能正在退化"
    
    - name: gpu_utilization_alerts
      rules:
      # GPU 利用率告警
      - alert: GPUUtilizationLow
        expr: DCGM_FI_DEV_GPU_UTIL < 30 and ON() (count(kube_pod_container_resource_requests{resource="nvidia_com_gpu"}) > 0)
        for: 30m
        labels:
          severity: warning
        annotations:
          summary: "GPU {{ $labels.gpu }} 利用率持续偏低: {{ $value }}%"
          description: "有 Pod 请求了 GPU 但利用率低于 30%,可能存在资源浪费"
    
      # 显存告警
      - alert: GPUMemoryUsageHigh
        expr: (DCGM_FI_DEV_FB_USED / DCGM_FI_DEV_FB_FREE_AND_USED) * 100 > 95
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "GPU {{ $labels.gpu }} 显存使用率超过 95%: {{ $value | humanize }}%"
          description: "节点 {{ $labels.instance }} 的 GPU 显存即将耗尽,OOM 风险高"
    
      # 功耗告警
      - alert: GPUPowerDrawHigh
        expr: DCGM_FI_DEV_POWER_USAGE > DCGM_FI_DEV_POWER_LIMIT * 0.95
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "GPU {{ $labels.gpu }} 功耗接近上限"
          description: "功耗 {{ $value }}W 接近 Power Limit,可能触发硬件降频"

    5.3 备份与恢复

    5.3.1 GPU Operator 配置备份

    GPU Operator 的配置散落在 Helm values、ConfigMap、自定义资源等多个位置。定期备份这些配置,在集群迁移或灾难恢复时能省大量时间。

    #!/bin/bash
    set -euo pipefail
    # GPU Operator 配置备份脚本
    # 建议通过 CronJob 每天执行一次
    
    BACKUP_DIR="/opt/backup/gpu-operator/$(date '+%Y-%m-%d')"
    mkdir -p "$BACKUP_DIR"
    
    echo "=== GPU Operator 配置备份开始 ==="
    
    # 1. 备份 Helm release values
    echo "[1/5] 备份 Helm values"
    helm get values gpu-operator -n gpu-operator -o yaml > "$BACKUP_DIR/helm-values.yaml" 2>/dev/null || \
    echo "警告:无法获取 Helm values,可能未通过 Helm 安装"
    
    # 2. 备份 GPU Operator 命名空间下所有资源
    echo "[2/5] 备份命名空间资源"
    for resource in configmap secret daemonset deployment service serviceaccount; do
        kubectl get "$resource" -n gpu-operator -o yaml > "$BACKUP_DIR/$resource.yaml" 2>/dev/null
    done
    
    # 3. 备份 ClusterPolicy(GPU Operator 核心配置)
    echo "[3/5] 备份 ClusterPolicy"
    kubectl get clusterpolicy -o yaml > "$BACKUP_DIR/clusterpolicy.yaml" 2>/dev/null
    
    # 4. 备份 GPU 相关节点标签
    echo "[4/5] 备份节点 GPU 标签"
    kubectl get nodes -o json | jq '[.items[] | select(.metadata.labels["nvidia.com/gpu.present"] == "true") | {
        name: .metadata.name,
        labels: (.metadata.labels | with_entries(select(.key | startswith("nvidia.com") or startswith("gpu"))))
    }]' > "$BACKUP_DIR/node-gpu-labels.json"
    
    # 5. 备份 ResourceQuota 和 LimitRange
    echo "[5/5] 备份 GPU 配额配置"
    kubectl get resourcequota --all-namespaces -o json | \
        jq '[.items[] | select(.spec.hard["requests.nvidia.com/gpu"] != null)]' \
        > "$BACKUP_DIR/gpu-resourcequotas.json"
    
    # 压缩并清理 30 天前的备份
    tar -czf "${BACKUP_DIR}.tar.gz" -C "$(dirname "$BACKUP_DIR")" "$(basename "$BACKUP_DIR")"
    rm -rf "$BACKUP_DIR"
    find "$(dirname "$BACKUP_DIR")" -name "*.tar.gz" -mtime +30 -delete
    
    echo "=== 备份完成: ${BACKUP_DIR}.tar.gz ==="

    5.3.2 GPU 硬件故障应急流程

    GPU 硬件故障(Xid 79 掉卡、ECC 不可纠正错误、物理损坏)需要快速响应,核心目标是:最小化对业务的影响,安全地隔离故障节点,完成硬件更换后重新加入集群。

    #!/bin/bash
    set -euo pipefail
    # GPU 硬件故障应急处理脚本
    # 用法: ./gpu-emergency.sh <node-name> <故障描述>
    
    NODE="${1:?用法: $0 <node-name> <故障描述>}"
    REASON="${2:-GPU hardware failure}"
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    LOG_FILE="/var/log/gpu-emergency/$(date '+%Y%m%d')-${NODE}.log"
    mkdir -p "$(dirname "$LOG_FILE")"
    
    log() { echo "[$TIMESTAMP] $*" | tee -a "$LOG_FILE"; }
    
    log "========== GPU 故障应急流程启动 =========="
    log "故障节点: $NODE"
    log "故障描述: $REASON"
    
    # 阶段一:隔离节点
    log "[阶段1/4] 隔离故障节点"
    kubectl cordon "$NODE"
    kubectl label node "$NODE" gpu-status=faulty --overwrite
    log "节点已标记为不可调度"
    
    # 阶段二:迁移工作负载
    log "[阶段2/4] 迁移工作负载"
    # 获取节点上运行的 GPU Pod 列表(排空前记录,便于后续确认恢复)
    kubectl get pods --all-namespaces --field-selector "spec.nodeName=$NODE" -o wide | \
        grep -v "gpu-operator\|kube-system" | tee -a "$LOG_FILE"
    
    kubectl drain "$NODE" \
        --ignore-daemonsets \
        --delete-emptydir-data \
        --timeout=300s \
        --force 2>&1 | tee -a "$LOG_FILE"
    log "工作负载迁移完成"
    
    # 阶段三:收集诊断信息(远程执行)
    log "[阶段3/4] 收集诊断信息"
    ssh "$NODE" "nvidia-bug-report.sh" 2>/dev/null && \
        scp "$NODE":/tmp/nvidia-bug-report.log.gz "$(dirname "$LOG_FILE")/nvidia-bug-report-${NODE}.log.gz" || \
    log "警告:无法远程收集诊断信息,GPU 可能已完全不可用"
    
    # 阶段四:等待硬件更换
    log "[阶段4/4] 节点已隔离,等待硬件更换"
    log "更换完成后执行以下命令重新加入集群:"
    log "  1. ssh $NODE 'nvidia-smi'  # 验证新 GPU 正常"
    log "  2. ssh $NODE 'nvidia-smi -q -d ECC'  # 确认 ECC 无错误"
    log "  3. kubectl label node $NODE gpu-status=healthy --overwrite"
    log "  4. kubectl uncordon $NODE"
    log "  5. kubectl get pods -n gpu-operator -o wide | grep $NODE  # 确认 Operator 组件恢复"
    log "========== 应急流程完成,日志: $LOG_FILE =========="

    六、总结

    6.1 技术要点回顾

    • GPU Operator 是基石:通过 Operator 模式统一管理驱动、Container Toolkit、Device Plugin、DCGM 等组件,避免手动在每个节点上折腾驱动安装。Helm 一键部署,ClusterPolicy 统一配置,这是 GPU 集群从"能用"到"好管"的关键一步
    • 监控必须覆盖硬件健康:GPU 利用率只是冰山一角。温度、ECC 错误、PCIe 链路状态、功耗这些硬件指标才是预防性运维的核心。DCGM Exporter + Prometheus + Grafana 三件套是标配
    • MIG 是多租户的正确答案:时间片共享适合开发调试,但生产环境的推理服务必须用 MIG 做硬隔离。一块 A100 切成 7 个 MIG 实例,每个实例有独立的显存和计算单元,故障不互相传染
    • 驱动管理是持久战:版本统一、滚动升级、CUDA 兼容性矩阵,这三件事做好了,80% 的 GPU 集群问题都不会发生。灰度验证流程(dev → inference → training)不能省
    • 故障响应要有预案:GPU 掉卡、ECC 错误、驱动崩溃,每种故障的处理流程提前写好脚本。出事时执行脚本比翻文档快得多

    6.2 进阶学习方向

    • NVIDIA NIM 微服务:NVIDIA 推出的推理微服务框架,将模型部署封装为标准容器镜像,内置 TensorRT-LLM 优化。适合需要快速部署大语言模型推理服务的场景,省去手动优化模型的工作量

      • 学习资源:NVIDIA NIM 文档
      • 实践建议:先用 NIM 部署一个 Llama 模型,体验从镜像拉取到 API 可用的全流程
    • GPU 虚拟化(vGPU / SR-IOV):vGPU 通过 NVIDIA 虚拟化层将物理 GPU 切分为多个虚拟 GPU,支持 VM 级别的 GPU 共享。SR-IOV 则在硬件层面实现虚拟化,性能损耗更低。适合混合云和虚拟化平台场景

      • 学习资源:NVIDIA vGPU 文档
      • 实践建议:对比 MIG vs vGPU vs SR-IOV 三种方案在延迟和吞吐量上的差异
    • DPU 数据处理单元:NVIDIA BlueField DPU 将网络、存储、安全等基础设施功能从 CPU 卸载到专用硬件。在 GPU 集群中,DPU 可以加速 RDMA 通信、处理网络加密、运行基础设施容器,让 CPU 和 GPU 专注于计算任务

      • 学习资源:NVIDIA DOCA 开发框架
      • 实践建议:从 BlueField-2 的网络加速功能入手,体验 RDMA over Converged Ethernet
    • GPU 集群网络(InfiniBand / RoCE):大规模分布式训练的性能瓶颈往往在网络而非 GPU。InfiniBand 提供 400Gbps 低延迟互联,RoCE v2 则在以太网上实现 RDMA。选型取决于规模和预算

      • 学习资源:NVIDIA Networking 文档
      • 实践建议:搭建一个 2 节点 RoCE 环境,用 ib_write_bwib_read_lat 测试实际带宽和延迟

    6.3 参考资料

    • NVIDIA GPU Operator 官方文档 — 安装、配置、升级的权威参考
    • NVIDIA DCGM 文档 — GPU 监控和诊断的核心工具
    • NVIDIA Driver CUDA 兼容性矩阵 — 驱动与 CUDA Toolkit 版本对应关系
    • Kubernetes Device Plugin 框架 — 理解 GPU 如何被 K8s 调度
    • NVIDIA MIG 用户指南 — Multi-Instance GPU 配置详解
    • Xid 错误码参考 — GPU 硬件错误码完整列表和处理建议

    附录

    A. 命令速查表

    # ==================== nvidia-smi 常用命令 ====================
    
    nvidia-smi                                  # 基础状态概览
    nvidia-smi -L                               # 列出所有 GPU 及 UUID
    nvidia-smi -q                               # 完整详细信息
    nvidia-smi -q -d PERFORMANCE               # 性能状态和降频原因
    nvidia-smi -q -d ECC                         # ECC 错误详情
    nvidia-smi -q -d TEMPERATURE               # 温度和阈值
    nvidia-smi -q -d POWER                       # 功耗和限制
    nvidia-smi -q -d CLOCK                       # 时钟频率
    nvidia-smi -q -d PIDS                        # GPU 上运行的进程
    nvidia-smi --query-gpu=index,name,temperature.gpu,utilization.gpu,memory.used,memory.total --format=csv  # 自定义查询
    nvidia-smi -i 0 -pl 300                      # 设置 GPU 0 功耗限制为 300W
    nvidia-smi -i 0 -r                           # 重置 GPU 0
    nvidia-smi -i 0 --reset-ecc-errors=volatile  # 重置 ECC volatile 计数
    nvidia-smi -pm 1                             # 启用持久模式(减少首次调用延迟)
    nvidia-smi topo -m                            # GPU 拓扑(NVLink/PCIe 连接关系)
    nvidia-smi nvlink -s                         # NVLink 状态
    nvidia-smi mig -lgip                         # 列出可用的 MIG Profile
    nvidia-smi mig -lgi                          # 列出已创建的 GPU Instance
    nvidia-smi mig -lci                          # 列出已创建的 Compute Instance
    nvidia-smi dmon -s pucvmet -d 2             # 持续监控(每 2 秒刷新)
    sudo nvidia-bug-report.sh                    # 生成完整诊断报告
    
    # ==================== GPU Operator kubectl 命令 ====================
    
    kubectl get pods -n gpu-operator -o wide              # 查看 Operator 所有组件状态
    kubectl get clusterpolicy -o yaml                      # 查看 ClusterPolicy 配置
    kubectl describe node <node> | grep -A20 "Allocatable" # 查看节点可分配 GPU 数量
    kubectl describe node <node> | grep -A5 "nvidia.com"   # 查看节点 GPU 资源和标签
    kubectl get nodes -l nvidia.com/gpu.present=true        # 列出所有 GPU 节点
    kubectl get nodes -l nvidia.com/mig.strategy=mixed     # 列出启用 MIG 的节点
    kubectl logs -n gpu-operator -l app=nvidia-driver-daemonset --tail=50           # 驱动容器日志
    kubectl logs -n gpu-operator -l app=nvidia-device-plugin-daemonset --tail=50    # Device Plugin 日志
    kubectl logs -n gpu-operator -l app=nvidia-dcgm-exporter --tail=50              # DCGM Exporter 日志
    kubectl get events -n gpu-operator --sort-by='.lastTimestamp' | tail -20         # 最近事件
    kubectl get resourcequota --all-namespaces | grep gpu                           # 查看 GPU 配额

    B. 配置参数详解

    GPU Operator Helm Values 关键参数

    参数路径 默认值 说明
    driver.enabled true 是否由 Operator 管理驱动安装(预装驱动时设为 false)
    driver.version 随 Operator 版本 锁定驱动版本号,如 535.183.01
    driver.rdma.enabled false 启用 RDMA/GPUDirect 支持(InfiniBand 环境必开)
    toolkit.enabled true 安装 NVIDIA Container Toolkit
    devicePlugin.enabled true 部署 K8s Device Plugin
    devicePlugin.config.name "" Device Plugin 配置 ConfigMap 名称(MIG/时间片配置)
    dcgmExporter.enabled true 部署 DCGM Exporter 监控组件
    dcgmExporter.serviceMonitor.enabled false 创建 Prometheus ServiceMonitor(用 Prometheus Operator 时开启)
    mig.strategy none MIG 策略:none/single/mixed
    gfd.enabled true 部署 GPU Feature Discovery(自动标记节点 GPU 信息)
    nodeStatusExporter.enabled false 节点状态导出器(v24.6+ 新增)
    sandboxDevicePlugin.enabled false 沙箱设备插件(vGPU 场景使用)

    DCGM Exporter 常用指标字段

    指标名称 类型 说明
    DCGM_FI_DEV_GPU_UTIL Gauge GPU 计算利用率(%)
    DCGM_FI_DEV_MEM_COPY_UTIL Gauge 显存带宽利用率(%)
    DCGM_FI_DEV_FB_USED Gauge 已使用显存(MiB)
    DCGM_FI_DEV_FB_FREE Gauge 空闲显存(MiB)
    DCGM_FI_DEV_GPU_TEMP Gauge GPU 核心温度(°C)
    DCGM_FI_DEV_MEMORY_TEMP Gauge 显存温度(°C)
    DCGM_FI_DEV_POWER_USAGE Gauge 实时功耗(W)
    DCGM_FI_DEV_POWER_LIMIT Gauge 功耗限制(W)
    DCGM_FI_DEV_PCIE_TX_THROUGHPUT Gauge PCIe 发送吞吐量(KB/s)
    DCGM_FI_DEV_PCIE_RX_THROUGHPUT Gauge PCIe 接收吞吐量(KB/s)
    DCGM_FI_DEV_ECC_SBE_VOL_TOTAL Counter 可纠正 ECC 错误计数(volatile)
    DCGM_FI_DEV_ECC_DBE_VOL_TOTAL Counter 不可纠正 ECC 错误计数(volatile)
    DCGM_FI_DEV_SM_CLOCK Gauge SM 时钟频率(MHz)
    DCGM_FI_DEV_MEM_CLOCK Gauge 显存时钟频率(MHz)
    DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL Gauge NVLink 总带宽(MB/s)
    DCGM_FI_DEV_XID_ERRORS Gauge 最近的 Xid 错误码

    C. 术语表

    术语 英文 解释
    GPU Operator GPU Operator NVIDIA 开发的 K8s Operator,自动化管理 GPU 节点上的驱动、运行时、监控等组件的生命周期
    DCGM Data Center GPU Manager NVIDIA 数据中心 GPU 管理工具,提供健康监控、诊断、策略管理等功能
    MIG Multi-Instance GPU 多实例 GPU 技术,将一块物理 GPU 切分为多个独立实例,每个实例有隔离的显存和计算资源
    Xid 错误 Xid Error NVIDIA GPU 驱动层面的错误码体系,每个 Xid 编号对应特定的硬件或软件故障类型
    ECC Error Correcting Code 错误纠正码,GPU 显存的硬件级错误检测和纠正机制
    NVLink NVLink NVIDIA 专有的高速 GPU 互联总线,带宽远高于 PCIe,用于多卡并行通信
    Device Plugin Device Plugin K8s 设备插件框架,使 GPU 等硬件资源能被 K8s 调度器识别和分配
    GFD GPU Feature Discovery GPU 特征发现组件,自动为 K8s 节点添加 GPU 型号、驱动版本、MIG 配置等标签
    TDP Thermal Design Power 热设计功耗,GPU 在满载时的最大功耗设计值
    Gang Scheduling Gang Scheduling 组调度,确保分布式训练任务的所有 Pod 同时获得资源并同时启动
    Bin Packing Bin Packing 装箱调度策略,尽量将 Pod 集中调度到少数节点,提高资源利用率
    RoCE RDMA over Converged Ethernet 在以太网上实现 RDMA 远程直接内存访问的协议,是 InfiniBand 的低成本替代方案
    DPU Data Processing Unit 数据处理单元,专用于网络、存储、安全等基础设施任务的可编程处理器
    SR-IOV Single Root I/O Virtualization 单根 IO 虚拟化,允许一个 PCIe 物理设备呈现为多个虚拟设备,实现硬件级虚拟化



    上一篇:《宝可梦TCGP》上线一年营收12亿美元,解析全球第一IP的长青秘诀
    下一篇:Claude Code 如何选工具?2430次测试揭示其技术选型逻辑
    您需要登录后才可以回帖 登录 | 立即注册

    手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

    GMT+8, 2026-3-1 00:42 , Processed in 0.494363 second(s), 43 queries , Gzip On.

    Powered by Discuz! X3.5

    © 2025-2026 云栈社区.

    快速回复 返回顶部 返回列表