Dimensionamento automático de cargas de trabalho de GPU no AKS usando métricas de DCGM e KEDA

Neste artigo, você aprenderá a dimensionar automaticamente cargas de trabalho de GPU em AKS (Serviço de Kubernetes do Azure) usando métricas de GPU coletadas pelo exportador do DCGM (Gerenciador de GPUs do Data Center) da NVIDIA. Essas métricas são expostas por meio do Azure Managed Prometheus e consumidas pelo Kubernetes Event-Driven Autoscaling (KEDA) para dimensionar automaticamente cargas de trabalho com base na utilização de GPU em tempo real. Essa solução ajuda a otimizar o uso de recursos de GPU e controlar os custos operacionais ajustando dinamicamente a escala do aplicativo em resposta à demanda de carga de trabalho.

Prerequisites

  • CLI do Azure versão 2.60.0 ou posterior. Execute az --version para encontrar a versão. Se precisar instalar ou atualizar, consulte Instalar CLI do Azure.
  • Helm versão 3.17.0 ou posterior instalada.
  • kubectl versão 1.28.9 ou posterior instalado.
  • Cota de GPU da NVIDIA em sua assinatura de Azure. Este exemplo usa a Standard_NC40ads_H100_v5 SKU, mas também há suporte para outras SKUs de VM NVIDIA H100.

Antes de continuar, verifique se o cluster do AKS está configurado com o seguinte:

Neste ponto, você deve ter:

Criar um novo dimensionador KEDA usando as métricas do Exportador de DCGM da NVIDIA

Para criar um dimensionador KEDA, você precisa de dois componentes:

  1. O endpoint de consulta do Prometheus.
  2. A identidade gerenciada atribuída ao usuário.

Obter o endpoint de consulta do Azure Managed Prometheus

  1. Você pode encontrar esse valor na seção Visão geral do workspace Azure Monitor anexado ao cluster do AKS no portal Azure.

    Captura de tela do endpoint de consulta do Managed Prometheus.

  2. Exporte o endpoint de consulta do Azure Managed Prometheus para uma variável de ambiente:

    export PROMETHEUS_QUERY_ENDPOINT="https://example.prometheus.monitor.azure.com"
    

Recuperar a identidade gerenciada atribuída pelo usuário

A Identidade Gerenciada Atribuída ao Usuário foi criada anteriormente seguindo as etapas de integração do KEDA. Se necessário, recarregue esse valor com o az identity show comando:

export USER_ASSIGNED_CLIENT_ID="$(az identity show --resource-group $RESOURCE_GROUP --name $USER_ASSIGNED_IDENTITY_NAME --query 'clientId' -o tsv)"

Criar o manifesto do escalador KEDA

Este manifesto cria o TriggerAuthentication e o ScaledObject para escalonamento automático com base na utilização de GPU medida pela métrica DCGM_FI_DEV_GPU_UTIL.

Note

Este exemplo usa a DCGM_FI_DEV_GPU_UTIL métrica, que mede a utilização da GPU. Outras métricas também estão disponíveis no exportador DCGM, de acordo com os requisitos da sua carga de trabalho. Para obter uma lista completa das métricas disponíveis, consulte a documentação do Exportador de DCGM da NVIDIA.

Campo Descrição
metricName Especifica a métrica de GPU a ser monitorada. DCGM_FI_DEV_GPU_UTIL relata a porcentagem de tempo em que a GPU está processando ativamente cargas de trabalho. Esse valor normalmente varia de 0 a 100.
query Consulta PromQL que calcula a utilização média da GPU em todos os pods da implantação my-gpu-workload. Isso garante que as decisões de dimensionamento sejam baseadas no uso geral da GPU, não em um único pod.
threshold O percentual médio de utilização da GPU alvo que aciona o escalonamento. Se a média exceder 5%, o dimensionador aumentará o número de réplicas de pod.
activationThreshold A utilização média mínima de GPU necessária para ativar o dimensionamento. Se a utilização estiver abaixo de 2%, ações de dimensionamento não ocorrerão, impedindo o dimensionamento desnecessário durante períodos de baixa atividade.
  1. Crie o seguinte manifesto KEDA:

    cat <<EOF > keda-gpu-scaler-prometheus.yaml
    apiVersion: keda.sh/v1alpha1
    kind: TriggerAuthentication
    metadata:
      name: azure-managed-prometheus-trigger-auth
    spec:
      podIdentity:
        provider: azure-workload
        identityId: ${USER_ASSIGNED_CLIENT_ID}
    ---
    apiVersion: keda.sh/v1alpha1
    kind: ScaledObject
    metadata:
      name: my-gpu-workload
    spec:
      scaleTargetRef:
        name: my-gpu-workload
      minReplicaCount: 1
      maxReplicaCount: 20
      triggers:
        - type: prometheus
          metadata:
            serverAddress: ${PROMETHEUS_QUERY_ENDPOINT}
            metricName: DCGM_FI_DEV_GPU_UTIL
            query: avg(DCGM_FI_DEV_GPU_UTIL{deployment="my-gpu-workload"})
            threshold: '5'
            activationThreshold: '2'
          authenticationRef:
            name: azure-managed-prometheus-trigger-auth
    EOF
    
  2. Aplique este manifesto usando o kubectl apply comando:

    kubectl apply -f keda-gpu-scaler-prometheus.yaml
    

Testar os novos recursos de dimensionamento

  1. Crie uma carga de trabalho de exemplo que consuma recursos de GPU no cluster do AKS. Você pode começar com o seguinte exemplo:

    cat <<EOF > my-gpu-workload.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-gpu-workload
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: my-gpu-workload
      template:
        metadata:
          labels:
            app: my-gpu-workload
        spec:
          tolerations:
            - key: "sku"
              operator: "Equal"
              value: "gpu"
              effect: "NoSchedule"
          containers:
            - name: my-gpu-workload
              image: mcr.microsoft.com/azuredocs/samples-tf-mnist-demo:gpu
              command: ["/bin/sh"]
              args: ["-c", "while true; do python /app/main.py --max_steps=500; done"]
              resources:
                limits:
                  nvidia.com/gpu: 1
    EOF
    
  2. Aplique este manifesto de implantação usando o kubectl apply comando:

    kubectl apply -f my-gpu-workload.yaml
    

    Note

    Se nenhum nó de GPU estiver disponível no momento, o pod permanecerá em um Pending estado até que um nó seja provisionado, mostrando a seguinte mensagem:

    Events:
      Type     Reason            Age    From                Message
      ----     ------            ----   ----                -------
      Warning  FailedScheduling  3m19s  default-scheduler   0/2 nodes are available: 2 Insufficient nvidia.com/gpu. preemption: 0/2 nodes are available: 2 No preemption victims found for incoming pod.
    

    O dimensionador automático de cluster eventualmente iniciará e provisionará um novo nó de GPU:

    Normal   TriggeredScaleUp  2m43s  cluster-autoscaler  pod triggered scale-up: [{aks-gpunp-36854149-vmss 0->1 (max: 2)}]
    

    Note

    Dependendo do tamanho da sua SKU de GPU provisionada, o provisionamento de nós pode levar vários minutos.

  3. Para verificar o progresso, verifique os eventos de HPA (Dimensionador Automático de Pod Horizontal) usando o kubectl describe comando:

    kubectl describe hpa my-gpu-workload
    

    A saída deve ser semelhante à seguinte:

    Conditions:
      Type            Status  Reason            Message
      ----            ------  ------            -------
      AbleToScale     True    ReadyForNewScale  recommended size matches current size
      ScalingActive   True    ValidMetricFound  the HPA successfully calculated a replica count from external metric s0-prometheus(&LabelSelector{MatchLabels:map[string]string{scaledobject.keda.sh/name: my-gpu-workload}})
      ScalingLimited  True    TooFewReplicas    the desired replica count is less than the minimum replica count
    
  4. Confirme se o nó da GPU foi adicionado e se o pod está em execução com o comando kubectl get:

    kubectl get nodes
    

    A saída deve ser semelhante à seguinte:

    NAME                                STATUS   ROLES    AGE     VERSION
    aks-gpunp-36854149-vmss000005       Ready    <none>   4m36s   v1.31.7
    aks-nodepool1-34179260-vmss000002   Ready    <none>   26h     v1.31.7
    aks-nodepool1-34179260-vmss000003   Ready    <none>   26h     v1.31.7
    

Reduzir verticalmente o pool de nós de GPU

Para reduzir o pool de nós de GPU, exclua a implantação da carga de trabalho usando o comando kubectl delete:

kubectl delete deployment my-gpu-workload

Note

Você pode configurar o pool de nós para reduzir para zero habilitando o dimensionador automático de cluster e definindo min-count como 0 no momento da criação do pool de nós. Por exemplo:

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

Próximas Etapas