没有 GPU 时如何学习和试用 HAMi——Fake GPU + HAMi 使用教程

本实验将在 macOS 上使用 OrbStack 自带 Kubernetes 和 run-ai/fake-gpu-operator 搭建一个纯本地 Kubernetes 集群,然后在线安装 HAMi。

来源:HAMi 官网教程

这个实验不需要真实 NVIDIA GPU,适合用于课堂预习、讲解 HAMi 组件组成、验证 GPU Pod 调度流程,以及在个人电脑上快速熟悉 HAMi 的基础使用方式。

你将得到什么

完成本实验后,你会得到一个本地 Kubernetes 集群:

  • fake-gpu-operator 在 CPU 节点上模拟 nvidia.com/gpu 资源
  • HAMi scheduler、admission webhook 等控制面组件正常运行
  • 普通 Pod 可以通过 nvidia.com/gpu 申请模拟 GPU
  • 可以观察 fake GPU 资源从节点发现、Pod 申请、调度到运行的完整链路

注意:fake GPU 不能代表真实 GPU 的显存隔离、算力隔离、CUDA 运行时和驱动能力。本实验用于理解 HAMi 组成和基础调度链路;涉及真实显存切分、nvidia.com/gpumemnvidia.com/gpucores、CUDA 程序运行和性能隔离时,仍需要真实 NVIDIA GPU 环境。

前提条件

  • macOS,Intel 或 Apple Silicon 均可
  • 已安装 OrbStack 并启用内置 Kubernetes
  • 能访问 GitHub、GHCR 和 HAMi Helm 仓库
  • 本机至少 4 CPU、8 GB 内存可用于实验

步骤 1: 确认本地环境

1
2
3
4
5
6
7
8
# 检查集群版本
kubectl version

# 查看集群节点
kubectl get nodes -o wide

# 检查 Helm
helm version

步骤 2: 安装 Fake-gpu-operator

2.1 创建命名空间并设置安全策略

1
2
kubectl create namespace gpu-operator
kubectl label namespace gpu-operator pod-security.kubernetes.io/enforce=privileged

2.2 给节点打标签

1
2
NODE_NAME=$(kubectl get nodes -o jsonpath='{.items[0].metadata.name}')
kubectl label node ${NODE_NAME} run.ai/simulated-gpu-node-pool=default

2.3 安装 Fake-gpu-operator

1
2
3
4
5
6
7
export FAKE_GPU_OPERATOR_VERSION=0.0.80

helm upgrade -i gpu-operator \
oci://ghcr.io/run-ai/fake-gpu-operator/fake-gpu-operator \
--namespace gpu-operator \
--create-namespace \
--version ${FAKE_GPU_OPERATOR_VERSION}

2.4 等待组件运行

1
kubectl get pods -n gpu-operator

2.5 验证模拟 GPU 资源

1
2
3
4
kubectl get node ${NODE_NAME} \
-o custom-columns=NAME:.metadata.name,GPU:.status.capacity.nvidia\\.com/gpu

kubectl get node ${NODE_NAME} --show-labels | tr ',' '\n' | grep -E 'nvidia.com/gpu|run.ai'

步骤 3: 安装 HAMi

3.1 添加 HAMi Helm 仓库

1
2
helm repo add hami-charts https://project-hami.github.io/HAMi/
helm repo update

3.2 安装 HAMi

1
2
3
helm install hami hami-charts/hami \
-n kube-system \
--set devicePlugin.enabled=false

3.3 验证 HAMi 组件

1
2
kubectl get pods -n kube-system | grep hami
kubectl get deploy,svc,cm,sa -n kube-system | grep hami

3.4 确认所有 Helm Release

1
helm list -A

步骤 4: 安装 Prometheus

4.1 添加 Helm 仓库

1
2
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

4.2 安装 kube-prometheus-stack

1
2
3
4
helm install prometheus prometheus-community/kube-prometheus-stack \
-n monitoring --create-namespace \
--set grafana.enabled=false \
--version=75.15.1

4.3 等待 Prometheus 就绪

1
kubectl get pods -n monitoring

4.4 创建 ServiceMonitor 采集 GPU 指标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
kubectl apply -f - <<'EOF'
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: nvidia-dcgm-exporter
namespace: gpu-operator
labels:
release: prometheus
spec:
selector:
matchLabels:
app: nvidia-dcgm-exporter
namespaceSelector:
matchNames:
- gpu-operator
endpoints:
- port: gpu-metrics
path: /metrics
interval: 15s
EOF

验证 GPU 指标已采集:

1
2
kubectl exec -n monitoring prometheus-prometheus-kube-prometheus-prometheus-0 -- \
promtool query instant http://localhost:9090 'DCGM_FI_DEV_GPU_UTIL'

步骤 5: 运行模拟 GPU 工作负载

5.1 创建测试 Pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: fake-gpu-pod
labels:
hami.io/webhook: ignore
annotations:
run.ai/simulated-gpu-utilization: "10-30"
spec:
restartPolicy: Never
containers:
- name: app
image: ubuntu:22.04
command: [ "bash", "-lc", "sleep 3600" ]
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
nvidia.com/gpu: 1
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
EOF

5.2 等待 Pod 运行

1
kubectl get pod fake-gpu-pod -o wide

5.3 查看 Pod 的 GPU 资源申请

1
kubectl describe pod fake-gpu-pod | grep -A6 "Limits"

5.4 查看节点的 GPU 资源分配情况

1
kubectl describe node ${NODE_NAME} | grep -A10 "Allocated resources"

5.5 执行模拟 nvidia-smi

1
kubectl exec fake-gpu-pod -- nvidia-smi

步骤 6: 安装 HAMi WebUI

6.1 添加 HAMi WebUI Helm 仓库

1
2
helm repo add hami-webui https://Project-HAMi.github.io/HAMi-WebUI/
helm repo update

6.2 给节点添加 GPU 标签

1
kubectl label node ${NODE_NAME} gpu=on

6.3 添加模拟 GPU 注册信息

1
2
3
kubectl annotate node ${NODE_NAME} \
hami.io/node-nvidia-register='[{"id":"GPU-3cef3724-8228-5a66-b391-b0901788f5d0","count":10,"devmem":11441,"devcore":100,"type":"NVIDIA-Tesla-K80","mode":"hami-core","health":true},{"id":"GPU-5127182e-f297-5a25-bb44-0444c3be540c","index":1,"count":10,"devmem":11441,"devcore":100,"type":"NVIDIA-Tesla-K80","mode":"hami-core","health":true}]' \
hami.io/node-handshake="Requesting_$(date '+%Y.%m.%d %H:%M:%S')"

6.4 安装 HAMi WebUI

1
2
3
4
5
helm install my-hami-webui hami-webui/hami-webui \
--set externalPrometheus.enabled=true \
--set externalPrometheus.address="http://prometheus-kube-prometheus-prometheus.monitoring.svc.cluster.local:9090" \
--set dcgm-exporter.enabled=false \
-n kube-system

6.5 等待 WebUI 就绪

1
kubectl get pods -n kube-system | grep webui

6.6 访问 WebUI

1
kubectl -n kube-system port-forward svc/my-hami-webui 8080:3000

浏览器打开 http://localhost:8080/admin/vgpu/monitor/overview

步骤 7: 观察 HAMi 和 Fake GPU 的边界

1
2
3
4
5
6
7
8
# HAMi 组件
kubectl get deploy,svc,cm,sa -n kube-system | grep hami

# Fake-gpu-operator 组件
kubectl get daemonset,deploy,pod -n gpu-operator

# 节点容量
kubectl describe node ${NODE_NAME} | grep -A10 "Capacity:"

清理环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 删除测试 Pod
kubectl delete pod fake-gpu-pod

# 卸载 HAMi WebUI
helm uninstall my-hami-webui -n kube-system

# 卸载 HAMi
helm uninstall hami -n kube-system

# 卸载 Prometheus
helm uninstall prometheus -n monitoring
kubectl delete namespace monitoring

# 卸载 fake-gpu-operator
helm uninstall gpu-operator -n gpu-operator
kubectl delete namespace gpu-operator

# 清理节点标签和 annotation
kubectl label node ${NODE_NAME} gpu- run.ai/simulated-gpu-node-pool-
kubectl annotate node ${NODE_NAME} hami.io/node-nvidia-register- hami.io/node-handshake-

常见问题排查

问题 1: CoreDNS ImagePullBackOff

Docker Hub 连接超时导致 CoreDNS 无法启动,集群内所有 DNS 解析失败。

1
2
3
4
5
6
7
8
9
10
# 诊断
kubectl get pods -n kube-system | grep coredns

# 解决:从阿里云镜像拉取 CoreDNS 并重新打标签
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:1.10.1
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:1.10.1 \
rancher/mirrored-coredns-coredns:1.10.1

# 重启 CoreDNS
kubectl rollout restart deploy coredns -n kube-system

问题 2: HAMi WebUI ErrImagePull

Docker Hub 连接超时导致 WebUI 镜像拉取失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 诊断
kubectl describe pod -n kube-system my-hami-webui-*** | grep -A20 "Events:"

# 解决:从 DaoCloud 镜像拉取并重新打标签
docker pull docker.m.daocloud.io/projecthami/hami-webui-fe-oss:v1.2.0
docker pull docker.m.daocloud.io/projecthami/hami-webui-be-oss:v1.2.0
docker tag docker.m.daocloud.io/projecthami/hami-webui-fe-oss:v1.2.0 \
projecthami/hami-webui-fe-oss:v1.2.0
docker tag docker.m.daocloud.io/projecthami/hami-webui-be-oss:v1.2.0 \
projecthami/hami-webui-be-oss:v1.2.0

# 重启 WebUI
kubectl rollout restart deploy my-hami-webui -n kube-system

问题 3: Pod UnexpectedAdmissionError

fake-gpu-operator 的 device-plugin 重启后,GPU 设备暂时标记为不健康。

1
2
3
4
5
6
# 诊断
kubectl describe pod fake-gpu-pod | grep -A10 "Events:"

# 解决:删除后重新创建 Pod
kubectl delete pod fake-gpu-pod
# 然后重新 apply Pod YAML

问题 4: nvidia-smi DNS 解析失败

Pod 内执行 nvidia-smi 时报 DNS 超时,原因是 CoreDNS 未正常运行。

1
2
3
4
5
# 诊断
kubectl exec fake-gpu-pod -- nvidia-smi
# 如果看到 dial tcp: lookup topology-server.gpu-operator: i/o timeout

# 解决:先修复 CoreDNS(见问题 1),然后重新创建 Pod