一、概述
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-smi 报 NVML: 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 memory 但 nvidia-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:"
解决方案:
- 尝试 GPU Reset:
sudo nvidia-smi -i <gpu_id> -r
- 如果 Reset 失败,需要重启节点
- 重启后仍然复现,检查 PCIe 物理连接,必要时更换 GPU 或 Riser Card
- 反复出现 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
解决方案:
- 单次 Uncorrectable 错误:记录并观察,可能是宇宙射线等偶发因素
- 多次 Uncorrectable 错误:立即将节点标记为不可调度,迁移负载
- 联系 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_bw 和 ib_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 物理设备呈现为多个虚拟设备,实现硬件级虚拟化 |