一、环境说明
这次测试环境是一套单节点 Kubernetes 集群,节点上有一张 NVIDIA GPU,显存 8G 左右。部署目标是使用 HAMi 对单张 GPU 做 vGPU 共享,让多个 Pod 可以共享同一张物理 GPU。
HAMi 原名k8s-vGPU-scheduler,现在是 Kubernetes 上的异构算力虚拟化中间件,主要用于 GPU、NPU 等异构设备的共享、隔离和调度。对于 NVIDIA GPU 来说,HAMi 可以让 Pod 按显存、GPU core 等维度申请资源,从而避免一个小任务独占整张 GPU。HAMi 官方文档中也说明,它支持多种异构 AI 计算设备,并且支持多个容器或工作负载共享设备资源。
本文主要测试以下内容:
1. 部署前检查 NVIDIA Driver 和 NVIDIA Container Toolkit 2. 使用 Helm 部署 HAMi 3. 验证 HAMi 组件是否正常 4. 测试一张 8G GPU 被两个 Pod 共享 5. 测试 nvidia.com/gpumem 显存切分 6. 测试 nvidia.com/gpumem-percentage 显存百分比切分 7. 测试 nvidia.com/gpucores 算力比例限制 8. 测试指定 GPU 型号 9. 测试指定 GPU UUID 10. 说明 nvidia.com/gpu: 2 这个容易误解的点二、部署 HAMi 前需要准备什么
在 Kubernetes 上使用 NVIDIA GPU,大体要先解决三件事:
1. 宿主机能识别 GPU 2. 容器能使用 GPU 3. Kubernetes 能调度 GPU 资源HAMi 官方 Helm 部署文档中提到,部署前需要在 GPU 节点上准备 NVIDIA Driver 和 NVIDIA Container Toolkit,并且假设nvidia-container-runtime已经配置为默认的底层运行时。也就是说,HAMi 本身不是用来安装显卡驱动的,驱动和容器运行时环境需要提前准备好。
这里有一点需要注意:
在 HAMi 场景下,通常不需要再单独部署 NVIDIA 官方 k8s-device-plugin。原因是 HAMi 安装后会部署自己的hami-device-plugin,由它负责把 HAMi 管理的 GPU 资源注册给 kubelet。HAMi 官方 FAQ 也说明,HAMi Device Plugin、Volcano vGPU Device Plugin、NVIDIA 官方 Device Plugin 都会管理 GPU 资源,同一个节点上建议只使用一种 GPU 管理插件,避免资源冲突。
如果你的集群里已经通过 GPU Operator 部署了 NVIDIA 官方 device-plugin,需要注意不要让两个 device-plugin 同时管理同一种nvidia.com/gpu资源,否则很容易出现资源显示、调度行为和实际设备分配对不上的问题。
三、检查宿主机和容器 GPU 环境
3.1 检查宿主机 GPU 是否正常
先在宿主机上执行:
nvidia-smi正常情况下应该能看到显卡信息,例如:
NVIDIA GeForce RTX 3070 Ti Laptop GPU Memory-Usage: 0MiB / 8192MiB查看 GPU 型号:
nvidia-smi --query-gpu=name --format=csv,noheader查看 GPU UUID:
nvidia-smi --query-gpu=index,name,uuid,memory.total --format=csv,noheader示例输出:
0, NVIDIA GeForce RTX 3070 Ti Laptop GPU, GPU-998864a7-78d9-dbab-e122-4c37842ce7cf, 8192 MiB后面测试nvidia.com/use-gputype和nvidia.com/use-gpuuuid时会用到这两个值。
3.2 检查 Docker 容器是否能使用 GPU
如果你的机器上使用 Docker,可以先用 Docker 跑一个容器测试 GPU 是否能被容器识别。
docker run --rm --gpus all nvidia/cuda:11.0.3-base-ubuntu18.04 nvidia-smi如果这里不能正常输出 GPU 信息,就不要急着安装 HAMi,应该先处理 NVIDIA Driver、NVIDIA Container Toolkit 或 Docker runtime 配置。
3.3 注意 Docker 和 containerd 的区别
这里要特别注意:
Docker 测试成功,不代表 Kubernetes Pod 一定能使用 GPU。原因是现在很多 Kubernetes 集群默认使用的是 containerd,而不是 Docker。HAMi 官方部署文档里 Docker 和 containerd 的 NVIDIA runtime 配置是分开的:如果 Kubernetes 使用 Docker,需要把nvidia-container-runtime配成 Docker 的默认 runtime;如果 Kubernetes 使用 containerd,需要在 containerd 配置中把 NVIDIA runtime 配成默认 runtime。
可以通过下面命令查看节点使用的容器运行时:
kubectl get node -o wide如果显示的是 containerd,可以使用 NVIDIA 官方推荐的方式配置:
sudo nvidia-ctk runtime configure --runtime=containerd sudo systemctl restart containerdNVIDIA 官方文档也说明,Kubernetes 使用 containerd 时,可以通过nvidia-ctk runtime configure --runtime=containerd配置,然后重启 containerd。
如果是 Docker,则可以使用:
sudo nvidia-ctk runtime configure --runtime=docker sudo systemctl restart docker本文后面的 Pod YAML 没有显式配置:
runtimeClassName: nvidia前提是 NVIDIA runtime 已经被配置为默认容器运行时。如果你的集群不是默认使用 NVIDIA runtime,而是通过 RuntimeClass 暴露nvidiaruntime,那么需要根据实际环境给 Pod 增加:
runtimeClassName: nvidia四、安装 HAMi
4.1 给 GPU 节点打标签
HAMi 默认只管理带有gpu=on标签的 GPU 节点。官方文档说明,需要给 GPU 节点打gpu=on标签,没有这个标签的节点不能被 HAMi scheduler 管理。先查看节点名称:
kubectl get node给节点打标签:
kubectl label nodes master-01 gpu=on --overwrite确认标签:
kubectl get node master-01 --show-labels | grep gpu=on如果你发现hami-scheduler正常,但是hami-device-plugin没有起来,优先检查这个标签是否存在。
4.2 添加 HAMi Helm 仓库
先查看 Kubernetes Server 版本:
kubectl version添加 HAMi Helm 仓库:
helm repo add hami-charts https://project-hami.github.io/HAMi/ helm repo update4.3 安装 HAMi
安装时需要设置 kube-scheduler 镜像版本和 Kubernetes Server 版本匹配。HAMi 官方安装文档中也明确写到,scheduler.kubeScheduler.imageTag需要和 Kubernetes Server 版本保持一致。
例如 Kubernetes Server 版本是v1.29.0,安装命令如下:
helm install hami hami-charts/hami \ --set scheduler.kubeScheduler.imageTag=v1.29.0 \ -n kube-system这里的v1.29.0要替换成你自己集群的 Kubernetes Server 版本。
如果你的版本是v1.27.9,那就写成:
helm install hami hami-charts/hami \ --set scheduler.kubeScheduler.imageTag=v1.27.9 \ -n kube-system五、验证 HAMi 组件是否正常
执行:
kubectl -n kube-system get pod | grep -E "hami|vgpu"新版本一般能看到类似:
hami-device-plugin-xxxxx 2/2 Running hami-scheduler-xxxxx 2/2 Running老版本可能叫:
vgpu-device-plugin-xxxxx Running vgpu-scheduler-xxxxx RunningHAMi 官方文档中也说明,如果hami-device-plugin和hami-scheduler都是 Running,说明安装成功。查看节点资源:
kubectl describe node master-01重点看Capacity和Allocatable:
Capacity: nvidia.com/gpu: 10 Allocatable: nvidia.com/gpu: 10这里有个容易误解的点:
nvidia.com/gpu: 10这不是说机器上有 10 张物理 GPU,而是 HAMi 把一张物理 GPU 按默认配置注册成了多个可分配的 vGPU 份额。HAMi 配置中nvidia.deviceSplitCount默认值是10,含义是单张 GPU 默认最多允许分配给 10 个任务。所以在单卡 8G 的机器上看到nvidia.com/gpu: 10是正常现象。
六、HAMi 常用资源字段说明
HAMi 在 Pod 里主要通过下面几个资源字段控制 GPU 申请:
resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 3000 nvidia.com/gpucores: 30字段含义如下:
nvidia.com/gpu 表示申请 GPU/vGPU 设备分配实例。安装 HAMi 后,节点上看到的 nvidia.com/gpu 数量通常来自 HAMi 的 deviceSplitCount 配置。例如单卡默认可能显示为 10,但这个 10 不是 10 张物理 GPU,也不表示单个 Pod 可以从同一张物理 GPU 上申请多个 vGPU。 nvidia.com/gpumem 表示申请多少 GPU 显存。官方示例中 nvidia.com/gpumem: 3000 表示每个 vGPU 申请 3G 左右显存。 nvidia.com/gpumem-percentage 表示按百分比申请显存。例如 10 表示申请这张 GPU 约 10% 的显存。 nvidia.com/gpucores 表示申请 GPU core 的比例。例如 30 可以理解为申请约 30% 的 GPU 算力。这里注意一点:
nvidia.com/gpumem 和 nvidia.com/gpumem-percentage 不要同时写在同一个容器里。前者表示按固定显存大小申请,后者表示按百分比申请,二者选择一种即可。HAMi 官方显存示例中也明确说明,nvidia.com/gpumem不能和nvidia.com/gpumem-percentage一起使用。
Kubernetes 里 GPU 这类扩展资源一般写在limits下。如果只写limits,Kubernetes 会默认把 limit 当作 request 使用。Kubernetes 官方文档也说明,GPU 可以只写 limits;如果同时写 requests 和 limits,两者必须相等;不能只写 GPU requests 而不写 limits。
七、容易误解的点:nvidia.com/gpu: 2不是从一张卡里拿 2 份 vGPU
前面在查看节点资源时,可以看到类似下面的结果:
Capacity: nvidia.com/gpu: 10 Allocatable: nvidia.com/gpu: 10如果是单卡环境,这里很容易产生一个误解:
既然节点上显示 nvidia.com/gpu: 10, 是不是说明这一张物理 GPU 被切成了 10 份, 所以单个 Pod 写 nvidia.com/gpu: 2, 就是从这一张物理 GPU 里拿 2 份 vGPU?这个理解是不对的。
HAMi 官方 FAQ 对这个问题有明确说明:deviceSplitCount: 10表示一张物理 GPU 最多可以同时服务 10 个任务,但它并不表示一个任务可以从同一张物理 GPU 上申请多个 vGPU。当一个任务申请nvidia.com/gpu: 2时,HAMi 会把它解释为需要两个物理 GPU,而不是从同一张 GPU 上申请两个 vGPU。也就是说,下面这种写法:
resources: limits: nvidia.com/gpu: 2可以简单理解为:
这个 Pod 需要 2 个 GPU/vGPU 设备分配实例,并且这 2 个实例不能来自同一张物理 GPU。 对于我的单卡环境来说,可以简单理解为这个 Pod 需要 2 张物理 GPU,所以无法调度成功。而不是:
这个 Pod 需要从 1 张 GPU 里拿 2 个 vGPU 份额。所以在单节点、单张 8G GPU 环境里,如果创建下面这个 Pod:
apiVersion: v1 kind: Pod metadata: name: hami-gpu-2-test spec: restartPolicy: Never containers: - name: cuda image: nvidia/cuda:11.0.3-base-ubuntu18.04 command: ["bash", "-lc", "nvidia-smi && sleep 3600"] resources: limits: nvidia.com/gpu: 2 nvidia.com/gpumem: 2000 nvidia.com/gpucores: 30这个 Pod 无法调度成功。因为当前节点只有一张物理 GPU,而 Pod 申请的是 2 个 GPU/vGPU 设备分配实例。创建后查看 Pod:
kubectl get pod hami-gpu-2-test一般会看到它处于Pending状态:
NAME READY STATUS RESTARTS AGE hami-gpu-2-test 0/1 Pending 0 1m继续查看事件:
kubectl describe pod hami-gpu-2-test可以看到调度失败相关信息。这里要把两个概念分清楚:
deviceSplitCount 表示一张物理 GPU 最多允许多少个任务共享。 nvidia.com/gpu 表示这个 Pod 申请几个 GPU/vGPU 设备分配实例。 当单个 Pod 写成 nvidia.com/gpu: 2 时,HAMi 会按需要 2 个 GPU/vGPU 设备实例处理。 在单卡环境下,它无法从同一张物理 GPU 上拿到两个 vGPU。HAMi FAQ 里也说明,vGPU 的设计目标是让多个任务共享同一张 GPU,而不是让一个任务在同一张 GPU 上绑定多个 vGPU。deviceSplitCount: 10只是允许最多 10 个任务共享该 GPU,并不会增加真实的物理 GPU 资源。
所以,如果目标是:
一张 8G GPU 同时跑两个 Pod正确做法不是创建一个 Pod 并写:
nvidia.com/gpu: 2而是创建两个 Pod,每个 Pod 都申请:
resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 3000 nvidia.com/gpucores: 30也就是:
Pod A 申请 1 个 vGPU,3000MB 显存,30% GPU core。 Pod B 申请 1 个 vGPU,3000MB 显存,30% GPU core。这样两个 Pod 才能共享同一张物理 GPU。
八、测试 1:运行一个基础 HAMi GPU Pod
先验证 HAMi 调度链路和容器内 GPU 可见性。
apiVersion: v1 kind: Pod metadata: name: hami-basic spec: restartPolicy: Never containers: - name: cuda image: nvidia/cuda:11.0.3-base-ubuntu18.04 command: ["bash", "-lc", "nvidia-smi && sleep 3600"] resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 2000 nvidia.com/gpucores: 30进入容器验证:
kubectl exec -it hami-basic -- nvidia-smi如果正常,会看到类似下面的输出:
[HAMI-core Msg(...): Initializing.....] Memory-Usage: 0MiB / 2000MiB重点看容器里显示的总显存是否变成了你申请的值。例如这里申请的是2000,那么容器内看到的显存上限应该接近2000MiB。
九、测试 2:一张 8G 卡切给两个 Pod,每个 Pod 申请 3G 显存
测试目的:
验证两个 Pod 是否可以共享同一张 8G 物理 GPU。 每个 Pod 申请 3000MB 显存。 两个 Pod 总共申请 6000MB,小于 8G,所以理论上可以同时 Running。YAML 如下:
apiVersion: v1 kind: Pod metadata: name: hami-gpumem-3000-1 spec: restartPolicy: Never containers: - name: cuda image: nvidia/cuda:11.0.3-base-ubuntu18.04 command: ["bash", "-lc", "nvidia-smi && sleep 3600"] resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 3000 nvidia.com/gpucores: 30 --- apiVersion: v1 kind: Pod metadata: name: hami-gpumem-3000-2 spec: restartPolicy: Never containers: - name: cuda image: nvidia/cuda:11.0.3-base-ubuntu18.04 command: ["bash", "-lc", "nvidia-smi && sleep 3600"] resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 3000 nvidia.com/gpucores: 30分别进入两个 Pod:
kubectl exec -it hami-gpumem-3000-1 -- nvidia-smi kubectl exec -it hami-gpumem-3000-2 -- nvidia-smi预期结果:
两个 Pod 都能 Running。 两个 Pod 内执行 nvidia-smi 都能看到 GPU。 每个 Pod 内看到的 GPU 总显存大约是 3000MiB。如果这两个 Pod 都能正常运行,说明 HAMi 已经可以把一张物理 GPU 按显存维度切给多个 Pod 使用。
十、测试 3:按显存百分比切分
除了直接写nvidia.com/gpumem,HAMi 也支持通过nvidia.com/gpumem-percentage按百分比申请显存。例如 8G 显存的 GPU,申请 10%:
apiVersion: v1 kind: Pod metadata: name: hami-gpumem-percent-10 spec: restartPolicy: Never containers: - name: cuda image: nvidia/cuda:11.0.3-base-ubuntu18.04 command: ["bash", "-lc", "nvidia-smi && sleep 3600"] resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem-percentage: 10 nvidia.com/gpucores: 10验证:
kubectl exec -it hami-gpumem-percent-10 -- nvidia-smi预期结果:
容器内看到的总显存约等于整卡显存的 10%。 如果物理卡是 8192MiB,那么 10% 大约就是 819MiB。这里建议 Pod 名字和百分比保持一致。比如资源里写的是nvidia.com/gpumem-percentage: 10,Pod 名称就叫hami-gpumem-percent-10,避免后面排查时看乱。
十一、测试 4:按 GPU core 百分比限制
nvidia.com/gpucores可以理解为 HAMi 里用于申请 GPU 算力比例的字段。比如:
nvidia.com/gpucores: 30可以简单理解为申请约 30% GPU core 算力。这里的30不是指 30 个物理 CUDA Core,而是 HAMi 定义的 GPU core 使用比例。测试 YAML:
apiVersion: v1 kind: Pod metadata: name: hami-gpucores-30 spec: restartPolicy: Never containers: - name: cuda image: nvidia/cuda:11.0.3-base-ubuntu18.04 command: ["bash", "-lc", "nvidia-smi && sleep 3600"] env: - name: GPU_CORE_UTILIZATION_POLICY value: "force" resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 2000 nvidia.com/gpucores: 30查看:
kubectl get pod hami-gpucores-30 kubectl exec -it hami-gpucores-30 -- nvidia-smi这里要注意:
nvidia-smi 只能证明容器能看到 GPU,以及显存视图是否被限制。 如果要验证 gpucores 的算力限制,需要运行 CUDA 压测程序观察 GPU-Util,而不是只看 nvidia-smi。HAMi 官方文档说明,nvidia.com/gpucores是通过 time-slice 方式实现的,所以通过nvidia-smi查询 core utilization 时可能会有波动,不一定稳定卡在某一个固定数值。
十二、GPU_CORE_UTILIZATION_POLICY=force 是什么
在测试 HAMi 的 GPU core 限制时,经常会看到下面这个环境变量:
env: - name: GPU_CORE_UTILIZATION_POLICY value: "force"这个配置不是 Kubernetes 原生字段,而是 HAMi 容器侧配置项,主要给容器里的 HAMi-core 使用。HAMi 官方配置文档把GPU_CORE_UTILIZATION_POLICY放在Container Configs: Env下面,也就是说它属于容器运行时侧的环境变量,不是 Kubernetes 原生资源字段。
要理解这个参数,关键是要把 HAMi 的两个阶段分开看:
第一阶段:调度阶段 HAMi scheduler 根据 Pod 里申请的 nvidia.com/gpu、nvidia.com/gpumem、nvidia.com/gpucores 判断当前节点、当前 GPU 是否还有足够资源。 第二阶段:容器运行阶段 Pod 启动以后,容器里的 CUDA/NVML 调用会受到 HAMi-core 的影响,从而让容器看到被分配后的 GPU 资源视图,并对显存、GPU core 等资源进行运行时控制。先看 Pod 资源申请:
resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 2000 nvidia.com/gpucores: 30这几个字段首先会进入 HAMi 的调度逻辑。它表达的是:
这个 Pod 需要 1 个 GPU/vGPU 设备分配实例; 这个 Pod 需要 2000MB 左右显存; 这个 Pod 需要 30% GPU core 配额。所以在调度阶段,HAMi scheduler 会根据这些资源申请去判断:
这张 GPU 的剩余显存是否足够; 这张 GPU 的剩余 core 配额是否足够; 这个 Pod 是否可以放到这张 GPU 上。举个例子,假设一张 GPU 上已经有一个 Pod 申请了:
nvidia.com/gpumem: 3000 nvidia.com/gpucores: 70这时候再来一个 Pod 申请:
nvidia.com/gpumem: 3000 nvidia.com/gpucores: 40即使显存还够,也可能因为 GPU core 配额不够而无法调度。这个阶段的重点是:
nvidia.com/gpucores 用于调度层面的资源计算。 HAMi scheduler 会根据它判断这张 GPU 还能不能继续放这个 Pod。但是,调度成功不代表容器运行时一定会强制把 GPU 利用率压到30%以下。因为调度器只负责“把 Pod 放到哪里”,Pod 真正运行起来以后,就进入了 HAMi-core 的运行时控制阶段。
也就是说:
nvidia.com/gpucores: 30 首先表示:调度时我申请 30% GPU core 配额。 GPU_CORE_UTILIZATION_POLICY=force 表示:容器运行起来以后,HAMi-core 也要强制按照 nvidia.com/gpucores 的值去限制 GPU core utilization。这才是GPU_CORE_UTILIZATION_POLICY=force的重点。
12.1 不加 GPU_CORE_UTILIZATION_POLICY=force 时
如果只写:
resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 2000 nvidia.com/gpucores: 30而不写:
env: - name: GPU_CORE_UTILIZATION_POLICY value: "force"那么nvidia.com/gpucores: 30仍然会参与 HAMi 的调度计算。HAMi scheduler 仍然会认为这个 Pod 申请了 30% GPU core,并用这个值判断当前 GPU 是否还有足够的 core 配额。
但是容器真正运行 CUDA 程序时,是否强制把 GPU core utilization 限制在30%以下,就取决于 HAMi-core 的默认策略。
不加 GPU_CORE_UTILIZATION_POLICY=force 时, nvidia.com/gpucores 主要体现为调度层面的 core 配额申请。 HAMi scheduler 会用它判断资源够不够, 但容器运行阶段不一定适合用来强验证 core 限制效果。12.2 加上 GPU_CORE_UTILIZATION_POLICY=force 时
如果写成:
env: - name: GPU_CORE_UTILIZATION_POLICY value: "force" resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 2000 nvidia.com/gpucores: 30它的含义就是:
调度阶段: HAMi scheduler 按照 30% GPU core 计算这个 Pod 是否可以调度。 运行阶段: Pod 启动后,HAMi-core 也会根据 nvidia.com/gpucores 的值,对容器内 GPU core utilization 做限制。HAMi 官方配置文档中对force的说明是:限制 core utilization 低于nvidia.com/gpucores。
所以如果只是为了让 HAMi scheduler 做资源计算,写nvidia.com/gpucores就可以。
但如果是为了测试运行时 GPU core 限制效果,建议同时加上:
env: - name: GPU_CORE_UTILIZATION_POLICY value: "force"这样测试目标更明确:
既验证调度层面的 GPU core 配额计算; 也验证容器运行时 HAMi-core 对 GPU core utilization 的限制。12.3 default、force、disable 三种策略怎么理解
HAMi 官方配置中,GPU_CORE_UTILIZATION_POLICY有三个常见取值:
default 默认策略。 force 强制限制 core utilization,使其低于 nvidia.com/gpucores。 disable 任务执行期间忽略 nvidia.com/gpucores 设置的利用率限制。可以这样理解:
| 策略 | 调度阶段 | 容器运行阶段 |
|---|---|---|
default | nvidia.com/gpucores仍然参与调度计算 | 使用 HAMi-core 默认策略 |
force | nvidia.com/gpucores参与调度计算 | HAMi-core 强制限制 core utilization |
disable | nvidia.com/gpucores仍然可能参与调度计算 | 运行时忽略nvidia.com/gpucores的利用率限制 |
这里最容易混淆的是disable。如果写成:
env: - name: GPU_CORE_UTILIZATION_POLICY value: "disable"它主要影响的是容器运行时阶段,意思是运行任务时忽略nvidia.com/gpucores设置的利用率限制。但是不要简单理解成:
disable 后调度阶段也完全不看 nvidia.com/gpucores。调度阶段是否能放下这个 Pod,仍然取决于 HAMi scheduler 对 Pod 资源申请的计算。GPU_CORE_UTILIZATION_POLICY这个环境变量重点影响的是容器运行时 HAMi-core 的行为。
十三、测试 5:指定 GPU 型号
HAMi 支持通过 Pod annotation 指定要使用的 GPU 型号。官方配置文档中nvidia.com/use-gputype的含义是:如果设置了这个 annotation,那么 Pod 分配到的设备类型必须是这里指定的类型。先查看本机 GPU 型号:
nvidia-smi --query-gpu=name --format=csv,noheader示例:
NVIDIA GeForce RTX 3070 Ti Laptop GPU然后写 YAML:
apiVersion: v1 kind: Pod metadata: name: hami-use-gputype-3070 annotations: nvidia.com/use-gputype: "NVIDIA GeForce RTX 3070 Ti Laptop GPU" spec: restartPolicy: Never containers: - name: cuda image: nvidia/cuda:11.0.3-base-ubuntu18.04 command: ["bash", "-lc", "nvidia-smi && sleep 3600"] resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 2000 nvidia.com/gpucores: 30查看:
kubectl get pod hami-use-gputype-3070 kubectl exec -it hami-use-gputype-3070 -- nvidia-smi预期结果:
如果 annotation 里的 GPU 型号和 nvidia-smi 查出来的型号一致,Pod 可以 Running。十四、测试 6:指定 GPU UUID
HAMi 也支持通过nvidia.com/use-gpuuuid指定 GPU UUID。官方配置文档中说明,如果设置了nvidia.com/use-gpuuuid,Pod 分配到的设备必须属于指定 UUID 列表。先查看 UUID:
nvidia-smi --query-gpu=index,name,uuid,memory.total --format=csv,noheader示例:
0, NVIDIA GeForce RTX 3070 Ti Laptop GPU, GPU-998864a7-78d9-dbab-e122-4c37842ce7cf, 8192 MiB把 UUID 写进 Pod annotation:
apiVersion: v1 kind: Pod metadata: name: hami-use-gpuuuid annotations: nvidia.com/use-gpuuuid: "GPU-998864a7-78d9-dbab-e122-4c37842ce7cf" spec: restartPolicy: Never containers: - name: cuda image: nvidia/cuda:11.0.3-base-ubuntu18.04 command: ["bash", "-lc", "nvidia-smi && sleep 3600"] resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 2000 nvidia.com/gpucores: 30验证:
kubectl get pod hami-use-gpuuuid kubectl exec -it hami-use-gpuuuid -- nvidia-smi在单卡环境里,指定正确 UUID 的意义主要是验证 annotation 是否生效。如果是多卡机器,这个功能更有用,可以指定任务只能跑到某一张或某几张 GPU 上。
十五、总结
这次在单节点 Kubernetes 环境中部署了 HAMi,并基于一张 8G NVIDIA GPU 做了几个基础测试。
整体来看,HAMi 的核心作用就是让 GPU 不再只能以整卡方式分配给一个 Pod,而是可以按显存、core、设备型号、设备 UUID 等维度进行更细粒度的调度和限制。
本次测试中需要重点记住几件事:
1. 部署 HAMi 前,宿主机必须先能正常执行 nvidia-smi。 2. 容器运行时必须配置 NVIDIA Container Toolkit。 3. HAMi 节点需要打 gpu=on 标签。 4. scheduler.kubeScheduler.imageTag 要和 Kubernetes Server 版本匹配。 5. 单卡环境下看到 nvidia.com/gpu: 10 是 HAMi 默认切分数量,不是 10 张物理卡。 6. nvidia.com/gpumem 可以按固定显存大小申请 GPU。 7. nvidia.com/gpumem-percentage 可以按百分比申请显存。 8. nvidia.com/gpumem 和 nvidia.com/gpumem-percentage 不要同时使用。 9. nvidia.com/gpucores 表示申请 GPU core 比例,不是 CUDA Core 数量。 10. GPU_CORE_UTILIZATION_POLICY=force 更适合用来测试 GPU core 运行时限制效果。 11. nvidia.com/use-gputype 和 nvidia.com/use-gpuuuid 可以用来做指定型号或指定卡调度。 12. 单个 Pod 写 nvidia.com/gpu: 2,不是从一张卡里拿 2 份 vGPU;在单卡环境里会无法调度。对于单卡实验环境来说,HAMi 的价值很明显:一张 8G GPU 可以被多个测试 Pod 共享,不再因为一个小任务就独占整张卡。