Alocar dispositivos dinamicamente para cargas de trabalho com DRA

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

Este documento é destinado a operadores de aplicativos e engenheiros de dados que executam cargas de trabalho como IA/ML ou computação de alto desempenho (HPC).

Sobre como solicitar dispositivos com a DRA

Ao configurar a infraestrutura do GKE para DRA, os drivers de DRA nos nós criam objetos DeviceClass no cluster. Uma DeviceClass define uma categoria de dispositivos, como GPUs, que estão disponíveis para solicitação de cargas de trabalho. Um administrador de plataforma pode implantar DeviceClasses adicionais que limitam os dispositivos que você pode solicitar em cargas de trabalho específicas.

Para solicitar dispositivos em uma DeviceClass, crie um dos seguintes objetos:

  • ResourceClaim: um ResourceClaim permite que um pod ou um usuário solicite recursos de hardware filtrando determinados parâmetros em uma DeviceClass.
  • 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 solicitar a configuração de dispositivo especificada. Para mais informações sobre todos os campos que podem ser especificados, consulte a referência da API ResourceClaimTemplate.

Limitações

  • O provisionamento automático de nós não é compatível.
  • Os clusters do Autopilot não são compatíveis com a DRA.
  • Não é possível usar os seguintes recursos de compartilhamento de GPU:
    • GPUs de compartilhamento de tempo
    • GPUs com várias instâncias
    • Serviço de multiprocessamento (MPS)

Requisitos

Para usar o DRA, sua versão do GKE precisa ser a 1.34 ou mais recente.

Você também precisa conhecer os seguintes requisitos e limitações:

Antes de começar

Antes de começar, verifique se você realizou as tarefas a seguir:

  • Ativar a API Google Kubernetes Engine.
  • Ativar a API Google Kubernetes Engine
  • Se você quiser usar a CLI do Google Cloud para essa tarefa, instale e inicialize a gcloud CLI. Se você instalou a gcloud CLI anteriormente, instale a versão mais recente executando o comando gcloud components update. Talvez as versões anteriores da gcloud CLI não sejam compatíveis com a execução dos comandos neste documento.

Usar o DRA para implantar cargas de trabalho

Para solicitar a alocação de dispositivos por pod, crie um ResourceClaimTemplate que tenha a configuração de dispositivo solicitada, como GPUs de um tipo específico. Quando você implanta 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 aloca os recursos solicitados e programa os pods nos nós correspondentes.

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

GPU

  1. Salve 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 faça referência ao ResourceClaimTemplate, salve o manifesto a seguir 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. Implantar a carga de trabalho:

    kubectl create -f dra-gpu-example.yaml
    

TPU

  1. Salve 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
    

    Esse ResourceClaimTemplate solicita que o GKE aloque um pool de nós de TPU inteiro para cada ResourceClaim.

  2. Crie o ResourceClaimTemplate:

    kubectl create -f claim-template.yaml
    
  3. Para criar uma carga de trabalho que faça referência ao ResourceClaimTemplate, salve o manifesto a seguir 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. Implantar a carga de trabalho:

    kubectl create -f dra-tpu-example.yaml
    

Verificar a alocação de hardware

Para verificar se as cargas de trabalho receberam hardware, confira o ResourceClaim ou os registros do pod. Para verificar a alocação de GPUs ou TPUs, selecione uma das seguintes opções:

GPU

  1. Receba o ResourceClaim associado à carga de trabalho implantada:

    kubectl get resourceclaims
    

    O resultado será o seguinte:

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

    kubectl describe resourceclaims RESOURCECLAIM
    

    Substitua RESOURCECLAIM pelo nome completo do ResourceClaim que você recebeu da saída da etapa anterior.

    O resultado será o 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. Acesse os registros da carga de trabalho implantada:

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

    O resultado será o seguinte:

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

    A saída dessas etapas mostra que o GKE alocou uma GPU ao contêiner.

TPU

  1. Receba o ResourceClaim associado à carga de trabalho implantada:

    kubectl get resourceclaims | grep dra-tpu-example
    

    O resultado será o seguinte:

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

    kubectl describe resourceclaims RESOURCECLAIM -o yaml
    

    Substitua RESOURCECLAIM pelo nome completo do ResourceClaim que você recebeu da saída da etapa anterior.

    O resultado será o 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. Acesse os registros da carga de trabalho implantada:

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

    O resultado será o 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
    

    A saída dessas etapas indica que todas as TPUs em um pool de nós foram alocadas para o pod.

A seguir