在 Azure Kubernetes 服务 (AKS) 上将 GPU 用于计算密集型工作负荷

图形处理单元 (GPU) 通常用于计算密集型工作负荷,例如图形和可视化工作负荷。 AKS 支持创建启用 GPU 的节点池,以在 Kubernetes 中运行这些计算密集型工作负荷。 有关可用的启用了 GPU 的 VM 的详细信息,请参阅 Azure 中 GPU 优化 VM 的大小。 对于 AKS 节点池,建议的最小大小为 Standard_NC6s_v3。

注意

启用 GPU 的 VM 包含专用硬件,这些硬件定价较高,其可用性受区域限制。 有关详细信息,请参阅定价工具和区域可用性

目前,使用支持 GPU 的节点池这一功能仅适用于 Linux 节点池。

“在 Azure Kubernetes 服务 (AKS) 上将 GPU 用于计算密集型工作负荷”以详细步骤的形式介绍了如何在 AKS 群集上运行 GPU 工作负荷,但需在 Azure 中国区更改某些配置。 例如,以下 docker 中心映像应该进行更改,以便使用 dockerhub.azk8s.cn

doc 中的原始映像 Azure 中国区支持的映像
k8s-device-plugin:1.11 dockerhub.azk8s.cn/nvidia/k8s-device-plugin:1.11
microsoft/samples-tf-mnist-demo:gpu dockerhub.azk8s.cn/microsoft/samples-tf-mnist-demo:gpu

下面以详细步骤的形式介绍了如何在 Azure 中国区 AKS 群集上运行 GPU 工作负荷:

开始之前

本文假定你拥有现有的 AKS 群集。 如果需要 AKS 群集,请参阅快速入门:使用 Azure CLI 部署 Azure Kubernetes 服务群集

还需安装并配置 Azure CLI 2.0.64 或更高版本。 运行 az --version 即可查找版本。 如果需要进行安装或升级,请参阅安装 Azure CLI

确保 Azure 订阅可以创建 NCv3 串行 VM(例如 Standard_NC6s_v3),否则,你可以提交一个支持票证,以便为 Azure 订阅启用该类型的 VM 大小。

创建 AKS 群集

如果需要可满足最低要求(启用了 GPU 的节点和 Kubernetes 版本 1.10 或更高版本)的 AKS 群集,请完成以下步骤。 如果已拥有满足这些要求的 AKS 群集,请跳至下一部分

首先,使用 az group create 命令为群集创建资源组。 以下示例在 chinaeast2 区域创建名为 myResourceGroup 的资源组:

az group create --name myResourceGroup --location chinaeast2

现在,使用 az aks create 命令创建 AKS 群集。 以下示例会创建具有一个节点(大小为 Standard_NC6s_v3)的群集:

az aks create \
    --resource-group myResourceGroup \
    --name myAKSCluster \
    --node-vm-size Standard_NC6s_v3 \
    --node-count 1

获取群集的凭据

使用 az aks get-credentials 命令获取 AKS 群集的凭据。 以下示例命令获取 myResourceGroup 资源组中 myAKSCluster 的凭据 。

az aks get-credentials --resource-group myResourceGroup --name myAKSCluster

添加 NVIDIA 设备插件

可通过一种选项添加 NVIDIA 设备插件:

  • 手动安装 NVIDIA 设备插件

手动安装 NVIDIA 设备插件

可为 NVIDIA 设备插件部署 DaemonSet。 此 DaemonSet 在会每个节点上运行 pod,以便为 GPU 提供所需驱动程序。

使用 [az aks nodepool add][az-aks-nodepool-add] 将节点池添加到群集。

az aks nodepool add \
    --resource-group myResourceGroup \
    --cluster-name myAKSCluster \
    --name gpunp \
    --node-count 1 \
    --node-vm-size Standard_NC6s_v3 \
    --node-taints sku=gpu:NoSchedule \
    --enable-cluster-autoscaler \
    --min-count 1 \
    --max-count 3

以上命令将名为 gpunp 的节点池添加到 myResourceGroup 资源组中的 myAKSCluster 。 该命令还将节点池中节点的 VM 大小设置为 Standard_NC6s_v3,启用群集自动缩放程序,将群集自动缩放程序配置为在节点池中保留最少一个节点和最多三个节点,并为节点池指定 sku=gpu:NoSchedule 排斥 。

注意

只能在创建节点池期间为节点池设置排斥和 VM 大小,但随时可以更新自动缩放程序设置。

使用 kubectl create namespace 命令创建命名空间,例如 gpu-resources:

kubectl create namespace gpu-resources

创建名为“nvidia-device-plugin-ds.yam”的文件并粘贴以下 YAML 清单 。 此清单作为 Kubernetes 项目的 NVIDIA 设备插件的一部分提供。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nvidia-device-plugin-daemonset
  namespace: gpu-resources
spec:
  selector:
    matchLabels:
      name: nvidia-device-plugin-ds
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      # Mark this pod as a critical add-on; when enabled, the critical add-on scheduler
      # reserves resources for critical add-on pods so that they can be rescheduled after
      # a failure.  This annotation works in tandem with the toleration below.
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ""
      labels:
        name: nvidia-device-plugin-ds
    spec:
      tolerations:
      # Allow this pod to be rescheduled while the node is in "critical add-ons only" mode.
      # This, along with the annotation above marks this pod as a critical add-on.
      - key: CriticalAddonsOnly
        operator: Exists
      - key: nvidia.com/gpu
        operator: Exists
        effect: NoSchedule
      - key: "sku"
        operator: "Equal"
        value: "gpu"
        effect: "NoSchedule"
      containers:
      - image: mcr.azk8s.cn/oss/nvidia/k8s-device-plugin:1.11
        name: nvidia-device-plugin-ctr
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
        volumeMounts:
          - name: device-plugin
            mountPath: /var/lib/kubelet/device-plugins
      volumes:
        - name: device-plugin
          hostPath:
            path: /var/lib/kubelet/device-plugins

使用 kubectl apply 创建 DaemonSet 并确认是否已成功创建 NVIDIA 设备插件,如以下示例输出中所示:

$ kubectl apply -f nvidia-device-plugin-ds.yaml

daemonset "nvidia-device-plugin" created

确认 GPU 是可计划的

创建 AKS 群集后,确认 GPU 在 Kubernetes 中是可计划的。 首先,使用 kubectl get nodes 命令列出群集中的节点:

$ kubectl get nodes

NAME                   STATUS   ROLES   AGE   VERSION
aks-gpunp-28993262-0   Ready    agent   13m   v1.20.7

现在,使用 kubectl describe node 命令确认 GPU 是可计划的。 在" 容量" 部分下,GPU 应列出为

以下精简示例显示了 GPU 在名为“aks-nodepool1-18821093-0”的节点上可用 :

$ kubectl describe node aks-gpunp-28993262-0

Name:               aks-gpunp-28993262-0
Roles:              agent
Labels:             accelerator=nvidia

[...]

Capacity:
[...]
 nvidia.com/gpu:                 1
[...]

安装 GPU 插件

kubectl create -f https://raw.githubusercontent.com/andyzhangx/demo/master/linux/gpu/nvidia-device-plugin-ds-mooncake.yaml

运行启用了 GPU 的工作负荷

若要查看 GPU 的运行情况,请通过相应的资源请求计划启用了 GPU 的工作负荷。 在此示例中,我们针对 MNIST 数据集运行一个 Tensorflow 作业。

创建名为“samples-tf-mnist-demo.yaml”的文件并粘贴以下 YAML 清单 。 以下作业清单包括资源限制 nvidia.com/gpu: 1

注意

如果在调用驱动程序时收到版本不匹配错误,例如,CUDA 驱动程序版本不足以支持 CUDA 运行时版本,请查看 NVIDIA 驱动程序矩阵兼容性图表 - https://docs.nvidia.com/deploy/cuda-compatibility/index.html

apiVersion: batch/v1
kind: Job
metadata:
  labels:
    app: samples-tf-mnist-demo
  name: samples-tf-mnist-demo
spec:
  template:
    metadata:
      labels:
        app: samples-tf-mnist-demo
    spec:
      containers:
      - name: samples-tf-mnist-demo
        image: mcr.azk8s.cn/azuredocs/samples-tf-mnist-demo:gpu
        args: ["--max_steps", "500"]
        imagePullPolicy: IfNotPresent
        resources:
          limits:
           nvidia.com/gpu: 1
      restartPolicy: OnFailure
      tolerations:
      - key: "sku"
        operator: "Equal"
        value: "gpu"
        effect: "NoSchedule"

使用 kubectl apply 命令运行该作业。 此命令分析清单文件并创建定义的 Kubernetes 对象:

kubectl apply -f samples-tf-mnist-demo.yaml

查看启用了 GPU 的工作负荷的状态和输出

使用 kubectl get jobs 命令和 参数监视作业 的进度。 先拉取映像并处理数据集可能需要几分钟时间。 当“COMPLETIONS”列显示“1/1”时,作业便已成功完成 。 使用 kubetctl --watchkubetctl --watch退出命令:

$ kubectl get jobs samples-tf-mnist-demo --watch

NAME                    COMPLETIONS   DURATION   AGE

samples-tf-mnist-demo   0/1           3m29s      3m29s
samples-tf-mnist-demo   1/1   3m10s   3m36s

若要查看启用了 GPU 的工作负荷的输出,首先请使用 kubectl get pods 命令获取 Pod 名称:

$ kubectl get pods --selector app=samples-tf-mnist-demo

NAME                          READY   STATUS      RESTARTS   AGE
samples-tf-mnist-demo-mtd44   0/1     Completed   0          4m39s

现在,使用 kubectl logs 命令查看 Pod 日志。 以下示例 pod 日志确认已发现适当的 GPU 设备,即 Tesla K80。 为自己的 pod 提供名称:

$ kubectl logs samples-tf-mnist-demo-smnr6

2019-05-16 16:08:31.258328: I tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA
2019-05-16 16:08:31.396846: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Found device 0 with properties: 
name: Tesla K80 major: 3 minor: 7 memoryClockRate(GHz): 0.8235
pciBusID: 2fd7:00:00.0
totalMemory: 11.17GiB freeMemory: 11.10GiB
2019-05-16 16:08:31.396886: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: Tesla K80, pci bus id: 2fd7:00:00.0, compute capability: 3.7)
2019-05-16 16:08:36.076962: I tensorflow/stream_executor/dso_loader.cc:139] successfully opened CUDA library libcupti.so.8.0 locally
Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting /tmp/tensorflow/input_data/train-images-idx3-ubyte.gz
Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Extracting /tmp/tensorflow/input_data/train-labels-idx1-ubyte.gz
Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Extracting /tmp/tensorflow/input_data/t10k-images-idx3-ubyte.gz
Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting /tmp/tensorflow/input_data/t10k-labels-idx1-ubyte.gz
Accuracy at step 0: 0.1081
Accuracy at step 10: 0.7457
Accuracy at step 20: 0.8233
Accuracy at step 30: 0.8644
Accuracy at step 40: 0.8848
Accuracy at step 50: 0.8889
Accuracy at step 60: 0.8898
Accuracy at step 70: 0.8979
Accuracy at step 80: 0.9087
Accuracy at step 90: 0.9099
Adding run metadata for 99
Accuracy at step 100: 0.9125
Accuracy at step 110: 0.9184
Accuracy at step 120: 0.922
Accuracy at step 130: 0.9161
Accuracy at step 140: 0.9219
Accuracy at step 150: 0.9151
Accuracy at step 160: 0.9199
Accuracy at step 170: 0.9305
Accuracy at step 180: 0.9251
Accuracy at step 190: 0.9258
Adding run metadata for 199
Accuracy at step 200: 0.9315
Accuracy at step 210: 0.9361
Accuracy at step 220: 0.9357
Accuracy at step 230: 0.9392
Accuracy at step 240: 0.9387
Accuracy at step 250: 0.9401
Accuracy at step 260: 0.9398
Accuracy at step 270: 0.9407
Accuracy at step 280: 0.9434
Accuracy at step 290: 0.9447
Adding run metadata for 299
Accuracy at step 300: 0.9463
Accuracy at step 310: 0.943
Accuracy at step 320: 0.9439
Accuracy at step 330: 0.943
Accuracy at step 340: 0.9457
Accuracy at step 350: 0.9497
Accuracy at step 360: 0.9481
Accuracy at step 370: 0.9466
Accuracy at step 380: 0.9514
Accuracy at step 390: 0.948
Adding run metadata for 399
Accuracy at step 400: 0.9469
Accuracy at step 410: 0.9489
Accuracy at step 420: 0.9529
Accuracy at step 430: 0.9507
Accuracy at step 440: 0.9504
Accuracy at step 450: 0.951
Accuracy at step 460: 0.9512
Accuracy at step 470: 0.9539
Accuracy at step 480: 0.9533
Accuracy at step 490: 0.9494
Adding run metadata for 499

使用容器见解监视 GPU 使用情况

包含 AKS 的容器见解可使用以下指标来监视 GPU 使用情况。

指标名称 指标维度(标记) 说明
containerGpuDutyCycle container.azm.ms/clusterId, container.azm.ms/clusterName, containerName, gpuId, gpuModel, gpuVendor 在刚过去的采样周期(60 秒)中,GPU 处于繁忙/积极处理容器的状态的时间百分比。 占空比是 1 到 100 之间的数字。
containerGpuLimits container.azm.ms/clusterId, container.azm.ms/clusterName, containerName 每个容器可以将限值指定为一个或多个 GPU。 不能请求或限制为 GPU 的一部分。
containerGpuRequests container.azm.ms/clusterId, container.azm.ms/clusterName, containerName 每个容器可以请求一个或多个 GPU。 不能请求或限制为 GPU 的一部分。
containerGpumemoryTotalBytes container.azm.ms/clusterId, container.azm.ms/clusterName, containerName, gpuId, gpuModel, gpuVendor 可用于特定容器的 GPU 内存量(以字节为单位)。
containerGpumemoryUsedBytes container.azm.ms/clusterId, container.azm.ms/clusterName, containerName, gpuId, gpuModel, gpuVendor 特定容器使用的 GPU 内存量(以字节为单位)。
nodeGpuAllocatable container.azm.ms/clusterId, container.azm.ms/clusterName, gpuVendor 节点中可供 Kubernetes 使用的 GPU 数。
nodeGpuCapacity container.azm.ms/clusterId, container.azm.ms/clusterName, gpuVendor 节点中的 GPU 总数。

清理资源

若要删除本文中创建的相关 Kubernetes 对象,请使用 kubectl delete job 命令,如下所示:

kubectl delete jobs samples-tf-mnist-demo

后续步骤

若要运行 Apache Spark 作业,请参阅在 AKS 上运行 Apache Spark 作业

有关在 Kubernetes 上运行机器学习 (ML) 工作负荷的更多信息,请参阅 Kubeflow 实验室

如果要详细了解如何配合使用 Azure Kubernetes 服务与 Azure 机器学习,请参阅以下文章: