跳转到内容

HAMI 面试题

30 道题
分类
Kubernetes
子分类
gpu
题目数
30 道
已阅读 0 / 30 题
1 HAMI 的核心定位是什么?它与 GPU Operator、Volcano、Time-Slicing 分别在什么层面解决问题?

答案:

HAMI 是 GPU 共享与虚拟化中间件,在 Kubernetes 中实现单 GPU 被多个容器共享,并提供显存与算力维度的隔离。HAMI 位于设备插件层与调度层之间,通过 LD_PRELOAD 注入 CUDA 库拦截 API 调用实现资源限制,同时以 Scheduler Extender 方式参与 Pod 调度决策。

分层对比:

组件作用层面核心能力典型场景
HAMICUDA API 拦截 + 调度扩展显存/算力隔离,单卡共享多推理服务共享 GPU
GPU Operator驱动与组件生命周期管理NVIDIA 驱动、container-toolkit、device-plugin 自动化部署GPU 节点初始化与运维
Volcano批量调度与任务编排Gang Scheduling、Queue、公平调度分布式训练任务调度
Time-SlicingGPU 时分复用基于时间片的 GPU 共享轻量级 GPU 复用

HAMI 与 GPU Operator 互补:GPU Operator 管理 GPU 基础软件栈,HAMI 在此之上提供细粒度资源共享。HAMI 与 Volcano 可协同:Volcano 负责任务排队与 Gang Scheduling,HAMI 负责单卡内的资源切分与隔离。HAMI 与 Time-Slicing 的本质区别:HAMI 提供显存硬隔离 + 算力软隔离,Time-Slicing 仅做时间片轮转不提供资源保证。

2 HAMI 的显存隔离机制是如何实现的?

答案:

HAMI 通过 LD_PRELOAD 机制在容器启动时注入自定义 CUDA 库(libvgpu.so),劫持 CUDA 显存分配相关 API(cudaMalloc、cudaFree、cuMemAlloc 等),在应用请求 GPU 显存时检查是否超过容器声明的显存限制,若超限则返回分配失败,从而实现显存的硬隔离。

实现链路:

graph TD
    A[Container 启动] --> B["LD_PRELOAD=libvgpu.so"]
    B --> C["拦截 cudaMalloc(size)"]
    C --> D["检查 current_used + size > hami.io/gpu-memory"]
    D -->|是| E["返回 cudaErrorMemoryAllocation - OOM"]
    D -->|否| F["透传到真实 CUDA driver 分配"]

关键配置文件(device-plugin 侧):

# HAMI device plugin 配置
devices:
  nvidia:
    enabled: true
    resourceCountName: hami.io/gpu
    resourceMemoryName: hami.io/gpu-memory
    resourceMemoryPercentageName: hami.io/gpu-memory-percentage
    resourceCoreName: hami.io/gpu-core

Pod 侧声明:

resources:
  limits:
    hami.io/gpu: 1          # 请求 1 张 GPU 卡
    hami.io/gpu-memory: 4   # 限制显存 4GB
    hami.io/gpu-core: 30    # 限制 30% 算力

显存限制在进程启动即生效,libvgpu.so 维护每个进程的显存用量计数器,实时拦截并校验每次显存分配请求。

3 HAMI 的算力隔离机制是如何实现的?

答案:

HAMI 的算力隔离基于 GPU 时间片控制,通过在 libvgpu.so 中劫持 CUDA Kernel Launch API(cudaLaunchKernel、cuLaunchKernel 等),在 Kernel 执行前插入 sleep 或忙等待来控制 GPU 核心利用率占比。

控制模型:

时间窗口(默认 1 秒)
  ├── 有效计算时间 = 窗口 × (core_percentage / 100)
  └── 强制空闲时间 = 窗口 × (1 - core_percentage / 100)

CPU 利用率控制实现:

// libvgpu.so 中的伪代码逻辑
void intercept_kernel_launch() {
    uint64_t elapsed = now() - window_start;
    uint64_t allowed_time = time_window * core_percent / 100;

    if (elapsed >= time_window) {
        // 新窗口开启
        window_start = now();
        busy_time = 0;
    }

    if (busy_time >= allowed_time) {
        // 超额,休眠至下一个窗口
        usleep((time_window - elapsed) * 1000);
        window_start = now();
        busy_time = 0;
    }

    real_kernel_launch();
    busy_time += kernel_exec_time;
}

关键参数:

参数默认值说明
time_window1000ms算力统计窗口
core_percent100容器声明的算力百分比
utilization_penaltytrue是否启用超限惩罚

算力隔离为软限制(soft limit),不影响 Kernel 正确性,仅限制吞吐。在 GPU 空闲时容器可能获得超过声明的算力,繁忙时则严格限制在声明区间内。

4 HAMI 的设备插件是如何向 kubelet 注册并上报虚拟化 GPU 资源的?

答案:

HAMI device plugin 实现了 Kubernetes Device Plugin API(v1beta1),在 GPU 节点上以 DaemonSet 形式运行,向 kubelet 的 /var/lib/kubelet/device-plugins/ 目录注册 Unix Socket,并通过 ListAndWatch gRPC 接口持续上报虚拟化后的 GPU 资源。

注册流程:

graph TD
    A[HAMI Device Plugin Pod] --> B["1. 发现物理 GPU - nvml"]
    B --> B1["读取 GPU 型号、显存总量、SM 数量"]
    A --> C["2. 注册 Device Plugin Socket"]
    C --> C1["/var/lib/kubelet/device-plugins/hami.sock"]
    A --> D["3. kubelet 调用 ListAndWatch"]
    D --> D1["返回虚拟化 Devices 列表"]
    D1 --> D1a["hami.io/gpu - GPU 卡数"]
    D1 --> D1b["hami.io/gpu-memory - 显存 MB"]
    D1 --> D1c["hami.io/gpu-core - 算力百分比"]
    D1 --> D1d["hami.io/gpu-memory-percentage"]
    A --> E["4. kubelet 注册为 Extended Resource"]
    E --> E1["Node.Status.Capacity: hami.io/gpu-memory: 16384"]
    A --> F["5. Allocate 回调"]
    F --> F1["容器创建前,挂载 libvgpu.so 并通过环境变量注入配置"]

上报资源示例:

# kubectl describe node gpu-node-01
Capacity:
  hami.io/gpu:              8
  hami.io/gpu-core:         800
  hami.io/gpu-memory:       131072   # 单位 MiB,8×16GB
  hami.io/gpu-memory-percentage: 800
  nvidia.com/gpu:           8
Allocatable:
  hami.io/gpu:              8
  hami.io/gpu-core:         800
  hami.io/gpu-memory:       126848
  hami.io/gpu-memory-percentage: 800

每个物理 GPU 被抽象为 100 个算力单位(hami.io/gpu-core: 100)和其全部显存(hami.io/gpu-memory)。

5 HAMI-scheduler 的调度扩展原理是什么?

答案:

HAMI-scheduler 以 Kubernetes Scheduler Extender 模式运行,部署为独立 Service,在 Kube-scheduler 配置中注册为外部扩展器,对 GPU 资源的 Pod 执行 Filter 和 Prioritize 阶段的二次调度逻辑。

架构流程:

graph TD
    A[Kube-scheduler] --> B["默认调度阶段 - Filter / Score / Reserve"]
    A --> C["遇到 hami.io/* 资源的 Pod"]
    C --> D["HTTP POST → HAMI-scheduler Service"]
    D --> E["Filter: 检查节点 hami 资源是否满足 Pod 请求"]
    E --> E1["细粒度到单卡级别:该卡上的 gpu-memory 和 gpu-core 剩余量是否满足 Pod 声明的 limit"]
    D --> F["Prioritize: 优先将 Pod 调度到已有分配的 GPU 卡上"]
    F --> F1["减少 GPU 碎片化"]
    A --> G["Bind: 调度成功的 Pod 绑定到节点"]

Kube-scheduler 配置示例:

apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
extenders:
  - urlPrefix: "http://hami-scheduler.kube-system:31993/scheduler"
    filterVerb: filter
    prioritizeVerb: prioritize
    weight: 20
    enableHTTPS: false
    managedResources:
      - name: hami.io/gpu
      - name: hami.io/gpu-memory
      - name: hami.io/gpu-core
    ignorable: false

HAMI-scheduler 维护集群内每张 GPU 卡的实时分配状态(分配了哪些容器、剩余显存与算力),在 Filter 阶段排除无法满足 Pod 资源需求的节点,在 Prioritize 阶段通过装箱策略优先填满已部分使用的 GPU 卡。

6 HAMI 的 GPU 共享模式是如何让多个容器共享同一张 GPU 的?

答案:

HAMI 的核心共享模式是将一张物理 GPU 拆分为多个虚拟 GPU(vGPU),每个 vGPU 拥有独立的显存限额与算力限额,通过环境变量和 LD_PRELOAD 注入的方式在容器内强制执行限制,从而允许多个容器同时使用同一张 GPU。

共享模型示意:

graph TD
    A["Physical GPU: NVIDIA A100 80GB"] --> B["Container A: hami.io/gpu-memory: 30GB | hami.io/gpu-core: 40"]
    A --> C["Container B: hami.io/gpu-memory: 25GB | hami.io/gpu-core: 35"]
    A --> D["Container C: hami.io/gpu-memory: 20GB | hami.io/gpu-core: 25"]
    B --> B1["Pod: inference-service-v1"]
    C --> C1["Pod: inference-service-v2"]
    D --> D1["Pod: dev-notebook"]

Pod 声明示例:

apiVersion: v1
kind: Pod
metadata:
  name: gpu-shared-pod
spec:
  containers:
  - name: app
    image: nvidia/cuda:12.1.0-runtime-ubuntu22.04
    resources:
      limits:
        hami.io/gpu: 1
        hami.io/gpu-memory: 8   # 8GB 显存
        hami.io/gpu-core: 25    # 25% 算力

Device Plugin 在 Allocate 阶段的行为:

{
  "envs": {
    "LD_PRELOAD": "/usr/local/hami/libvgpu.so",
    "CUDA_DEVICE_MEMORY_LIMIT": "8589934592",
    "CUDA_DEVICE_SM_LIMIT": "25",
    "CUDA_DEVICE_MEMORY_SHARED_CACHE": "/tmp/hami-cache"
  },
  "mounts": [
    {
      "containerPath": "/usr/local/hami/libvgpu.so",
      "hostPath": "/usr/local/hami/libvgpu.so"
    }
  ]
}

每个容器看到的仍然是完整的物理 GPU(nvidia-smi 显示全部显存),但 libvgpu.so 在 API 层面拦截并限制实际可用资源,每个容器的限制彼此独立、互不干扰。

7 HAMI 的 Helm 安装包含哪些核心组件与参数?

答案:

HAMI 通过 Helm Chart 部署,核心组件包括:HAMI Device Plugin(DaemonSet)、HAMI Scheduler(Deployment)、HAMI Webhook(可选,用于自动注入环境变量)。

核心 Helm 参数:

helm repo add hami-charts https://project-hami.github.io/HAMi/charts
helm install hami hami-charts/hami \
  --namespace kube-system \
  --set devicePlugin.image.tag=v2.4.0 \
  --set scheduler.kubeScheduler.image.tag=v2.4.0 \
  --set devicePlugin.devices.nvidia.resourceCountName=hami.io/gpu \
  --set devicePlugin.devices.nvidia.resourceMemoryName=hami.io/gpu-memory \
  --set devicePlugin.devices.nvidia.resourceCoreName=hami.io/gpu-core \
  --set scheduler.defaultMem=0 \
  --set scheduler.defaultCores=0 \
  --set scheduler.defaultGPUNum=1

核心组件清单:

组件类型功能
hami-device-pluginDaemonSet注册 GPU 资源、上报虚拟化设备、挂载 libvgpu.so
hami-schedulerDeploymentScheduler Extender,细粒度 GPU 资源调度
hami-webhookDeployment(可选)Mutating Webhook,自动注入 GPU 环境变量
hami-metricsSidecar(可选)暴露 GPU 使用指标给 Prometheus

关键配置参数说明:

# values.yaml 核心配置
devicePlugin:
  devices:
    nvidia:
      enabled: true
      resourceCountName: hami.io/gpu
      resourceMemoryName: hami.io/gpu-memory
      resourceCoreName: hami.io/gpu-core
      resourceMemoryPercentageName: hami.io/gpu-memory-percentage
  nodeSelector: {}         # GPU 节点选择器
  tolerations: []          # 容忍策略

scheduler:
  enabled: true
  schedulerName: hami-scheduler
  defaultMem: 0            # 默认显存限制(0=容器未声明时不限制)
  defaultCores: 0          # 默认算力限制
  defaultGPUNum: 1         # 默认 GPU 数量
8 HAMI 如何实现 GPU 显存限制的精确控制?

答案:

HAMI 显存限制依赖于 CUDA 显存分配 API 的全量拦截。libvgpu.so 在进程初始化时读取环境变量 CUDA_DEVICE_MEMORY_LIMIT(单位为字节),在每次 cudaMalloc / cuMemAlloc / cudaMallocManaged 等显存分配调用时执行限额校验。

拦截点覆盖:

CUDA API拦截方式限制策略
cudaMallocLD_PRELOAD 符号覆盖总分配量 + 本次请求 <= limit
cudaMallocManagedLD_PRELOAD 符号覆盖同上
cuMemAllocLD_PRELOAD 符号覆盖同上
cudaMallocPitchLD_PRELOAD 符号覆盖同上
cudaMalloc3DLD_PRELOAD 符号覆盖同上
cudaFreeLD_PRELOAD 符号覆盖更新已用量计数器

显存限制精度:

# 容器内环境变量(由 device plugin Allocate 阶段注入)
CUDA_DEVICE_MEMORY_LIMIT=8589934592    # 8GB = 8 × 1024³

# 应用程序视角
# cudaMalloc(4GB)  → 成功,已用 4GB / 8GB
# cudaMalloc(5GB)  → 失败,返回 cudaErrorMemoryAllocation
# cudaFree(4GB)    → 成功,已用 0GB / 8GB

HAMI 的显存限制为 硬限制,应用程序在超限时收到的错误码与 GPU 物理 OOM 一致(cudaErrorMemoryAllocation),应用层可按标准 CUDA 错误处理逻辑响应。libvgpu.so 不在显存层面做预留或超分(overcommit),声明的限制即为硬上限。

9 HAMI 的算力利用率限制如何配置?

答案:

HAMI 算力限制通过 hami.io/gpu-core 资源声明,每个物理 GPU 被抽象为 100 个算力单位。例如声明 hami.io/gpu-core: 30 即限制该容器占用 GPU 总 SM 时间的 30%。

Pod 配置:

apiVersion: v1
kind: Pod
metadata:
  name: gpu-limited-pod
spec:
  containers:
  - name: training
    image: nvidia/cuda:12.1.0-devel-ubuntu22.04
    resources:
      limits:
        hami.io/gpu: 1
        hami.io/gpu-memory: 16   # 16GB 显存
        hami.io/gpu-core: 50     # 50% 算力

算力配置策略对比:

配置方式场景示例
固定百分比明确知道工作负载的算力需求hami.io/gpu-core: 30
不限制开发测试环境不声明 gpu-core
动态配置HAMI Webhook 自动注入按 namespace annotation 注入默认值
优先级继承生产环境高优先级 Pod 获取更高算力上限

运行时行为:

算力限制 = 30(30% GPU SM 时间)

时间轴(每 1000ms 窗口):
[==30% 有效计算==|______70% 空闲______|==30% 有效计算==|...]

在 GPU 空闲时,容器可能获得超过 30% 的实际算力(soft limit 特性);当同一 GPU 上的其他容器也有负载时,libvgpu.so 的节流机制会将容器 SM 使用率限制在 30% 以内。

10 HAMI 与 nvidia-device-plugin 如何兼容工作?

答案:

HAMI 与 nvidia-device-plugin(NVIDIA 官方设备插件)共存于同一集群,HAMI 通过配置仅接管 GPU 节点的虚拟化资源上报,nvidia-device-plugin 仍可继续上报整卡资源(nvidia.com/gpu),两者通过不同的 Extended Resource 名称区分。

共存架构:

graph TD
    A["Node: GPU Node"] --> B["nvidia-device-plugin"]
    A --> C["HAMI device-plugin"]
    B --> B1["上报: nvidia.com/gpu - 整卡,用于非共享场景"]
    C --> C1["上报: hami.io/gpu, hami.io/gpu-memory, hami.io/gpu-core - 虚拟化,用于共享场景"]

HARM 配置文件中的共存设置:

# HAMI values.yaml
devicePlugin:
  devices:
    nvidia:
      enabled: true
      # 关键:不与 nvidia-device-plugin 争夺 nvidia.com/gpu
      resourceCountName: hami.io/gpu
      # 保留原始 nvidia.com/gpu 资源给非 HAMI 的 Pod
      disableNvidiaResource: false

使用场景分流:

Pod 类型资源声明插件处理
整卡独占 Podnvidia.com/gpu: 1nvidia-device-plugin
GPU 共享 Podhami.io/gpu: 1 + hami.io/gpu-memory: 8HAMI device-plugin

注意事项:

HAMI device plugin 不应接管 nvidia.com/gpu 资源的注册(通过 disableNvidiaResource 或资源名配置控制),避免与 nvidia-device-plugin 冲突。在同一节点上,物理 GPU 的整卡资源与虚拟化资源互斥:分配给 HAMI Pod 的 GPU 卡上的 nvidia.com/gpu 资源应从节点 Capacity 中扣除对应数量。

11 HAMI 对 CUDA 应用的兼容性如何?哪些 CUDA 特性可能受限?

答案:

HAMI 通过 LD_PRELOAD 劫持 CUDA 运行时 API,兼容主流 CUDA 版本(CUDA 10.0 - 12.x),涵盖 PyTorch、TensorFlow、ONNX Runtime、TensorRT 等主流深度学习框架。限制主要出现在直接调用 CUDA Driver API 的场景或涉及 GPU 间通信的高级特性。

兼容性矩阵:

特性兼容状态说明
cudaMalloc / cudaFree完全兼容核心显存分配 API
cudaLaunchKernel完全兼容核心 Kernel 启动 API
cudaMemcpy (Host-Device)完全兼容不拦截,透传
cuBLAS / cuDNN完全兼容基于上述 API,间接兼容
NCCL(单卡)兼容不涉及 P2P / RDMA 时
NCCL(多卡跨节点)兼容通信不走 HAMI
NCCL(同节点 P2P)受限共享 GPU 场景下 P2P 受限
CUDA IPC不支持共享 GPU 下进程间显存共享受限
MPS(Multi-Process Service)不支持与 HAMI 共享模式冲突
CUDA Graph部分兼容静态图捕获时算力控制可能不精确
GPU Direct RDMA依赖硬件HAMI 不介入,取决于 InfiniBand 配置

框架兼容性验证命令:

# 验证 PyTorch 兼容性
kubectl run torch-test --image=pytorch/pytorch:2.0.1-cuda11.7-cudnn8-runtime \
  --restart=Never --rm -it -- \
  python -c "import torch; print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0))"

# 验证 TensorFlow 兼容性
kubectl run tf-test --image=tensorflow/tensorflow:2.13.0-gpu \
  --restart=Never --rm -it -- \
  python -c "import tensorflow as tf; print(tf.config.list_physical_devices('GPU'))"

典型受限场景(CUDA IPC):

涉及 cudaIpcGetMemHandle / cudaIpcOpenMemHandle 的程序在同一 GPU 的多个 HAMI 容器间无法共享显存指针,因为每个容器的虚拟地址空间被 libvgpu.so 隔离。

12 HAMI 的资源上报格式有哪些?各自含义是什么?

答案:

HAMI 定义了一套 Extended Resource 命名体系,以 hami.io/ 为前缀,覆盖 GPU 卡数、显存、算力三个维度。

资源类型总览:

资源名单位含义示例值
hami.io/gpu虚拟 GPU 卡数1
hami.io/gpu-memoryMiB显存限额8192(8GB)
hami.io/gpu-core%算力百分比(0-100/卡)30
hami.io/gpu-memory-percentage%显存百分比25

节点 Capacity 视角:

物理 GPU: 8 × NVIDIA A100 80GB

节点上报:
  hami.io/gpu:                    800     # 8 张 × 100 = 800 虚拟卡
  hami.io/gpu-memory:             655360  # 8 × 80GB = 640GB = 655360 MiB
  hami.io/gpu-core:               800     # 8 × 100 = 800 算力单位
  hami.io/gpu-memory-percentage:  800     # 8 × 100 = 800 百分比单位

Pod 层面声明:

# 声明方式一:显存绝对值
resources:
  limits:
    hami.io/gpu: 1
    hami.io/gpu-memory: 4096  # 4GB

# 声明方式二:显存百分比
resources:
  limits:
    hami.io/gpu: 1
    hami.io/gpu-memory-percentage: 25  # 25% 的总显存

# 声明方式三:算力限制
resources:
  limits:
    hami.io/gpu: 1
    hami.io/gpu-core: 50  # 50% 算力

hami.io/gpu-memoryhami.io/gpu-memory-percentage 两种声明方式二选一,device plugin 在 Allocate 阶段将其统一转换为字节数注入环境变量。hami.io/gpu-corehami.io/gpu-memory 的 Sum 必须与 hami.io/gpu 保持逻辑一致(每张虚拟 GPU 卡 = 100 算力 + 全部物理卡显存)。

13 HAMI 如何与 Volcano 调度器集成?

答案:

HAMI 与 Volcano 的集成通过 Volcano 的 Device Plugin 机制 + HAMI-scheduler 作为 Volcano 的调度插件实现。Volcano 负责批量任务编排与队列管理,HAMI 负责 GPU 资源的细粒度分配。

集成架构:

graph TD
    A[Volcano Scheduler] --> B["Session - 调度会话"]
    B --> B1["Queue / JobOrder / TaskOrder 排序"]
    B --> B2["Gang Scheduling 检查"]
    B --> C["HAMI Device Plugin - Volcano 侧"]
    C --> D["调用 HAMI-scheduler API"]
    D --> D1["查询节点 GPU 卡剩余资源 - 显存 + 算力"]
    D --> D2["决策 Pod 分配到哪张物理 GPU"]
    A --> E["Bind: 分配到具体节点"]

Volcano Job 声明 HAMI 资源:

apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: distributed-training
spec:
  minAvailable: 4
  schedulerName: volcano
  queue: gpu-queue
  tasks:
  - replicas: 4
    name: worker
    template:
      spec:
        containers:
        - name: pytorch
          image: pytorch/pytorch:2.0.1-cuda11.7-cudnn8-devel
          resources:
            limits:
              hami.io/gpu: 1
              hami.io/gpu-memory: 16
              hami.io/gpu-core: 50

关键配置:

# HAMI 启用 Volcano 集成
scheduler:
  enabled: true
  volcanoEnabled: true
  # Scheduler Extender URL 同时注册到 Kube-scheduler 和 Volcano

集成后 Volcano 的 Gang Scheduling 确保分布式训练的所有 Worker 同时获得 GPU 资源,HAMI 在此基础上确保每个 Worker 获得指定显存与算力。

14 HAMI 如何处理 GPU 拓扑感知调度?

答案:

HAMI 的拓扑感知调度基于 NVML Topology API 获取节点 GPU 拓扑信息(PCIe 拓扑、NVLink 连接关系),在调度决策中优先将需要高带宽通信的 Pod 调度到 NVLink 直接连接的 GPU 上。

拓扑感知调度策略:

graph TD
    A["Node: 8 × A100"] --> B["NVSwitch 互联拓扑"]
    B --> B1["GPU0 ←──NVLink 600GB/s──→ GPU1"]
    B --> B2["GPU0 ←──NVLink 600GB/s──→ GPU2"]
    B --> B3["GPU0 ←── PCIe Switch ──→ GPU4 - 较低带宽"]
    A --> C["HAMI 调度决策"]
    C --> C1["任务请求 2 卡 → 优先分配 GPU0 + GPU1 - NVLink 直连"]
    C --> C2["任务请求 2 卡 → 若无 NVLink 组合,退而求其次分配 PCIe Switch 内 GPU"]

Pod 声明拓扑偏好:

apiVersion: v1
kind: Pod
metadata:
  name: nvlink-training
  annotations:
    hami.io/gpu-topology-policy: "nvlink-first"  # 优先 NVLink 拓扑
spec:
  containers:
  - name: training
    resources:
      limits:
        hami.io/gpu: 2
        hami.io/gpu-memory: 32

拓扑策略选项:

策略行为
nvlink-first优先选择 NVLink 直连的 GPU 对
nvlink-only仅选择 NVLink 直连的 GPU(无满足条件的节点时调度失败)
balanced均匀分布到不同 NUMA / PCIe 域(避免竞争)
none不做拓扑感知(默认)

拓扑信息由 device plugin 在启动时通过 NVML 采集并上报给 scheduler,scheduler 维护 GPU 拓扑图(graph),在 Filter 阶段根据拓扑策略过滤节点,在 Score 阶段为满足偏好拓扑的节点赋予更高分数。

15 HAMI 提供哪些监控指标?如何与 Prometheus 集成?

答案:

HAMI 通过内嵌的 metrics sidecar 暴露 GPU 使用率、显存用量、算力占用等指标,格式兼容 Prometheus text format,可由 Prometheus Operator 的 ServiceMonitor 或 PodMonitor 自动抓取。

核心指标:

指标名类型含义标签
hami_gpu_memory_used_bytesGauge容器 GPU 显存使用量pod, namespace, gpu_id
hami_gpu_memory_limit_bytesGauge容器 GPU 显存限额pod, namespace, gpu_id
hami_gpu_core_utilizationGaugeGPU 算力利用率(%)pod, namespace, gpu_id
hami_gpu_core_limitGauge容器算力限额pod, namespace, gpu_id
hami_gpu_utilizationGauge物理 GPU 总利用率gpu_id, node
hami_gpu_memory_total_bytesGauge物理 GPU 总显存gpu_id, node
hami_gpu_shared_countGauge物理 GPU 上共享容器数gpu_id, node
hami_gpu_oom_events_totalCounter显存 OOM 事件数pod, namespace, gpu_id

Prometheus 集成配置:

# PodMonitor 示例
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: hami-metrics
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: hami-device-plugin
  podMetricsEndpoints:
  - port: metrics
    interval: 30s
    path: /metrics

常用 PromQL 查询:

# 每张物理 GPU 上的容器数
hami_gpu_shared_count

# 容器显存使用率
hami_gpu_memory_used_bytes / hami_gpu_memory_limit_bytes * 100

# 物理 GPU 总显存使用率
sum by (gpu_id) (hami_gpu_memory_used_bytes) / hami_gpu_memory_total_bytes * 100

# GPU 算力超限检测(容器算力利用率超过其限额 120%)
hami_gpu_core_utilization > hami_gpu_core_limit * 1.2

Grafana 仪表盘可按 GPU 维度(总览)、Pod 维度(单容器视角)、节点维度(集群视图)三种层级组织面板,分别监控碎片化程度、单容器 SLA 和集群利用率趋势。

16 HAMI 在生产环境中有哪些最佳实践?

答案:

资源粒度控制:

# 推荐的最小资源粒度(A100 80GB)
# 显存: 4GB 起,以 2GB 为步长
# 算力: 10% 起,以 5% 为步长
resources:
  limits:
    hami.io/gpu: 1
    hami.io/gpu-memory: 8   # 8GB
    hami.io/gpu-core: 20    # 20%

节点分组与 GPU 型号选择:

# 使用 nodeSelector 将不同型号 GPU 分组
apiVersion: v1
kind: Pod
spec:
  nodeSelector:
    hami.io/gpu-model: "a100-80gb"
  containers:
  - resources:
      limits:
        hami.io/gpu: 1

设置默认资源限制(防止未声明的 Pod 占用整卡):

# HAMI Helm values
scheduler:
  defaultMem: 4096      # 默认显存 4GB
  defaultCores: 10      # 默认算力 10%
  defaultGPUNum: 1

资源超分配监控告警:

# Prometheus 告警规则
groups:
- name: hami
  rules:
  - alert: HAMIGPUOversubscribed
    expr: hami_gpu_shared_count > 8
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "GPU XQOPEN $labels.gpu_id XQCLOSE 共享容器数超过 8"

  - alert: HAMIGPUMemoryHigh
    expr: sum by (gpu_id) (hami_gpu_memory_used_bytes) / hami_gpu_memory_total_bytes > 0.95
    for: 1m
    labels:
      severity: critical
    annotations:
      summary: "GPU XQOPEN $labels.gpu_id XQCLOSE 显存使用率超过 95%"

网卡与 NUMA 亲和性:

# 训练任务绑定高速网卡所在 NUMA 域的 GPU
spec:
  containers:
  - resources:
      limits:
        hami.io/gpu: 4
    volumeMounts:
    - name: nvidia-peermem
      mountPath: /dev/infiniband

命名空间级别资源配额:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: gpu-quota
  namespace: ml-team
spec:
  hard:
    hami.io/gpu-memory: 160   # 160GB 总显存
    hami.io/gpu-core: 200     # 200% 总算力(2 张卡)
17 HAMI vs MIG vs Time-Slicing 三者如何对比?各自的适用场景是什么?

答案:

维度HAMINVIDIA MIGTime-Slicing
隔离级别显存硬隔离 + 算力软隔离显存/算力/缓存/带宽全硬隔离无隔离(仅时分复用)
GPU 要求所有 NVIDIA GPUA100 / A30 / H100 等 MIG 支持型号所有 NVIDIA GPU
显存保护是(cudaMalloc 限制)是(硬件分区)否(无限制,互相干扰)
算力保护部分(时间片节流)是(SM 硬件隔离)
故障隔离部分(OOM 不影响其他容器)是(MIG 实例完全独立)
分片粒度数理论无上限最多 7 个 MIG 实例(A100)受 GPU 上下文限制
配置复杂度中(Helm 安装 + Pod 声明)高(GPU 模式切换 + 重启)低(device-plugin 配置)
动态调整支持(Pod 重建)不支持(需重置 GPU)不支持
性能开销低(LD_PRELOAD 开销)无(硬件原生)无(原生)

适用场景决策树:

graph TD
    A["是否需要硬件级安全隔离 - 多租户?"] -->|是| B[MIG]
    B --> B1["适用:SaaS 平台提供 GPU 服务、严格多租户隔离"]
    A -->|否| C["是否需要显存硬限制?"]
    C -->|是| D[HAMI]
    D --> D1["适用:推理服务共享 GPU、开发环境 GPU 复用"]
    C -->|否| E["Time-Slicing"]
    E --> E1["适用:开发测试、非关键批处理、GPU 空闲时段复用"]

HAMI 的独特优势在于不依赖特定 GPU 硬件型号,在 T4 / V100 / A10 等不支持 MIG 的 GPU 上也能实现显存隔离与算力软隔离,覆盖了 MIG 无法覆盖的 GPU 型号范围。

18 HAMI 如何通过节点亲和性选择特定型号的 GPU?

答案:

HAMI 通过 Kubernetes 原生 nodeSelector / nodeAffinity 机制结合 device plugin 上报的 GPU 型号标签,实现 Pod 对特定 GPU 型号的调度亲和性。

节点标签自动注册:

HAMI device plugin 启动时通过 NVML 读取 GPU 型号,自动为节点打上标签:

# HAMI 自动添加的节点标签
hami.io/gpu-model=NVIDIA-A100-SXM4-80GB
hami.io/gpu-memory-total=81920    # MiB
hami.io/gpu-count=8
hami.io/gpu-type=tesla
nvidia.com/gpu.product=NVIDIA-A100-SXM4-80GB

Pod 按 GPU 型号选择:

# 仅调度到 A100 GPU 节点
apiVersion: v1
kind: Pod
spec:
  nodeSelector:
    hami.io/gpu-model: "NVIDIA-A100-SXM4-80GB"
  containers:
  - resources:
      limits:
        hami.io/gpu: 1
# 排除特定型号(In 操作符的逆向)
apiVersion: v1
kind: Pod
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: hami.io/gpu-model
            operator: NotIn
            values:
            - "NVIDIA-T4"
            - "NVIDIA-Tesla-K80"
  containers:
  - resources:
      limits:
        hami.io/gpu: 1

虚拟 GPU 类型的亲和性:

# 部署时通过 Helm 设置虚拟 GPU 类型标签
devicePlugin:
  nodeLabels:
    gpu-tier: "premium"  # A100/H100 节点
    gpu-tier: "standard" # V100/T4 节点

# Pod 选择
spec:
  nodeSelector:
    gpu-tier: "premium"
19 HAMI 如何处理显存 OOM 与超限场景?

答案:

HAMI 在显存超限时,通过 libvgpu.so 在 cudaMalloc 调用处拦截并返回 cudaErrorMemoryAllocation(错误码 2),应用层按标准 CUDA OOM 方式处理,不会导致内核态 GPU 异常或节点 crash。

OOM 处理流程:

graph TD
    A["应用调用 cudaMalloc(size)"] --> B["libvgpu.so 检查: current_usage + size > limit ?"]
    B -->|是| C["返回 cudaErrorMemoryAllocation"]
    C --> C1["PyTorch: 抛出 RuntimeError - CUDA out of memory"]
    C --> C2["TensorFlow: 抛出 ResourceExhaustedError"]
    C --> C3["自定义 CUDA: 检查 cudaMalloc 返回值"]
    B -->|否| D["透传到显卡驱动正常分配"]

与其他容器的隔离性:

HAMI 的 OOM 仅影响发起超限分配的容器自身,不会波及同一物理 GPU 上的其他容器。因为每个容器的 libvgpu.so 实例独立维护各自的显存使用计数器。但如果应用绕过 cudaMalloc(例如通过 CUDA Driver API 直接操作显存),则 HAMI 无法拦截,可能导致物理 GPU 级别的 OOM,影响同卡其他容器。

OOM 监控告警:

# HAMI 记录 OOM 事件的 counter 指标
rate(hami_gpu_oom_events_total[5m]) > 0

# Pod 显存使用接近上限
hami_gpu_memory_used_bytes / hami_gpu_memory_limit_bytes > 0.95

Pod 层面 OOM 表现:

# 容器内 nvidia-smi 显示(HAMI 修改过的 nvidia-smi)
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name              GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A     12345      C   python                      4096MiB |
|                                                                   (limit: 8192MiB) |
+-----------------------------------------------------------------------------+
20 HAMI 支持哪些容器运行时?

答案:

HAMI 对容器运行时的依赖主要体现在 LD_PRELOAD 挂载和环境变量注入两个环节,理论上兼容所有符合 OCI 规范的容器运行时。

兼容性矩阵:

运行时兼容状态说明
containerd完全兼容推荐运行时,生产环境首选
cri-o兼容Kubernetes 1.24+ 推荐
Docker(dockershim)兼容Kubernetes 1.23 及以下版本
nvidia-container-runtime完全兼容HAMI 与此运行时协同工作

containerd 配置要点:

# /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
  runtime_type = "io.containerd.runc.v2"

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia]
  runtime_type = "io.containerd.runc.v2"
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia.options]
    BinaryName = "/usr/bin/nvidia-container-runtime"

HAMI 不依赖特定运行时的特有功能。libvgpu.so 的挂载通过 device plugin 的 Allocate 响应中的 mount 字段指定 hostPath,标准 OCI runtime spec 支持此挂载方式。环境变量注入同样通过 device plugin Allocate 响应的 envs 字段,由 kubelet 传递给容器运行时。

21 HAMI 如何进行版本升级?有哪些兼容性注意事项?

答案:

HAMI 升级涉及 device plugin(DaemonSet)scheduler(Deployment)libvgpu.so 三个组件,需按顺序升级以保持兼容性。

升级步骤:

# 1. 先升级 scheduler(无状态,可滚动更新)
kubectl set image deployment/hami-scheduler \
  scheduler=projecthami/hami:v2.4.0 \
  -n kube-system

# 2. 升级 device plugin DaemonSet(逐个节点)
kubectl set image daemonset/hami-device-plugin \
  device-plugin=projecthami/hami:v2.4.0 \
  -n kube-system

# 3. 确认 libvgpu.so 版本与 device plugin 匹配
# device plugin 容器内自带的 libvgpu.so 会自动挂载到宿主机路径
kubectl rollout status daemonset/hami-device-plugin -n kube-system

兼容性保障规则:

升级路径兼容性注意事项
v2.3.x → v2.4.x兼容先升 scheduler,再升 device plugin
v2.2.x → v2.4.x需评估检查 CRD 变更和资源名变更
libvgpu.so 版本必须与 device plugin 一致不同版本混合导致 CUDA API 拦截行为不一致
CUDA 版本v2.4 支持 CUDA 11.0-12.x升级前验证目标 CUDA 版本
Kubernetes 版本支持 1.20 - 1.29检查 API 弃用情况

回滚策略:

# 先回滚 device plugin
helm rollback hami -n kube-system

# 已运行的 Pod 继续使用旧版 libvgpu.so,不受影响
# 新建 Pod 将使用回滚后的 libvgpu.so

升级期间的行为:

  • 已运行的 Pod 不受 scheduler 升级影响(scheduler 仅参与调度阶段)
  • device plugin DaemonSet 滚动更新期间,该节点上已运行的 Pod 不受影响
  • 新 Pod 在 device plugin 升级期间不可调度到对应节点(Allocate 不可用)
22 HAMI 如何实现多租户 GPU 资源隔离?

答案:

HAMI 的多租户隔离由 Namespace ResourceQuota + HAMI Webhook 注入默认限制 + 显存硬隔离 三层构成。

租户隔离架构:

graph TD
    A[Cluster] --> B["tenant-a - namespace"]
    A --> C["tenant-b - namespace"]
    B --> B1["ResourceQuota: hami.io/gpu-memory=160GB, hami.io/gpu-core=400"]
    B --> B2["Pod 声明 gpu-memory 后,由 Webhook 补全 gpu-core 默认值"]
    C --> C1["ResourceQuota: hami.io/gpu-memory=80GB, hami.io/gpu-core=200"]
    C --> C2["同上"]

ResourceQuota 配置:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: gpu-tenant-a-quota
  namespace: tenant-a
spec:
  hard:
    requests.hami.io/gpu: 4
    limits.hami.io/gpu: 4
    limits.hami.io/gpu-memory: 160Gi
    limits.hami.io/gpu-core: 400
    limits.hami.io/gpu-memory-percentage: 400
apiVersion: v1
kind: LimitRange
metadata:
  name: gpu-limit-range
  namespace: tenant-a
spec:
  limits:
  - type: Container
    default:
      hami.io/gpu: 1
      hami.io/gpu-memory: 8Gi
      hami.io/gpu-core: 20
    defaultRequest:
      hami.io/gpu: 1
      hami.io/gpu-memory: 4Gi
      hami.io/gpu-core: 10
    max:
      hami.io/gpu-memory: 40Gi
      hami.io/gpu-core: 80
    min:
      hami.io/gpu-memory: 2Gi
      hami.io/gpu-core: 5

显存层面的硬隔离保证:

即使两个租户的 Pod 被调度到同一张物理 GPU 上,各自的 libvgpu.so 实例独立拦截 CUDa 显存分配调用,租户 A 的 Pod 无论如何无法使用超过其声明的 gpu-memory,也永远无法访问租户 B 的显存空间。

注意事项:

HAMI 不提供 GPU 数据清理(类似 MIG 的硬件隔离 + 显存归零),同一张物理 GPU 上的上一个容器释放显存后,残留数据可能对后续调度到同卡的容器构成信息泄露风险。对高安全等级的多租户场景,结合 MIG 或配合 NVIDIA Confidential Computing 特性使用。

23 HAMI 对训练工作负载有什么支持能力?

答案:

HAMI 对训练工作负载的核心价值在于 多卡训练场景下的 GPU 共享与碎片化消除,支持 PyTorch DDP、Horovod、DeepSpeed 等分布式训练框架。

训练工作负载典型配置:

apiVersion: v1
kind: Pod
metadata:
  name: ddp-training-worker-0
  annotations:
    hami.io/gpu-topology-policy: "nvlink-first"
spec:
  hostNetwork: true           # NCCL 通信使用主机网络
  containers:
  - name: training
    image: pytorch/pytorch:2.1.0-cuda12.1-cudnn8-devel
    env:
    - name: NCCL_DEBUG
      value: "INFO"
    - name: NCCL_SOCKET_IFNAME
      value: "eth0"
    - name: MASTER_ADDR
      value: "ddp-training-master"
    resources:
      limits:
        hami.io/gpu: 1
        hami.io/gpu-memory: 32   # 32GB 显存
        hami.io/gpu-core: 80     # 80% 算力(训练需要高算力)

支持特性矩阵:

训练特性支持状态说明
单节点多卡训练支持通过拓扑感知分配 NVLink 直连 GPU
多节点分布式训练支持NCCL 通信依赖 HostNetwork
Gradient Accumulation支持不涉及 GPU 特性
Mixed Precision(AMP)支持显存和算力限制均正常生效
Gradient Checkpointing支持显存换计算,显存限制下有效
DeepSpeed ZeRO部分支持ZeRO Stage 3 需大显存,HARM 共享模式下受限
CUDA Graph(静态图加速)部分支持图捕获期间算力控制精度下降

训练优化建议:

# 训练 Pod 建议 gpu-core 不低于 50
# 训练 Pod 建议 gpu-memory 设置为模型占用 + 20% 余量
# 建议使用 hostNetwork 减少 NCCL 通信延迟
# 建议配合 Volcano 使用 Gang Scheduling 保证 All-or-Nothing
24 HAMI 对推理工作负载有什么优化?

答案:

HAMI 对推理工作负载的核心优化点在于 高密度 GPU 共享显存优先分配策略。推理服务通常显存需求大、算力需求低,HAMI 的细粒度显存 + 低算力配置可大幅提升 GPU 利用率。

推理服务典型配置:

# LLM 推理(70B 模型,INT4 量化,约需 35GB 显存)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: llama-inference
spec:
  replicas: 2
  template:
    spec:
      containers:
      - name: vllm
        image: vllm/vllm-openai:latest
        args:
        - --model=/models/llama-70b-int4
        - --tensor-parallel-size=1
        - --max-model-len=4096
        resources:
          limits:
            hami.io/gpu: 1
            hami.io/gpu-memory: 40   # 40GB 显存
            hami.io/gpu-core: 15     # 15% 算力(推理算力需求低)
        env:
        - name: CUDA_DEVICE_MEMORY_LIMIT
          value: "42949672960"       # 40GB,由 HAMI 注入

推理场景优化策略:

策略配置效果
高密度部署gpu-core=10, gpu-memory=模型显存+2GB单 A100 80G 可承载 2 个 70B INT4 或 4 个 13B FP16
显存优先调度scheduler 装箱策略优先使用显存富余的 GPU减少显存碎片
空闲时 burst算力软限制,GPU 空闲时自动获得更多算力冷启动和突发请求有更好延迟
HPA 联动基于 GPU 显存或请求延迟触发扩缩容弹性匹配推理流量

推理场景典型共享密度:

graph TD
    A["A100 80GB GPU"] --> B["推理实例 1: 40GB 显存, 15% 算力 - LLaMA-70B INT4"]
    A --> C["推理实例 2: 20GB 显存, 10% 算力 - SDXL 图像生成"]
    A --> D["推理实例 3: 16GB 显存, 10% 算力 - Whisper-large-v3"]

总计: 76GB / 80GB 显存, 35% / 100% 算力

25 HAMI 常见故障有哪些?如何诊断排查?

答案:

故障现象一:Pod 调度卡在 Pending 状态

# 排查步骤
kubectl describe pod <pod-name>
# 查看 Events,常见原因:
# 1. "0/10 nodes are available: Insufficient hami.io/gpu-memory"
#    → GPU 显存不足,HAMIscheduler Filter 阶段排除所有节点
# 2. "0/10 nodes are available: Insufficient hami.io/gpu-core"
#    → GPU 算力不足

# 检查节点资源
kubectl get nodes -o custom-columns=NAME:.metadata.name,\
  GPU-MEMORY:.status.allocatable.hami\.io/gpu-memory,\
  GPU-CORE:.status.allocatable.hami\.io/gpu-core

# 检查 scheduler 日志
kubectl logs -n kube-system deployment/hami-scheduler --tail=50

故障现象二:容器内 nvidia-smi 无输出或报错

# 原因:libvgpu.so 未正确挂载或 LD_PRELOAD 未生效
# 验证:
kubectl exec <pod> -- env | grep LD_PRELOAD
# 预期输出: LD_PRELOAD=/usr/local/hami/libvgpu.so

kubectl exec <pod> -- ls -la /usr/local/hami/libvgpu.so
# 预期:文件存在

# 如果 libvgpu.so 缺失,检查 device plugin Pod 日志
kubectl logs -n kube-system daemonset/hami-device-plugin --tail=100

故障现象三:应用报 CUDA OOM 但实际显存低于 limit

# 原因:CUDA context 开销 + cuDNN/cuBLAS 内部缓存
# libvgpu.so 统计的是应用通过 cudaMalloc 显式分配的显存
# CUDA context 和框架内部缓存不计入 limit 但会消耗物理显存

# 缓解措施:
# 1. 给 limit 预留 10-15% 余量
# 2. 设置框架减少缓存
#    PyTorch: export PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:128
#    TensorFlow: tf.config.experimental.set_memory_growth(gpu, True)

故障现象四:device plugin 反复重启

# 检查 nvidia-driver 版本
kubectl logs -n kube-system daemonset/hami-device-plugin | grep -i "driver\|nvidia\|nvml"

# NVML 初始化失败的常见原因:
# 1. nvidia-driver 未安装或版本过低(要求 >= 450.80.02)
# 2. /dev/nvidia* 设备文件缺失
# 3. nvidia-container-toolkit 未正确配置

# 验证节点基础 GPU 环境
kubectl run gpu-test --image=nvidia/cuda:12.1.0-base-ubuntu22.04 \
  --restart=Never --rm -it --overrides='{"spec":{"nodeName":"<gpu-node>"}}' \
  -- nvidia-smi

故障诊断汇总检查表:

检查项命令预期结果
device plugin 状态kubectl get ds -n kube-system hami-device-pluginREADY
scheduler 状态kubectl get deploy -n kube-system hami-schedulerREADY
节点资源上报kubectl describe node <node>hami.io/* 字段存在
libvgpu.so 挂载kubectl exec <pod> -- ls /usr/local/hami/libvgpu.so
LD_PRELOADkubectl exec <pod> -- envLD_PRELOAD 设置正确
GPU 驱动kubectl exec <pod> -- nvidia-smi正常输出
26 HAMI 中 Pod 优先级与抢占对 GPU 资源的影响是怎样的?

答案:

HAMI 的 Pod 优先级与抢占机制遵循 Kubernetes 原生 PriorityClass + Preemption 框架,结合 HAMI-scheduler 的 GPU 状态感知,在高优先级 Pod 无法调度时触发低优先级 Pod 驱逐,释放 GPU 资源。

PriorityClass 定义:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: gpu-training-high
value: 10000
globalDefault: false
description: "高优先级分布式训练任务"
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: gpu-inference-medium
value: 5000
globalDefault: false
description: "中等优先级推理服务"
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: gpu-dev-low
value: 1000
globalDefault: false
description: "低优先级开发测试"

HAMI 抢占决策流程:

graph TD
    A["高优先级 Pod 进入调度队列"] --> B["Kube-scheduler Filter 阶段通过"]
    A --> C["HAMI-scheduler Filter: 检查节点 GPU 卡剩余资源"]
    C --> D["有足够资源"]
    D --> D1["正常调度"]
    C --> E["资源不足"]
    E --> F["进入 Preemption 评估"]
    F --> G["评估同节点上低优先级 Pod 占用的 GPU 资源"]
    G --> H["被抢占 Pod 释放的 gpu-memory + gpu-core 是否满足需求?"]
    H -->|是| I["驱逐低优先级 Pod → 调度高优先级 Pod"]
    H -->|否| J["继续评估下一个候选节点"]
    F --> K["无满足条件的节点 → Pending"]

GPU 资源释放时间:

# 抢占后 GPU 资源释放存在延迟
# 1. Pod 驱逐(terminationGracePeriodSeconds,默认 30s)
# 2. 容器停止 → libvgpu.so 卸载 → 显存清理(CUDA context 销毁)
# 3. HAMI device plugin 感知并上报更新后的 GPU 状态
#    (ListAndWatch 默认健康检查间隔,取决于 kubelet 轮询周期)
# 总延迟:通常 30s - 60s

HARM 抢占注意事项:

显存清理依赖应用进程正常退出时的 CUDA context 销毁。如果被抢占的应用进程在收到 SIGTERM 后没有正常执行 cudaFree 或 cuCtxDestroy,物理显存可能短期内不会完全释放(CUDA driver 层面的延迟回收)。对显存敏感的场景,建议 terminationGracePeriodSeconds 设置为 60 秒以上,给应用足够时间优雅关闭。

27 HAMI GPU 共享场景下的性能干扰(Noisy Neighbor)如何评估与控制?

答案:

HAMI 共享模式下,同一物理 GPU 上的容器共享 GPU 显存带宽、L2 Cache 和 DRAM 带宽等资源,形成性能干扰(Noisy Neighbor),主要来源于显存带宽争抢和计算单元竞争。

干扰来源分析:

GPU 共享资源竞争模型:

  容器 A                    容器 B
    │                         │
    ├─ SM (计算单元)          ├─ SM (计算单元)
    │  HAMI 算力节流控制      │  HAMI 算力节流控制
    │                         │
    ├─ L2 Cache ──争抢──── L2 Cache  ← 无隔离
    │                         │
    ├─ HBM 带宽 ──争抢─── HBM 带宽   ← 无隔离
    │                         │
    └─ PCIe/NVLink ─争抢─ PCIe/NVLink ← 部分隔离(拓扑感知)

干扰量化评估方法:

# 1. 单容器独占 GPU 时跑基准测试
kubectl run benchmark-standalone --image=nvidia/cuda:12.1.0-devel-ubuntu22.04 \
  --overrides='{"spec":{"nodeSelector":{"hami.io/gpu-model":"NVIDIA-A100-SXM4-80GB"}}}' \
  -- /workspace/benchmark --iterations=1000

# 2. 共享 GPU 场景下同时运行两个容器
kubectl run benchmark-shared-a --resources='limits={hami.io/gpu=1,hami.io/gpu-memory=40,hami.io/gpu-core=50}' \
  -- /workspace/benchmark --iterations=1000 &
kubectl run benchmark-shared-b --resources='limits={hami.io/gpu=1,hami.io/gpu-memory=40,hami.io/gpu-core=50}' \
  -- /workspace/benchmark --iterations=1000 &

# 3. 对比吞吐量下降比例:干扰系数 = (throughput_shared - throughput_standalone) / throughput_standalone

控制与缓解策略:

策略方法效果
算力上限控制设置合理的 gpu-core 上限直接限制计算单元竞争
同质化调度将相似工作负载调度到同一 GPU减少异构负载干扰
反亲和调度延迟敏感服务使用 PodAntiAffinity避免核心服务受干扰
GPU 独占标记关键服务声明 gpu-core=100独占模式消除干扰
MIG 辅助对 A100/H100 结合 MIG 硬件隔离从硬件层面消除共享资源争抢

Prometheus 监控干扰指标:

# 同一 GPU 上容器间算力利用率标准差(高值 = 不均匀 = 存在干扰)
stddev by (gpu_id) (hami_gpu_core_utilization)

# 隔离效率 = 单容器算力利用率 / 声明算力占比
# 值 < 1 表示存在性能干扰
hami_gpu_core_utilization / hami_gpu_core_limit
28 HAMI 有哪些安全配置?

答案:

HAMI 的安全配置涉及 Pod SecurityRBAC 控制 GPU 资源访问LD_PRELOAD 安全风险管控 三个层面。

Pod Security 配置:

apiVersion: v1
kind: Pod
metadata:
  name: gpu-secure-pod
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop:
        - ALL
      readOnlyRootFilesystem: false  # CUDA 需要 tmp 写入
    resources:
      limits:
        hami.io/gpu: 1
        hami.io/gpu-memory: 8

RBAC 限制 GPU 资源使用:

# 仅允许特定 ServiceAccount 使用 HAMI GPU 资源
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: hami-gpu-user
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["create"]
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: gpu-resource-validator
webhooks:
- name: gpu-validator.k8s.io
  rules:
  - operations: ["CREATE", "UPDATE"]
    apiGroups: [""]
    apiVersions: ["v1"]
    resources: ["pods"]
  clientConfig:
    service:
      name: gpu-validator
      namespace: kube-system

LD_PRELOAD 安全防护:

# device plugin 部署时限制权限
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: hami-device-plugin
spec:
  template:
    spec:
      containers:
      - name: device-plugin
        securityContext:
          readOnlyRootFilesystem: true
          allowPrivilegeEscalation: false
        volumeMounts:
        - name: lib-dir
          mountPath: /usr/local/hami
          readOnly: true    # libvgpu.so 只读挂载
      volumes:
      - name: lib-dir
        hostPath:
          path: /usr/local/hami
          type: DirectoryOrCreate

GPU 显存数据安全注意事项:

HAMI 不执行 GPU 显存归零操作。容器释放显存后,物理显存中的数据残留对下一次分配到同 GPU 的容器构成潜在信息泄露风险。高安全场景需配合以下措施:

# 1. 只在独占 GPU 上运行敏感工作负载(声明 gpu-core=100)
# 2. 在应用退出前执行显存清零(cudaMemset)
# 3. 评估结合 MIG 硬件隔离 + NVIDIA Confidential Computing
29 HAMI 的监控与日志诊断体系如何搭建?

答案:

HAMI 的监控诊断体系由三层构成:HAMI 内置 metrics(GPU 使用指标)、HAMI 组件日志(device plugin + scheduler 运行日志)、Prometheus + Grafana + Loki(指标集中采集、可视化、日志聚合)。

架构总览:

graph TD
    subgraph grafana["Grafana 仪表盘"]
        G1["GPU 集群总览 - 利用率/碎片/共享密度"]
        G2["单 GPU 卡详情 - 显存分配图/算力分布"]
        G3["Pod 级别 GPU 监控 - 显存使用曲线/算力曲线"]
        G4["HAMI 组件健康状态 - device plugin / scheduler"]
    end
    subgraph prom["Prometheus - metrics"]
        P1[metrics 采集]
    end
    subgraph loki["Loki - logs"]
        L1[logs 聚合]
    end
    subgraph hami["HAMI 组件"]
        H1["device-plugin - metrics + logs"]
        H2["scheduler - metrics + logs"]
        H3["libvgpu.so - Pod 内 metrics"]
    end
    prom --> grafana
    loki --> grafana
    hami --> prom
    hami --> loki

关键告警规则:

# prometheus-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: hami-alerts
  namespace: kube-system
spec:
  groups:
  - name: hami.gpu
    rules:
    - alert: HAMIGPUMemoryHighUsage
      expr: (hami_gpu_memory_used_bytes / hami_gpu_memory_total_bytes) > 0.95
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: "GPU 显存使用率 > 95%"

    - alert: HAMIGPUOOMFrequency
      expr: rate(hami_gpu_oom_events_total[10m]) > 0.1
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "GPU OOM 事件频率异常"

    - alert: HAMIDevicePluginDown
      expr: up{job="hami-device-plugin"} == 0
      for: 3m
      labels:
        severity: critical

    - alert: HAMISchedulerDown
      expr: up{job="hami-scheduler"} == 0
      for: 3m
      labels:
        severity: critical

    - alert: HAMIGPUHighDensity
      expr: hami_gpu_shared_count > 10
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: "GPU 共享容器数超过 10,Noisy Neighbor 风险"

    - alert: HAMIGPUMemoryFragmentation
      expr: |
        (sum by (gpu_id) (hami_gpu_memory_limit_bytes) - sum by (gpu_id) (hami_gpu_memory_used_bytes))
        / hami_gpu_memory_total_bytes < 0.05
        and hami_gpu_shared_count < 3        
      for: 5m
      labels:
        severity: info
      annotations:
        summary: "GPU 显存碎片化(空闲少但容器少 = 显存碎片)"

组件日志诊断命令:

# device plugin 日志
kubectl logs -n kube-system -l app=hami-device-plugin --tail=100 \
  | grep -E "ERROR|WARN|FATAL"

# scheduler 日志
kubectl logs -n kube-system deployment/hami-scheduler --tail=100 \
  | grep -E "filter|allocate|error"

# 特定 Pod 的 GPU 事件(从 device plugin 日志关联)
kubectl logs -n kube-system -l app=hami-device-plugin \
  | grep "<pod-uid>"

# Loki 日志查询(HAMI GPU OOM 事件)
{app="hami-device-plugin"} |= "OOM"
30 HAMI 与 GPU Operator 如何协同部署?

答案:

HAMI 与 GPU Operator 的协同部署方案:GPU Operator 负责自动化安装和维护 NVIDIA 驱动、nvidia-container-toolkit、nvidia-device-plugin 等基础组件;HAMI 在此基础之上部署,接管 GPU 的虚拟化资源共享能力。

部署顺序与分工:

graph TD
    A["步骤 1: GPU Operator - NVIDIA 官方 Helm Chart"]
    A --> A1["NVIDIA Driver - DaemonSet,自动编译安装"]
    A --> A2["nvidia-container-toolkit - DaemonSet"]
    A --> A3["nvidia-device-plugin - DaemonSet,上报 nvidia.com/gpu"]
    A --> A4["dcgm-exporter - DaemonSet,GPU 指标采集"]
    A --> A5["GPU Feature Discovery - 节点标签自动注册"]
    B["步骤 2: HAMI - 4Paradigm Helm Chart"]
    B --> B1["HAMI device plugin - DaemonSet,上报 hami.io/* 资源"]
    B --> B2["HAMI scheduler - Deployment,Scheduler Extender"]
    B --> B3["libvgpu.so - 挂载到 /usr/local/hami/"]
    C["步骤 3: Prometheus + Grafana - 可选"]
    C --> C1["统一采集 DCGM + HAMI 指标"]

协同部署配置:

# 1. 安装 GPU Operator
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm install gpu-operator nvidia/gpu-operator \
  --namespace gpu-operator \
  --create-namespace \
  --set driver.enabled=true \
  --set toolkit.enabled=true \
  --set devicePlugin.enabled=true \
  --set dcgmExporter.enabled=true

# 2. 安装 HAMI
helm repo add hami https://project-hami.github.io/HAMi/charts
helm install hami hami/hami \
  --namespace kube-system \
  --set devicePlugin.devices.nvidia.resourceCountName=hami.io/gpu \
  --set devicePlugin.devices.nvidia.resourceMemoryName=hami.io/gpu-memory \
  --set devicePlugin.devices.nvidia.resourceCoreName=hami.io/gpu-core \
  --set scheduler.kubeScheduler.image.tag=v2.4.0 \
  --set devicePlugin.nodeSelector."nvidia\.com/gpu\.present"="true"

组件职责划分:

组件部署方资源名场景
nvidia-device-pluginGPU Operatornvidia.com/gpu整卡独占 Pod
HAMI device pluginHAMIhami.io/gpu / hami.io/gpu-memory / hami.io/gpu-coreGPU 共享 Pod
nvidia-container-toolkitGPU Operator通用所有 GPU 容器的基础运行时支持
dcgm-exporterGPU OperatorDCGM 指标GPU 硬件层级监控
HAMI metricsHAMIHAMI 指标vGPU 层级监控

节点初始化流程(GPU Operator + HAMI 完成后的节点状态):

graph TD
    A["GPU Node 最终状态"] --> B["NVIDIA Driver: 535.xx"]
    A --> C["nvidia-container-toolkit: running"]
    A --> D["GPU Feature Discovery labels: 自动注册"]
    A --> E["nvidia.com/gpu: capacity=8, allocatable=8"]
    A --> F["hami.io/gpu: capacity=800, allocatable=800"]
    A --> G["hami.io/gpu-memory: capacity=655360Mi, allocatable=640000Mi"]
    A --> H["hami.io/gpu-core: capacity=800, allocatable=800"]
    A --> I["DCGM metrics: 可用 - Prometheus 采集"]
    A --> J["HAMI metrics: 可用 - Prometheus 采集"]

升级注意事项:

  • GPU Operator 升级驱动可能触发节点重启,HAMI device plugin 需容忍节点 NotReady
  • HAMI libvgpu.so 升级不影响已运行的 Pod,新启动的 Pod 自动使用新版
  • DCGM exporter 和 HAMI metrics 指标互补:DCGM 提供硬件层级(温度/功耗/ECC),HAM 提供 vGPU 层级(容器级别显存/算力)
  • GPU Operator 与 HAMI 需统一 CUDA 驱动大版本(例如都为 CUDA 12.x 驱动系列)