Fake GPU Operator - 项目功能与实现原理分析
前文用Fake-GPU-Operator模拟了GPU在本地电脑上的调度,于是又进一步打算研究下Fake-GPU-Operator的原理。
一、概述
Fake GPU Operator(FGO) 是一个由 Run:ai 开源的 Kubernetes Operator,核心目标是:
在没有物理 GPU 硬件的 CPU-only 节点上,完整模拟 NVIDIA GPU 资源,使 GPU 相关应用、调度器、监控系统等可以在无硬件环境中正常运行。
典型使用场景
二、主要功能
1. GPU 资源模拟(核心功能)
在普通节点上向 Kubernetes 声明 nvidia.com/gpu 资源 支持配置 GPU 型号(如 Tesla-K80、A100)、显存大小、GPU 数量 支持 NVIDIA MIG(Multi-Instance GPU)模拟
2. 双模式资源分配
| Legacy Device Plugin | ||
| DRA(Dynamic Resource Allocation) |
3. GPU 监控指标模拟
以 NVIDIA DCGM Exporter 兼容格式暴露 Prometheus 指标 指标: DCGM_FI_DEV_GPU_UTIL、DCGM_FI_DEV_FB_USED、DCGM_FI_DEV_FB_FREE
支持通过 Pod 注解 run.ai/simulated-gpu-utilization: "10-30" 自定义利用率范围
4. nvidia-smi 模拟
向 GPU Pod 注入模拟的 nvidia-smi 可执行文件 通过 NODE_NAME 环境变量解析节点拓扑信息
5. KWOK 集成(超大规模模拟)
与 KWOK (Kubernetes WithOut Kubelet)集成 可模拟数千个虚拟 GPU 节点,无需真实 kubelet 进程
6. Compute Domain DRA(安全隔离)
模拟 NVIDIA Compute Domains(IMEX channel) 支持多节点 GPU 工作负载的安全隔离
7. Mock Backend(真实 NVML)
支持 mock 后端模式,安装 NVIDIA nvml-mock 允许真实 NVIDIA GPU Operator 组件对接模拟 GPU 支持直接调用 NVML 的应用(如真实 nvidia-smi、CUDA 设备发现)
8. 混合模式(真实 + 模拟 GPU 共存)
可与真实 NVIDIA GPU Operator 在同一集群共存 真实 GPU 节点由真实 Operator 管理,模拟节点由 FGO 管理
三、架构设计
整体架构图

组件列表(13 个可执行文件)
status-updater | ||
status-exporter | ||
device-plugin | ||
dra-plugin-gpu | ||
compute-domain-controller | ||
compute-domain-dra-plugin | ||
kwok-gpu-device-plugin | ||
kwok-dra-plugin | ||
kwok-compute-domain-dra-plugin | ||
status-exporter-kwok | ||
topology-server | ||
mig-faker | ||
nvidia-smi |
四、核心实现原理
4.1 拓扑配置系统(Topology ConfigMap)
FGO 的核心数据结构是存储在 Kubernetes ConfigMap 中的 拓扑配置。
集群级拓扑(Cluster Topology ConfigMap)
# 用户在 Helm values.yaml 中配置
topology:
nodePools:
default:
gpuProduct: Tesla-K80
gpuCount: 2
gpuMemory: 11441 # MiB
存储在 topology-cm(名称可配置)中,描述每个节点池的 GPU 规格。
节点级拓扑(Node Topology ConfigMap)
每个模拟 GPU 节点对应一个独立的 ConfigMap(topology-cm-<node-name>),存储该节点的实时 GPU 状态:
gpuMemory: 11441
gpuProduct: Tesla-K80
gpus:
- id: GPU-a1b2c3d4... # UUID(由 nodeName+index SHA1 生成)
status:
allocatedBy:
namespace: default
pod: gpu-pod
container: gpu-container
podGpuUsageStatus:
<pod-uid>:
utilization: {min: 80, max: 100}
fbUsed: 5720
useKnativeUtilization: false
格式兼容性
normalize.go 实现了新旧格式自动检测和转换:
旧格式:gpuProduct/gpuCount/gpuMemory 平铺字段 新格式:嵌套 gpu.backend/gpu.profile/gpu.overrides 结构 读取时自动归一化,保持向后兼容
4.2 节点接入流程(status-updater)
status-updater 是 FGO 的控制核心,包含三个 Controller:
NodeController(节点控制器)
监听带有 run.ai/simulated-gpu-node-pool 标签的节点:
节点加入集群
│
▼
isFakeGpuNode() 检查节点标签
│
▼
createNodeTopologyCM()
├── 从集群拓扑读取节点池配置
├── 解析 GPU 规格(型号、显存、数量)
├── 为每个 GPU 生成确定性 UUID(nodeName+index → SHA1)
└── 创建 Node Topology ConfigMap
│
▼
labelNode()
├── nvidia.com/gpu.deploy.dcgm-exporter: "true"
├── nvidia.com/gpu.deploy.device-plugin: "true"
├── nvidia.com/gpu.deploy.dra-plugin-gpu: "true"
└── nvidia.com/gpu.deploy.compute-domain-dra-plugin: "true"
这些标签触发 DaemonSet 在该节点上部署对应组件。
PodController(Pod 控制器)
监听调度到模拟 GPU 节点上的 GPU Pod:
Pod 调度到 GPU 节点
│
▼
过滤条件:
├── Pod 已调度(非 Pending)
├── Pod 未终止
└── Pod 是 GPU Pod(dedicated/shared/DRA)
│
▼
读取节点 Topology ConfigMap
│
▼
更新 GPU 分配状态
├── dedicated GPU pod:更新 AllocatedBy 字段
├── shared GPU pod:更新 PodGpuUsageStatus
└── DRA pod:通过 ResourceClaim 解析 GPU 分配
│
▼
写回 Topology ConfigMap
GPU 利用率计算策略
gpu_usage_calculator.go 按优先级依次判断:
Pod 注解 run.ai/simulated-gpu-utilization: "10-30" → 解析范围值 workloadKind 标签: TrainingWorkload → 80-100% InferenceWorkload / DistributedWorkload → 0%(使用 Knative 实时指标) InteractiveWorkload / build → 0% PodGroup priorityClassName(Run:ai 调度器集成) 默认值 → 100%
Knative 推理工作负载:当 useKnativeUtilization=true 时,status-exporter 查询 Prometheus rate(revision_app_request_count[1m]) 动态计算 GPU 利用率,实现与实际流量的联动。
4.3 GPU 资源声明(device-plugin)
device-plugin 针对不同节点类型采用两种完全不同的策略:
真实节点(RealNodeDevicePlugin)
实现 Kubernetes Device Plugin API(gRPC),与 kubelet 交互:
启动流程:
1. 从 Node Topology ConfigMap 读取 GPU 数量
2. 为每个 GPU 生成随机 UUID(pluginapi.Device)
3. 在 /var/lib/kubelet/device-plugins/fake-nvidia-gpu.sock 启动 gRPC 服务
4. 向 kubelet 注册 nvidia.com/gpu 资源
5. ListAndWatch:持续上报设备健康状态
分配流程(Allocate):
1. kubelet 请求分配 GPU
2. 返回 ContainerAllocateResponse:
├── 环境变量 MOCK_NVIDIA_VISIBLE_DEVICES=<device-ids>
├── 环境变量 NODE_NAME=<node-name>(供 nvidia-smi 使用)
└── 挂载 /var/lib/runai/bin/nvidia-smi → /bin/nvidia-smi
KWOK 虚拟节点(FakeNodeDevicePlugin)
KWOK 节点没有真实 kubelet,因此 直接 PATCH 节点 Status,绕过 Device Plugin gRPC:
// fake_node.go - 直接写入节点 Capacity 和 Allocatable
nodeStatus := v1.NodeStatus{
Capacity: v1.ResourceList{"nvidia.com/gpu": resource.NewQuantity(int64(gpuCount),resource.DecimalSI),},
Allocatable: v1.ResourceList{"nvidia.com/gpu": resource.NewQuantity(int64(gpuCount),resource.DecimalSI),},
}
kubeClient.CoreV1().Nodes().Patch(ctx,nodeName, MergePatchType, patchBytes, ..., "status")
这是两种模式的核心区别:FAKE_NODE 环境变量控制走哪条路径。
4.4 DRA 驱动(dra-plugin-gpu)
K8s 1.31+ 的现代资源分配机制:
初始化:
1. 读取 Node Topology ConfigMap
2. 为每个 GPU 创建 resourceapi.Device 对象
3. 通过 kubeletplugin.Helper 发布 ResourceSlice
分配流程:
1. PrepareResourceClaims:解析 ResourceClaim,返回 CDI 设备 ID
2. 生成 CDI spec(Container Device Interface)
3. 注入环境变量和设备挂载到容器
CDI 设备规范:
├── nvidia.com/gpu=GPU-<uuid>
└── 包含 nvidia-smi 挂载和环境变量注入
4.5 监控指标导出(status-exporter)
status-exporter 以 NVIDIA DCGM Exporter 兼容格式暴露指标,运行于每个 GPU 节点:
数据流:
Node Topology ConfigMap
│
▼ KubeWatcher(Watch ConfigMap 变更)
│
├──▶ MetricsExporter(:9400/metrics)
│ ├── DCGM_FI_DEV_GPU_UTIL{gpu, UUID, modelName, ...}
│ ├── DCGM_FI_DEV_FB_USED
│ └── DCGM_FI_DEV_FB_FREE
│
├──▶ LabelsExporter(更新节点 Labels)
│ └── nvidia.com/gpu.count, nvidia.com/gpu.memory 等
│
└──▶ FsExporter(写文件系统)
└── /run/nvidia-topologyd/... 等拓扑文件
指标刷新策略:
ConfigMap 变更时立即刷新 每 10 秒定时刷新(更新利用率随机范围值)
4.6 ComputeDomain CRD
自定义资源 ComputeDomain(resource.nvidia.com/v1beta1)模拟 NVIDIA 多节点 GPU 隔离:
用户创建 ComputeDomain CR
│
▼
compute-domain-controller
├── 创建 ResourceClaimTemplate
└── 更新 ComputeDomain status(Ready/Pending)
│
▼
compute-domain-dra-plugin
└── 分配 IMEX channel 设备给 Pod
五、关键数据流
完整 GPU Pod 生命周期
1. 管理员操作:
kubectl label node <node> run.ai/simulated-gpu-node-pool=default
2. status-updater/NodeController:
├── 检测到节点标签
├── 创建 Node Topology ConfigMap
└── 添加 nvidia.com/gpu.deploy.* 标签
3. DaemonSet 调度(由标签触发):
├── device-plugin Pod 在节点上启动
└── status-exporter Pod 在节点上启动
4. device-plugin:
├── 读取 Node Topology ConfigMap(获取 GPU 数量)
├── 创建虚拟 GPU 设备(带 UUID)
└── 向 kubelet 注册 nvidia.com/gpu 资源
5. 用户部署 GPU Pod:
resources.limits: nvidia.com/gpu: 1
6. kubelet 调用 device-plugin.Allocate():
└── 注入 MOCK_NVIDIA_VISIBLE_DEVICES, NODE_NAME, nvidia-smi 挂载
7. status-updater/PodController:
├── 检测到 GPU Pod 调度
├── 计算 GPU 利用率(注解/workloadKind/默认值)
└── 更新 Node Topology ConfigMap(GPU 分配状态)
8. status-exporter:
├── Watch 到 ConfigMap 变更
└── 更新 Prometheus 指标(DCGM_FI_DEV_GPU_UTIL 等)
六、配置系统
环境变量(关键)
TOPOLOGY_CM_NAME | |
TOPOLOGY_CM_NAMESPACE | |
NODE_NAME | |
FAKE_GPU_OPERATOR_NS | |
PROMETHEUS_URL | |
DISABLE_NODE_LABELING | |
FAKE_NODE | |
RUNAI_INTEGRATION_ENABLED |
Helm Values 关键配置
topology:
nodePools:
default:
gpuProduct: Tesla-K80 # GPU 型号
gpuCount: 2 # 每节点 GPU 数量
gpuMemory: 11441 # 显存 MiB
# 新格式(支持 mock backend)
topology:
nodePools:
my-pool:
gpu:
backend: fake # 或 mock(使用真实 NVML)
profile: a100 # mock 模式下的 GPU profile
draPlugin:
enabled: true # 启用 DRA(K8s 1.31+)
devicePlugin:
enabled: false # 禁用 Legacy Device Plugin
kwokDraPlugin:
enabled: true # 启用 KWOK 支持
computeDomainController:
enabled: true # 启用 ComputeDomain CRD
七、技术栈
八、项目目录结构
下面是整个代码仓库的概览图及各个模块的主要功能,其中的细节还有进一步学习研究。
fake-gpu-operator/
├── cmd/ # 13 个可执行文件入口
│ ├── device-plugin/ # Legacy Device Plugin
│ ├── dra-plugin-gpu/ # DRA GPU 驱动
│ ├── status-updater/ # 节点/Pod 状态控制器
│ ├── status-exporter/ # Prometheus 指标导出
│ ├── status-exporter-kwok/ # KWOK 节点指标导出
│ ├── compute-domain-controller/ # ComputeDomain 控制器
│ ├── compute-domain-dra-plugin/ # ComputeDomain DRA
│ ├── kwok-gpu-device-plugin/ # KWOK GPU Device Plugin
│ ├── kwok-dra-plugin/ # KWOK DRA 插件
│ ├── kwok-compute-domain-dra-plugin/
│ ├── topology-server/ # 拓扑信息服务
│ ├── mig-faker/ # MIG 模拟
│ └── nvidia-smi/ # nvidia-smi 模拟工具
│
├── internal/ # 内部实现包
│ ├── common/
│ │ ├── topology/ # 拓扑数据结构、ConfigMap 操作
│ │ ├── constants/ # 常量定义(标签、注解、环境变量)
│ │ ├── config/ # 配置验证
│ │ ├── kubeclient/ # Kubernetes 客户端封装
│ │ ├── profile/ # GPU profile 解析
│ │ └── app/ # App 运行框架
│ ├── deviceplugin/ # Device Plugin 实现
│ │ ├── real_node.go # 真实节点 Device Plugin
│ │ └── fake_node.go # KWOK 虚拟节点 Device Plugin
│ ├── dra-plugin-gpu/ # DRA 驱动实现
│ │ ├── driver.go # DRA 驱动核心
│ │ ├── state.go # 设备状态管理
│ │ ├── cdi.go # CDI 规范生成
│ │ └── discovery.go # GPU 设备发现
│ ├── status-updater/
│ │ ├── controllers/
│ │ │ ├── node/ # 节点控制器
│ │ │ ├── pod/ # Pod 控制器
│ │ │ ├── mock/ # Mock backend 控制器
│ │ │ └── runai/ # Run:ai 集成控制器
│ │ └── handlers/
│ │ ├── node/ # 节点事件处理(标签、ConfigMap)
│ │ └── pod/ # Pod 事件处理(GPU 分配、利用率)
│ ├── status-exporter/
│ │ ├── watch/ # ConfigMap Watch
│ │ └── export/
│ │ ├── metrics/ # Prometheus 指标
│ │ ├── labels/ # 节点标签更新
│ │ └── fs/ # 文件系统导出
│ ├── migfaker/ # MIG 模拟
│ ├── compute-domain-controller/ # ComputeDomain 控制器
│ └── kwok-*/ # KWOK 相关实现
│
├── pkg/
│ └── compute-domain/ # ComputeDomain 公共包
│
├── deploy/
│ └── fake-gpu-operator/ # Helm Chart
│ ├── templates/ # K8s 资源模板
│ └── crds/ # ComputeDomain CRD 定义
│
├── docs/ # 文档
├── test/ # E2E 测试
└── hack/ # 构建脚本
夜雨聆风