在阿里云容器服务 ACK 上安装 HAMi
本文介绍在阿里云容器服务 Kubernetes 版(ACK)的 NVIDIA GPU 节点上安装 HAMi 所需的 ACK 配置。其他通用步骤见安装前提条件和通过 Helm 在线安装。
准备 GPU 节点池
创建节点池时,选择 GPU 实例规格。ACK 会在节点上安装 NVIDIA 驱动和 NVIDIA Container Toolkit,因此无需部署 GPU Operator,也无需安装 ACK 共享 GPU 调度组件。
ACK 还会将 containerd 默认 runc 运行时的可执行文件设置为 nvidia-container-runtime。所有容器都会使用 NVIDIA 运行时,HAMi 无需配置 RuntimeClass。可在 GPU 节点上运行以下命令确认:
grep -A1 'runtimes.runc.options' /etc/containerd/config.toml
输出应包含:
[plugins."io.containerd.cri.v1.runtime".containerd.runtimes.runc.options]
BinaryName = "nvidia-container-runtime"
由于 ACK 已将驱动直接安装在宿主机上(nvidia-smi 位于 /usr/bin,驱动库位于 /lib/x86_64-linux-gnu),因此需要将 HAMi 的 devicePlugin.nvidiaDriverRoot 设置为 /。配置方法见准备 HAMi values 文件。
禁用 ACK 自带的 NVIDIA Device Plugin
ACK 默认会安装 ack-nvidia-device-plugin 组件,即 DaemonSet kube-system/ack-nvidia-device-plugin。它运行在带有 ack.node.gpu.schedule=default 标签的节点上,ACK 会为 GPU 节点自动添加该标签。它与 HAMi 的 Device Plugin 通过同一个 kubelet socket 注册 nvidia.com/gpu,因此同一节点上只能有一个生效。两者同时运行的后果见 Pod 能看到整张 GPU。
可以使用以下任一方法。
方法一:为 GPU 节点添加标签
该方法只在带有标签的节点上禁用 ACK 自带的 Device Plugin。通过节点池管理这些标签:在 ACK 控制台编辑 GPU 节点池,添加以下节点标签:
| 键 | 值 | 作用 |
|---|---|---|
ack.node.gpu.schedule | disabled | 停止节点上 ACK 自带的 Device Plugin |
gpu | on | 让 HAMi 的 Device Plugin 选中该节点 |
disabled 这个取值的说明见 ACK 文档使用 DRA 调度 GPU。
如需使用 kubectl 为单个节点设置标签,只在新节点,或已排空且没有运行 GPU 负载的节点上执行:
kubectl label node <node-name> ack.node.gpu.schedule=disabled gpu=on --overwrite
检查节点标签,并确认 ACK 的 DaemonSet 不再调度到该节点:
kubectl get nodes -L gpu,ack.node.gpu.schedule
kubectl -n kube-system get ds ack-nvidia-device-plugin
NAME STATUS ROLES AGE VERSION GPU ACK.NODE.GPU.SCHEDULE
cn-hangzhou.10.207.93.6 Ready <none> 51m v1.36.2-aliyun.1 on disabled
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
ack-nvidia-device-plugin 0 0 0 0 0 ack.node.gpu.schedule=default 57m
方法二:卸载组件
该方法在整个集群中禁用 ACK 自带的 Device Plugin。在 ACK 控制台进入集群的组件管理页面,卸载 ack-nvidia-device-plugin 组件,然后为 GPU 节点添加 HAMi Device Plugin 使用的标签:
kubectl label node <node-name> gpu=on
将 HAMi 镜像复制到容器镜像服务
中国内地地域的节点无法访问 Docker Hub,因此 hami 和 kube-webhook-certgen 镜像会拉取失败。Chart 默认的 kube-scheduler 镜像来自 registry.cn-hangzhou.aliyuncs.com,可以正常拉取。
将这两个 Docker Hub 镜像复制到与集群同地域的阿里云容器镜像服务(ACR)实例中,并将 hami 和 kube-webhook-certgen 仓库设置为公开,使节点无需凭证即可拉取。可以使用以下任一版本:
- ACR 企业版可以从 Docker Hub 同步镜像。见创建企业版实例和通过制品订阅获取海外源镜像。
- ACR 个人版需要自行推送镜像。见使用个人版实例推送拉取镜像。
自行推送镜像时,在一台能访问 Docker Hub 的机器上登录实例的公网地址,然后复制镜像。--all 会复制镜像的所有平台:
skopeo login --username=<username> registry.cn-<个人版实例所在的地域>.aliyuncs.com
skopeo copy --all docker://docker.io/projecthami/hami:v2.10.0 \
docker://registry.cn-<个人版实例所在的地域>.aliyuncs.com/<namespace>/hami:v2.10.0
skopeo copy --all docker://docker.io/liangjw/kube-webhook-certgen:v1.1.1 \
docker://registry.cn-<个人版实例所在的地域>.aliyuncs.com/<namespace>/kube-webhook-certgen:v1.1.1
为 HAMi 调度器授予 DRA 资源访问权限
hami-scheduler Pod 中的 kube-scheduler 容器绑定了内置的 system:kube-scheduler ClusterRole。在 ACK 上,该 ClusterRole 没有 resource.k8s.io API 组的规则。kube-scheduler v1.36 会监听该组中的 DRA 资源,因此会输出以下错误,并且一直不会开始选主:
E1010 16:36:37.676013 1 reflector.go:227] "Failed to watch" err="failed to list *v1.ResourceClaim: resourceclaims.resource.k8s.io is forbidden: User \"system:serviceaccount:kube-system:hami-scheduler\" cannot list resource \"resourceclaims\" in API group \"resource.k8s.io\" at the cluster scope"
此时 hami-scheduler Pod 处于 Running 状态,但其中的 vgpu-scheduler-extender 容器会反复输出 Scheduler extender has not become leader yet,申请 vGPU 资源的 Pod 会一直处于 Pending 状态。
在安装 HAMi 之前,将以下内容保存为 hami-scheduler-dra-rbac.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: hami-scheduler-dra
rules:
- apiGroups: ["resource.k8s.io"]
resources: ["resourceclaims", "resourceslices", "deviceclasses"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: hami-scheduler-dra
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: hami-scheduler-dra
subjects:
- kind: ServiceAccount
name: hami-scheduler
namespace: kube-system
应用该文件:
kubectl apply -f hami-scheduler-dra-rbac.yaml
该绑定对应名为 hami 的 release 的 ServiceAccount。如果使用其他 release 名称,ServiceAccount 名称为 <release-name>-hami-scheduler。
准备 HAMi values 文件
将 HAMi 的镜像指向 ACR 中的仓库。使用实例的专有网络(VPC)地址,节点无需 NAT 网关即可访问。需要逐个设置镜像,因为 global.imageRegistry 也会修改 kube-scheduler 镜像的仓库地址。
将以下内容保存为 hami-ack-values.yaml,并替换 <个人版实例所在的地域> 和 <namespace>。使用企业版时,将 registry 替换为企业版实例的专有网络地址:
scheduler:
extender:
image:
registry: registry-vpc.cn-<个人版实例所在的地域>.aliyuncs.com
repository: <namespace>/hami
patch:
imageNew:
registry: registry-vpc.cn-<个人版实例所在的地域>.aliyuncs.com
repository: <namespace>/kube-webhook-certgen
devicePlugin:
nvidiaDriverRoot: /
image:
registry: registry-vpc.cn-<个人版实例所在的地域>.aliyuncs.com
repository: <namespace>/hami
monitor:
image:
registry: registry-vpc.cn-<个人版实例所在的地域>.aliyuncs.com
repository: <namespace>/hami
安装 HAMi
按通过 Helm 在线安装部署,并在安装命令中传入 values 文件:
helm install hami hami-charts/hami -n kube-system --version 2.10.0 -f hami-ack-values.yaml
hami-device-plugin 和 hami-scheduler 运行后,确认 HAMi 调度器已持有选主租约:
kubectl -n kube-system get lease hami-scheduler
NAME HOLDER AGE
hami-scheduler hami-scheduler-566cc89c9d-68f6n_8ed04e0d-8e3d-457a-a866-76fc43de07f5 38s
然后确认 HAMi 已注册 GPU。devicePlugin.deviceSplitCount 默认为 10,因此一张 GPU 会上报 10 个 nvidia.com/gpu:
kubectl get node <node-name> -o jsonpath='{.status.allocatable.nvidia\.com/gpu}{"\n"}'
10
故障排查
Pod 能看到整张 GPU
如果节点上 ACK 自带的 Device Plugin 与 HAMi 同时运行,最后注册的 Device Plugin 会接管 nvidia.com/gpu。当 ACK 的 Device Plugin 接管后,节点的 nvidia.com/gpu allocatable 会从 HAMi 上报的值(例如 10)降为物理 GPU 数量。新建的 Pod 可以正常启动,不会报错,但 HAMi 的限制不再生效。
恢复步骤:
-
按禁用 ACK 自带的 NVIDIA Device Plugin在该节点上禁用 ACK 的 Device Plugin,等待该节点上的
ack-nvidia-device-pluginPod 被删除。 -
重启 HAMi 的 Device Plugin,使其重新注册:
kubectl -n kube-system rollout restart ds/hami-device-pluginkubectl -n kube-system rollout status ds/hami-device-plugin -
确认节点的
nvidia.com/gpuallocatable 恢复为 HAMi 上报的值。 -
重建在 ACK 的 Device Plugin 生效期间启动的 Pod。
Device Plugin 日志中出现 NUMA 错误
在只有一个 NUMA 节点的 ecs.gn6i-c4g1.xlarge 实例上,hami-device-plugin 每次注册设备时都会输出以下错误:
E1010 16:47:54.742604 36382 register.go:168] "failed to get numa information from sysfs" idx=0
I1010 16:47:54.742629 36382 register.go:204] Registered device id=0, memory=15360MB, type=NVIDIA-Tesla T4, numa=0, health=true
HAMi 从 /sys/bus/pci/devices/<bus-id>/numa_node 读取 GPU 所属的 NUMA 节点。在该实例上,内核为包括 GPU 在内的所有 PCI 设备上报 -1。HAMi 无法确定 NUMA 节点,于是输出这条错误并回退为 numa=0,与实际拓扑一致。设备仍以 health=true 注册成功,GPU 负载运行正常。在单 NUMA 节点的实例上可以忽略这条错误。