Atribua dinamicamente dispositivos a cargas de trabalho com a DRA

Pode pedir dispositivos de forma flexível para as suas cargas de trabalho do Google Kubernetes Engine (GKE) usando a atribuição dinâmica de recursos (DRA). Este documento mostra como criar um ResourceClaimTemplate para pedir dispositivos e, em seguida, criar uma carga de trabalho para observar como o Kubernetes atribui os dispositivos de forma flexível aos seus pods.

Este documento destina-se a operadores de aplicações e engenheiros de dados que executam cargas de trabalho como IA/AA ou computação de elevado desempenho (HPC).

Acerca do pedido de dispositivos com DRA

Quando configura a sua infraestrutura do GKE para a DRA, os controladores da DRA nos seus nós criam objetos DeviceClass no cluster. Uma DeviceClass define uma categoria de dispositivos, como GPUs, que estão disponíveis para pedido para cargas de trabalho. O administrador da plataforma pode implementar opcionalmente DeviceClasses adicionais que limitam os dispositivos que pode pedir em cargas de trabalho específicas.

Para pedir dispositivos numa DeviceClass, crie um dos seguintes objetos:

  • ResourceClaim: um ResourceClaim permite que um Pod ou um utilizador peça recursos de hardware filtrando determinados parâmetros numa DeviceClass.
  • ResourceClaimTemplate: um ResourceClaimTemplate define um modelo que os pods podem usar para criar automaticamente novos ResourceClaims por pod.

Para mais informações sobre ResourceClaims e ResourceClaimTemplates, consulte Quando usar ResourceClaims e ResourceClaimTemplates.

Os exemplos nesta página usam um ResourceClaimTemplate básico para pedir a configuração do dispositivo especificada. Para mais informações sobre todos os campos que pode especificar, consulte a referência da API ResourceClaimTemplate.

Limitações

  • A administração de contas automática de nós não é suportada.
  • Os clusters do Autopilot não suportam o DRA.
  • Não pode usar as seguintes funcionalidades de partilha de GPU:
    • GPUs de partilha de tempo
    • GPUs de várias instâncias
    • Serviço multiprocessos (MPS)

Requisitos

Para usar o DRA, a versão do GKE tem de ser a 1.34 ou posterior.

Também deve conhecer os seguintes requisitos e limitações:

Antes de começar

Antes de começar, certifique-se de que realizou as seguintes tarefas:

  • Ative a API Google Kubernetes Engine.
  • Ative a API Google Kubernetes Engine
  • Se quiser usar a CLI gcloud para esta tarefa, instale-a e, em seguida, inicialize a CLI gcloud. Se instalou anteriormente a CLI gcloud, execute o comando gcloud components update para obter a versão mais recente. As versões anteriores da CLI gcloud podem não suportar a execução dos comandos neste documento.

Use o DRA para implementar cargas de trabalho

Para pedir a atribuição de dispositivos por Pod, crie um ResourceClaimTemplate com a configuração do dispositivo pedida, como GPUs de um tipo específico. Quando implementa uma carga de trabalho que faz referência ao ResourceClaimTemplate, o Kubernetes cria ResourceClaims para cada Pod na carga de trabalho com base no ResourceClaimTemplate. O Kubernetes atribui os recursos pedidos e agenda os pods nos nós correspondentes.

Para pedir dispositivos numa carga de trabalho com DRA, selecione uma das seguintes opções:

GPU

  1. Guarde o seguinte manifesto como claim-template.yaml:

    apiVersion: resource.k8s.io/v1
    kind: ResourceClaimTemplate
    metadata:
      name: gpu-claim-template
    spec:
      spec:
        devices:
          requests:
          - name: single-gpu
            exactly:
              deviceClassName: gpu.nvidia.com
              allocationMode: ExactCount
              count: 1
    
  2. Crie o ResourceClaimTemplate:

    kubectl create -f claim-template.yaml
    
  3. Para criar uma carga de trabalho que referencie o ResourceClaimTemplate, guarde o seguinte manifesto como dra-gpu-example.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: dra-gpu-example
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: dra-gpu-example
      template:
        metadata:
          labels:
            app: dra-gpu-example
        spec:
          containers:
          - name: ctr
            image: ubuntu:22.04
            command: ["bash", "-c"]
            args: ["echo $(nvidia-smi -L || echo Waiting...)"]
            resources:
              claims:
              - name: single-gpu
          resourceClaims:
          - name: single-gpu
            resourceClaimTemplateName: gpu-claim-template
          tolerations:
          - key: "nvidia.com/gpu"
            operator: "Exists"
            effect: "NoSchedule"
    
  4. Implemente a carga de trabalho:

    kubectl create -f dra-gpu-example.yaml
    

TPU

  1. Guarde o seguinte manifesto como claim-template.yaml:

    apiVersion: resource.k8s.io/v1
    kind: ResourceClaimTemplate
    metadata:
      name: tpu-claim-template
    spec:
      spec:
        devices:
          requests:
          - name: all-tpus
            exactly:
              deviceClassName: tpu.google.com
              allocationMode: All
    

    Este ResourceClaimTemplate pede que o GKE atribua um conjunto de nós de TPU inteiro a cada ResourceClaim.

  2. Crie o ResourceClaimTemplate:

    kubectl create -f claim-template.yaml
    
  3. Para criar uma carga de trabalho que referencie o ResourceClaimTemplate, guarde o seguinte manifesto como dra-tpu-example.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: dra-tpu-example
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: dra-tpu-example
      template:
        metadata:
          labels:
            app: dra-tpu-example
        spec:
          containers:
          - name: ctr
            image: ubuntu:22.04
            command:
              - /bin/sh
              - -c
              - |
                echo "Environment Variables:"
                env
                echo "Sleeping indefinitely..."
                sleep infinity
            resources:
              claims:
              - name: all-tpus
          resourceClaims:
          - name: all-tpus
            resourceClaimTemplateName: tpu-claim-template
          tolerations:
          - key: "google.com/tpu"
            operator: "Exists"
            effect: "NoSchedule"
    
  4. Implemente a carga de trabalho:

    kubectl create -f dra-tpu-example.yaml
    

Valide a atribuição de hardware

Pode verificar se o hardware foi atribuído às suas cargas de trabalho consultando o ResourceClaim ou os registos do seu pod. Para validar a atribuição de GPUs ou TPUs, selecione uma das seguintes opções:

GPU

  1. Obtenha o ResourceClaim associado à carga de trabalho que implementou:

    kubectl get resourceclaims
    

    O resultado é semelhante ao seguinte:

    NAME                                               STATE                AGE
    dra-gpu-example-64b75dc6b-x8bd6-single-gpu-jwwdh   allocated,reserved   9s
    
  2. Aceda a mais detalhes sobre o hardware atribuído ao Pod:

    kubectl describe resourceclaims RESOURCECLAIM
    

    Substitua RESOURCECLAIM pelo nome completo do ResourceClaim que obteve do resultado do passo anterior.

    O resultado é semelhante ao seguinte:

       Name:         dra-gpu-example-68f595d7dc-prv27-single-gpu-qgjq5
       Namespace:    default
       Labels:       <none>
       Annotations:  resource.kubernetes.io/pod-claim-name: single-gpu
       API Version:  resource.k8s.io/v1
       Kind:         ResourceClaim
       Metadata:
       # Multiple lines are omitted here.
       Spec:
         Devices:
           Requests:
             Exactly:
               Allocation Mode:    ExactCount
               Count:              1
               Device Class Name:  gpu.nvidia.com
             Name:                 single-gpu
       Status:
         Allocation:
           Devices:
             Results:
               Device:   gpu-0
               Driver:   gpu.nvidia.com
               Pool:     gke-cluster-1-dra-gpu-pool-b56c4961-7vnm
               Request:  single-gpu
           Node Selector:
             Node Selector Terms:
               Match Fields:
                 Key:       metadata.name
                 Operator:  In
                 Values:
                   gke-cluster-1-dra-gpu-pool-b56c4961-7vnm
         Reserved For:
           Name:      dra-gpu-example-68f595d7dc-prv27
           Resource:  pods
           UID:       e16c2813-08ef-411b-8d92-a72f27ebf5ef
       Events:        <none>
       ```
    
  3. Obtenha registos da carga de trabalho que implementou:

    kubectl logs deployment/dra-gpu-example --all-pods=true
    

    O resultado é semelhante ao seguinte:

    [pod/dra-gpu-example-64b75dc6b-x8bd6/ctr] GPU 0: Tesla T4 (UUID: GPU-2087ac7a-f781-8cd7-eb6b-b00943cc13ef)
    

    A saída destes passos mostra que o GKE atribuiu uma GPU ao contentor.

TPU

  1. Obtenha o ResourceClaim associado à carga de trabalho que implementou:

    kubectl get resourceclaims | grep dra-tpu-example
    

    O resultado é semelhante ao seguinte:

    NAME                                               STATE                AGE
    dra-tpu-example-64b75dc6b-x8bd6-all-tpus-jwwdh     allocated,reserved   9s
    
  2. Aceda a mais detalhes sobre o hardware atribuído ao Pod:

    kubectl describe resourceclaims RESOURCECLAIM -o yaml
    

    Substitua RESOURCECLAIM pelo nome completo do ResourceClaim que obteve do resultado do passo anterior.

    O resultado é semelhante ao seguinte:

    apiVersion: resource.k8s.io/v1beta1
    kind: ResourceClaim
    metadata:
      annotations:
        resource.kubernetes.io/pod-claim-name: all-tpus
      creationTimestamp: "2025-03-04T21:00:54Z"
      finalizers:
      - resource.kubernetes.io/delete-protection
      generateName: dra-tpu-example-59b8785697-k9kzd-all-gpus-
      name: dra-tpu-example-59b8785697-k9kzd-all-gpus-gnr7z
      namespace: default
      ownerReferences:
      - apiVersion: v1
        blockOwnerDeletion: true
        controller: true
        kind: Pod
        name: dra-tpu-example-59b8785697-k9kzd
        uid: c2f4fe66-9a73-4bd3-a574-4c3eea5fda3f
      resourceVersion: "12189603"
      uid: 279b5014-340b-4ef6-9dda-9fbf183fbb71
    spec:
      devices:
        requests:
        - allocationMode: All
          deviceClassName: tpu.google.com
          name: all-tpus
    status:
      allocation:
        devices:
          results:
          - adminAccess: null
            device: "0"
            driver: tpu.google.com
            pool: gke-tpu-2ec29193-bcc0
            request: all-tpus
          - adminAccess: null
            device: "1"
            driver: tpu.google.com
            pool: gke-tpu-2ec29193-bcc0
            request: all-tpus
          - adminAccess: null
            device: "2"
            driver: tpu.google.com
            pool: gke-tpu-2ec29193-bcc0
            request: all-tpus
          - adminAccess: null
            device: "3"
            driver: tpu.google.com
            pool: gke-tpu-2ec29193-bcc0
            request: all-tpus
          - adminAccess: null
            device: "4"
            driver: tpu.google.com
            pool: gke-tpu-2ec29193-bcc0
            request: all-tpus
          - adminAccess: null
            device: "5"
            driver: tpu.google.com
            pool: gke-tpu-2ec29193-bcc0
            request: all-tpus
          - adminAccess: null
            device: "6"
            driver: tpu.google.com
            pool: gke-tpu-2ec29193-bcc0
            request: all-tpus
          - adminAccess: null
            device: "7"
            driver: tpu.google.com
            pool: gke-tpu-2ec29193-bcc0
            request: all-tpus
        nodeSelector:
          nodeSelectorTerms:
          - matchFields:
            - key: metadata.name
              operator: In
              values:
              - gke-tpu-2ec29193-bcc0
      reservedFor:
      - name: dra-tpu-example-59b8785697-k9kzd
        resource: pods
        uid: c2f4fe66-9a73-4bd3-a574-4c3eea5fda3f
    
  3. Obtenha registos da carga de trabalho que implementou:

    kubectl logs deployment/dra-tpu-example --all-pods=true | grep "TPU"
    

    O resultado é semelhante ao seguinte:

    [pod/dra-tpu-example-59b8785697-tm2lc/ctr] TPU_CHIPS_PER_HOST_BOUNDS=2,4,1
    [pod/dra-tpu-example-59b8785697-tm2lc/ctr] TPU_TOPOLOGY_WRAP=false,false,false
    [pod/dra-tpu-example-59b8785697-tm2lc/ctr] TPU_SKIP_MDS_QUERY=true
    [pod/dra-tpu-example-59b8785697-tm2lc/ctr] TPU_RUNTIME_METRICS_PORTS=8431,8432,8433,8434,8435,8436,8437,8438
    [pod/dra-tpu-example-59b8785697-tm2lc/ctr] TPU_WORKER_ID=0
    [pod/dra-tpu-example-59b8785697-tm2lc/ctr] TPU_WORKER_HOSTNAMES=localhost
    [pod/dra-tpu-example-59b8785697-tm2lc/ctr] TPU_TOPOLOGY=2x4
    [pod/dra-tpu-example-59b8785697-tm2lc/ctr] TPU_ACCELERATOR_TYPE=v6e-8
    [pod/dra-tpu-example-59b8785697-tm2lc/ctr] TPU_HOST_BOUNDS=1,1,1
    [pod/dra-tpu-example-59b8785697-tm2lc/ctr] TPU_TOPOLOGY_ALT=false
    [pod/dra-tpu-example-59b8785697-tm2lc/ctr] TPU_DEVICE_0_RESOURCE_CLAIM=77e68f15-fa2f-4109-9a14-6c91da1a38d3
    

    O resultado destes passos indica que todas as TPUs num conjunto de nós foram atribuídas ao pod.

O que se segue?