在 Azure Kubernetes 服务 (AKS) 上使用 GPU 来处理计算密集型工作负载

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

本文帮助你在新的和现有 AKS 群集上预配具有可计划 GPU 的节点。

受支持的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。 对于以前的版本,默认通道为 None。 若要了解详细信息,请参阅 自动升级

  • AKS 不支持更新现有节点池以添加 GPU VM 大小。

注意

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

开始之前

  • 本文假设你有现有 AKS 群集。 如果没有群集,请使用 Azure CLIAzure PowerShellAzure 门户创建群集。
  • 需要安装 Azure CLI 2.72.2 或更高版本才能设置 --gpu-driver 字段。 运行 az --version 即可查找版本。 如果需要安装或升级,请参阅 安装 Azure CLI

获取群集的凭据

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

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

使用 NVIDIA GPU 的选项

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

注意

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

NVIDIA 设备插件安装

在 AKS 上使用 GPU 时,需要安装 NVIDIA 设备插件。 在某些情况下,会自动处理安装,例如使用 NVIDIA 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: gpu-resources
    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: nvcr.io/nvidia/k8s-device-plugin:v0.17.0
            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 驱动程序作为节点映像部署的一部分的维护和兼容性。

  1. 使用az aks nodepool add命令创建节点池,并将字段none设置为--gpu-driver跳过默认 GPU 驱动程序安装。

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

    在创建节点池期间将 --gpu-driver API 字段设置为 none 跳过自动 GPU 驱动程序安装。 不会更改任何现有节点。 可以将节点池缩放至零,然后进行备份,以使更改生效。

  2. 可以选择按照 以下步骤安装 NVIDIA 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 的负载

若要查看 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.microsoft.com/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. 使用 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
    

清理资源

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

    kubectl delete jobs samples-tf-mnist-demo
    

后续步骤