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

图形处理单元 (GPU) 通常用于计算密集型工作负荷,例如图形和可视化工作负载。 AKS 支持启用 GPU 的 Linux 节点池来运行计算密集型 Kubernetes 工作负载。

受支持的启用了 GPU 的 VM

要查看受支持的启用了 GPU 的 VM,请参阅《Azure 中优化了 GPU 的 VM 大小。 对于 AKS 节点池,建议的最小大小为 Standard_NC6s_v3。 AKS 不支持 NVv4 系列(基于 AMD GPU)。

注意

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

限制

  • 如果使用 Azure Linux 已启用 GPU 的节点池,则不会应用自动安全修补程序。 有关节点 OS 升级通道的默认行为,请参阅当前的 AKS API 版本。

注意

对于 AKS API 版本 2023-06-01 或更高版本,节点 OS 升级的默认通道是 NodeImage。 对于以前的版本,默认通道是“”。 要了解详细信息,请参阅“自动升级”。

  • NVadsA10 v5 系列不是推荐用于 GPU VHD 的 SKU。
  • 不支持通过更新现有节点池来添加 GPU。

开始之前

本文帮助你在新的和现有 AKS 群集上预配具有可计划 GPU 的节点。 本文假定你拥有现有的 AKS 群集。 如果需要 AKS 群集,请参阅使用 Azure CLI 的 AKS 快速入门、使用 Azure PowerShell 的 AKS 快速入门或使用 Azure 门户的 AKS 快速入门。

注意

如果使用 Azure Linux GPU 节点池,则不会应用自动安全修补程序,并且群集的默认行为是“非托管”。 有关详细信息,请参阅 auto-upgrade

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

创建 AKS 群集

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

使用 NVIDIA GPU 的选项

使用 NVIDIA GPU 涉及各种 NVIDIA 软件组件(例如适用于 Kubernetes 的 NVIDIA 设备插件)的安装、GPU 驱动程序的安装,等等。

注意

默认情况下,Microsoft 会在节点映像部署过程中自动维护 NVidia 驱动程序的版本,并且 AKS 将会支持和管理它。 虽然 NVidia 驱动程序默认安装在支持 GPU 的节点上,但你需要安装设备插件。

NVIDIA 设备插件安装

在 AKS 上使用 GPU 时,需要安装 NVIDIA 设备插件。 在某些情况下,安装会自动进行,例如在使用 NVIDIA GPU OperatorAKS GPU 映像(预览版)时就是如此。 也可手动安装 NVIDIA 设备插件。

手动安装 NVIDIA 设备插件

可以为 NVIDIA 设备插件部署 DaemonSet,该插件会在每个节点上运行一个 Pod,为 GPU 提供所需的驱动程序。 这是为 Azure Linux 使用支持 GPU 的节点池时推荐使用的方法。

若要使用默认 OS SKU,请在不指定 OS SKU 的情况下创建节点池。 节点池是根据群集的 Kubernetes 版本为默认操作系统配置的。

  1. 使用 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,并使用参数配置以下节点池设置:

    • --node-vm-size:将节点池中节点的 VM 大小设置为 Standard_NC6s_v3
    • --node-taints:指定节点池上的 sku=gpu:NoSchedule 污点。
    • --enable-cluster-autoscaler:启用群集自动缩放程序。
    • --min-count:将群集自动缩放程序配置为在节点池中至少保留一个节点。
    • --max-count:将群集自动缩放程序配置为在节点池中至多保留三个节点。

    注意

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

  1. 使用 kubectl create namespace 命令创建命名空间。

    kubectl create namespace gpu-resources
    
  2. 创建名为 nvidia-device-plugin-ds.yaml 的文件,并粘贴适用于 Kubernetes 项目的 NVIDIA 设备插件中的以下 YAML 清单:

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: nvidia-device-plugin-daemonset
      namespace: kube-system
    spec:
      selector:
        matchLabels:
          name: nvidia-device-plugin-ds
      updateStrategy:
        type: RollingUpdate
      template:
        metadata:
          labels:
            name: nvidia-device-plugin-ds
        spec:
          tolerations:
          - key: "sku"
            operator: "Equal"
            value: "gpu"
            effect: "NoSchedule"
          # 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.
          # See https://kubernetes.io/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/
          priorityClassName: "system-node-critical"
          containers:
          - image: mcr.azk8s.cn/oss/nvidia/k8s-device-plugin:v0.14.1
            name: nvidia-device-plugin-ctr
            env:
              - name: FAIL_ON_INIT_ERROR
                value: "false"
            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
    
  3. 使用 kubectl apply 命令创建 DaemonSet 并确认已成功创建 NVIDIA 设备插件。

    kubectl apply -f nvidia-device-plugin-ds.yaml
    
  4. 成功安装 NVIDIA 设备插件后,就可以检查 GPU 是否可调度运行 GPU 工作负荷了。

跳过 GPU 驱动程序安装(预览版)

如果要控制 NVidia 驱动程序的安装或使用 NVIDIA GPU 运营商,则可以跳过默认的 GPU 驱动程序安装。 Microsoft 不支持,也不会在节点映像部署过程中管理 NVidia 驱动程序的维护和兼容性。

重要

AKS 预览功能是可选择启用的自助功能。 预览功能是“按现状”和“按可用”提供的,不包括在服务级别协议和有限保证中。 AKS 预览功能是由客户支持尽最大努力部分覆盖。 因此,这些功能并不适合用于生产。 有关详细信息,请参阅以下支持文章:

  1. 使用 az extension addaz extension update 命令注册或更新 aks-preview 扩展。

    # Register the aks-preview extension
    az extension add --name aks-preview
    
    # Update the aks-preview extension
    az extension update --name aks-preview
    
  2. 使用带有 --skip-gpu-driver-install 标志的 az aks nodepool add 命令创建节点池,以跳过自动 GPU 驱动程序安装。

    az aks nodepool add \
        --resource-group myResourceGroup \
        --cluster-name myAKSCluster \
        --name gpunp \
        --node-count 1 \
        --skip-gpu-driver-install \
        --node-vm-size Standard_NC6s_v3 \
        --enable-cluster-autoscaler \
        --min-count 1 \
        --max-count 3
    

    在节点池创建期间添加 --skip-gpu-driver-install 标志会跳过自动 GPU 驱动程序安装。 不会更改任何现有节点。 可以将节点池缩放至零,然后进行备份,以使更改生效。

将 NVIDIA GPU Operator 与 AKS 配合使用

NVIDIA GPU Operator 可自动管理预配 GPU 所需的所有 NVIDIA 软件组件,包括驱动程序安装、适用于 Kubernetes 的 NVIDIA 设备插件、NVIDIA 容器运行时等。 由于 GPU Operator 会处理这些组件,因此无需手动安装 NVIDIA 设备插件。 这也意味着不再需要在 AKS 上自动安装 GPU 驱动程序。

  1. 通过使用带 --skip-gpu-driver-installaz aks nodepool add 命令创建节点池,跳过自动 GPU 驱动程序安装。 在节点池创建期间添加 --skip-gpu-driver-install 标志会跳过自动 GPU 驱动程序安装。 不会更改任何现有节点。 可以将节点池缩放至零,然后进行备份,以使更改生效。

  2. 按照 NVIDIA 文档安装 GPU Operator

  3. 成功安装 GPU Operator 后,就可以检查 GPU 是否可调度运行 GPU 工作负荷了。

警告

不建议使用 AKS GPU 映像手动安装具有群集的 NVIDIA 设备插件守护程序集。

注意

使用 NVIDIA GPU Operator 在 SPOT 实例上部署时,还可能需要考虑其他一些因素。 请参考 https://github.com/NVIDIA/gpu-operator/issues/577

使用 AKS GPU 映像(预览版)

注意

AKS GPU 映像(预览版)将于 2025 年 1 月 10 日停用。 下面的自定义标头将不再可用,这意味着无法使用 AKS GPU 映像创建新的已启用 GPU 的节点池。 建议迁移到或使用默认 GPU 配置,而不是专用 GPU 映像,因为专用 GPU 映像不再受支持。 有关详细信息,请参阅 AKS 发行说明,或在 AKS 公共路线图中查看此停用公告。

AKS 提供了配置完全的 AKS 映像,其中包含适用于 Kubernetes 的 NVIDIA 设备插件。 AKS GPU 映像目前仅在 Ubuntu 18.04 上可用。

重要

AKS 预览功能是可选择启用的自助功能。 预览功能是“按现状”和“按可用”提供的,不包括在服务级别协议和有限保证中。 AKS 预览功能是由客户支持尽最大努力部分覆盖。 因此,这些功能并不适合用于生产。 有关详细信息,请参阅以下支持文章:

  1. 使用 az extension add 命令安装 aks-preview Azure CLI 扩展。

    az extension add --name aks-preview
    
  2. 使用 az extension update 命令更新到扩展的最新版本。

    az extension update --name aks-preview
    
  3. 使用 az feature register 命令注册 GPUDedicatedVHDPreview 功能标志。

    az feature register --namespace "Microsoft.ContainerService" --name "GPUDedicatedVHDPreview"
    

    状态显示为“已注册”需要几分钟时间

  4. 使用 az feature show 命令验证注册状态。

    az feature show --namespace "Microsoft.ContainerService" --name "GPUDedicatedVHDPreview"
    
  5. 当状态反映为已注册时,使用 az provider register 命令刷新 Microsoft.ContainerService 资源提供程序的注册。

    az provider register --namespace Microsoft.ContainerService
    

    将群集更新为使用 AKS GPU 映像后,可以将 GPU 节点的节点池添加到你的群集。

  6. 使用 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 \
        --aks-custom-headers UseGPUDedicatedVHD=true \
        --enable-cluster-autoscaler \
        --min-count 1 \
        --max-count 3
    

    前面的示例命令将名为 gpunp 的节点池添加到 myResourceGroup 中的 myAKSCluster,并使用参数配置以下节点池设置:

    • --node-vm-size:将节点池中节点的 VM 大小设置为 Standard_NC6s_v3
    • --node-taints:指定节点池上的 sku=gpu:NoSchedule 污点。
    • --aks-custom-headers:指定专用 AKS GPU 映像 UseGPUDedicatedVHD=true。 如果你的 GPU SKU 需要第二代 VM,请改为使用 --aks-custom-headers UseGPUDedicatedVHD=true,usegen2vm=true
    • --enable-cluster-autoscaler:启用群集自动缩放程序。
    • --min-count:将群集自动缩放程序配置为在节点池中至少保留一个节点。
    • --max-count:将群集自动缩放程序配置为在节点池中至多保留三个节点。

    注意

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

  7. 成功地使用 GPU 映像创建节点池后,就可以检查 GPU 是否可调度运行 GPU 工作负荷了。

确认 GPU 是可计划的

创建完群集后,确认 GPU 在 Kubernetes 中是可计划的。

  1. 使用 kubectl get nodes 命令列出群集中的节点。

    kubectl get nodes
    

    输出应类似于以下示例输出:

    NAME                   STATUS   ROLES   AGE   VERSION
    aks-gpunp-28993262-0   Ready    agent   13m   v1.20.7
    
  2. 使用 kubectl describe node 命令确认 GPU 可计划。

    kubectl describe node aks-gpunp-28993262-0
    

    在“容量”部分下,GPU 应列为 nvidia.com/gpu: 1。 输出应该类似于以下简洁示例输出:

    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 作业。

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

    注意

    如果在调用驱动程序时收到版本不匹配错误,例如,CUDA 驱动程序版本不足以支持 CUDA 运行时版本,请查看 NVIDIA 驱动程序矩阵兼容性图表

    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"
    
  2. 使用 kubectl apply 命令运行作业,该命令会分析清单文件并创建定义的 Kubernetes 对象。

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

查看启用了 GPU 的工作负载的状态

  1. kubectl get jobs 命令与 --watch 标志配合使用,以监视作业的进度。 先拉取映像并处理数据集可能需要几分钟时间。

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

    COMPLETIONS 列显示 1/1 时,作业已成功完成,如以下示例输出所示:

    NAME                    COMPLETIONS   DURATION   AGE
    
    samples-tf-mnist-demo   0/1           3m29s      3m29s
    samples-tf-mnist-demo   1/1   3m10s   3m36s
    
  2. 使用 Ctrl-C 退出 kubectl --watch 进程。

  3. 使用 kubectl get pods 命令获取 pod 的名称。

    kubectl get pods --selector app=samples-tf-mnist-demo
    
  4. 使用 kubectl logs 命令查看启用了 GPU 的工作负载的输出。

    kubectl logs samples-tf-mnist-demo-smnr6
    

    Pod 日志的以下精简示例输出确认已发现相应的 GPU 设备 Tesla K80

    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
    [...]
    Adding run metadata for 499
    

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

适用于 AKS 的容器见解监视以下 GPU 使用情况指标:

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

清理资源

  • 使用 kubectl delete job 命令移除在本文中创建的相关 Kubernetes 对象。

    kubectl delete jobs samples-tf-mnist-demo
    

后续步骤