Esegui il deployment di GPU per carichi di lavoro batch e di AI con Dynamic Workload Scheduler


Questa pagina mostra come ottimizzare l'ottenibilità delle GPU per i workload AI e batch su larga scala con GPU utilizzando Dynamic Workload Scheduler e ProvisioningRequest.

Best practice:

Utilizza lo scheduler dei workload dinamici per i carichi di lavoro batch e di AI su larga scala che possono essere eseguiti durante le ore di punta con condizioni di gestione della capacità GPU definite. Ciò può includere carichi di lavoro come l'addestramento di modelli di deep learning o una simulazione in cui viene creato contemporaneamente un numero elevato di GPU.

Per eseguire carichi di lavoro GPU in Google Kubernetes Engine (GKE) senza il pianificatore dei carichi di lavoro dinamico, consulta Eseguire GPU nei pool di nodi GKE Standard.

Quando utilizzare Dynamic Workload Scheduler

Ti consigliamo di utilizzare Dynamic Workload Scheduler se i tuoi carichi di lavoro soddisfano tutte le seguenti condizioni:

  • Richiedi GPU per eseguire i tuoi carichi di lavoro.
  • La tua capacità GPU riservata è limitata o non esiste e vuoi migliorare la disponibilità delle risorse GPU.
  • Il tuo workload è flessibile in termini di tempo e il tuo caso d'uso può permettersi di attendere per ottenere tutta la capacità richiesta, ad esempio quando GKE alloca le risorse GPU al di fuori delle ore di punta.
  • Il carico di lavoro richiede più nodi e non può iniziare a funzionare fino a quando non sono stati eseguiti il provisioning e la preparazione di tutti i nodi GPU contemporaneamente (ad esempio, l'addestramento distribuito del machine learning).

Prima di iniziare

Prima di iniziare, assicurati di aver eseguito le seguenti operazioni:

  • Attiva l'API Google Kubernetes Engine.
  • Attiva l'API Google Kubernetes Engine
  • Se vuoi utilizzare Google Cloud CLI per questa attività, installa e poi inizializza gcloud CLI. Se hai già installato gcloud CLI, ottieni la versione più recente eseguendo gcloud components update.

Utilizzare i pool di nodi con Dynamic Workload Scheduler

Questa sezione si applica solo ai cluster standard.

Puoi utilizzare uno dei seguenti tre metodi per indicare che Dinamic Workload Scheduler può funzionare con pool di nodi specifici nel tuo cluster:

Crea un node pool

Crea un pool di nodi con Dynamic Workload Scheduler abilitato utilizzando gcloud CLI:

gcloud container node-pools create NODEPOOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=LOCATION \
     --enable-queued-provisioning \
    --accelerator type=GPU_TYPE,count=AMOUNT,gpu-driver-version=DRIVER_VERSION \
    --machine-type=MACHINE_TYPE \
    --enable-autoscaling  \
    --num-nodes=0   \
    --total-max-nodes TOTAL_MAX_NODES  \
    --location-policy=ANY  \
    --reservation-affinity=none  \
    --no-enable-autorepair

Sostituisci quanto segue:

  • NODEPOOL_NAME: il nome scelto per il pool di nodi.
  • CLUSTER_NAME: il nome del cluster.
  • LOCATION: la regione Compute Engine del cluster, ad esempio us-central1.
  • GPU_TYPE: il tipo di GPU.
  • AMOUNT: il numero di GPU da collegare ai nodi nel pool di nodi.
  • DRIVER_VERSION: la versione del driver NVIDIA da installare. Può essere uno dei seguenti:
    • default: installa la versione predefinita del driver per la tua versione GKE.
    • latest: installa la versione del driver più recente disponibile per la tua versione di GKE. Disponibile solo per i nodi che utilizzano Container-Optimized OS.
  • TOTAL_MAX_NODES: il numero massimo di nodi da scalare automaticamente per l'intero pool di nodi.
  • MACHINE_TYPE: il tipo di macchina Compute Engine per i tuoi nodi.

    Best practice:

    Utilizza un tipo di macchina ottimizzato per l'acceleratore per migliorare le prestazioni e l'efficienza per i carichi di lavoro di AI/ML.

Se vuoi, puoi utilizzare i seguenti flag:

  • --no-enable-autoupgrade: consigliato. Disattiva gli upgrade automatici dei nodi. Supportato solo nei cluster GKE non registrati in un canale di rilascio. Per scoprire di più, consulta Disattivare gli upgrade automatici dei nodi per un pool di nodi esistente.
  • --node-locations=COMPUTE_ZONES: l'elenco separato da virgole di una o più zone in cui GKE crea i nodi GPU. Le zone devono trovarsi nella stessa regione del cluster. Scegli le zone con GPU disponibili.
  • --enable-gvnic: questo flag attiva gVNIC nei pool di nodi GPU per aumentare la velocità del traffico di rete.

Questo comando crea un pool di nodi con la seguente configurazione:

  • GKE consente il provisioning in coda e la scalabilità automatica dei cluster.
  • Il pool di nodi non ha inizialmente nodi.
  • Il flag --enable-queued-provisioning attiva Dynamic Workload Scheduler e aggiunge il taint cloud.google.com/gke-queued al pool di nodi.
  • I flag --no-enable-autorepair e --no-enable-autoupgrade disattivano la riparazione e l'upgrade automatici dei nodi, il che potrebbe interrompere i carichi di lavoro in esecuzione sui nodi riparati o sottoposti ad upgrade. Puoi disattivare l'upgrade automatico dei nodi solo su cluster non registrati in un canale di rilascio.

Aggiorna il pool di nodi esistente e abilita Dynamic Workload Scheduler

Abilita Dynamic Workload Scheduler per un pool di nodi esistente. Esamina i prerequisiti per configurare correttamente il pool di nodi.

Prerequisiti

  • Assicurati di creare un pool di nodi con il flag --reservation-affinity=none. Questo flag è necessario per attivare in un secondo momento il programmatore del carico di lavoro dinamico, poiché non puoi modificare l'affinità di prenotazione dopo la creazione del pool di nodi.

  • Assicurati di mantenere almeno un pool di nodi senza la gestione di Dynamic Workload Scheduler abilitata per il corretto funzionamento del cluster.

  • Assicurati che il pool di nodi sia vuoto. Puoi ridimensionare il node pool in modo che non abbia nodi.

  • Assicurati che la scalabilità automatica sia abilitata e configurata correttamente.

  • Assicurati che le riparazioni automatiche siano disattivate.

Abilita Dynamic Workload Scheduler per il pool di nodi esistente

Puoi abilitare Dynamic Workload Scheduler per un pool di nodi esistente utilizzando gcloud CLI:

gcloud container node-pools update NODEPOOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=LOCATION \
     --enable-queued-provisioning

Sostituisci quanto segue:

  • NODEPOOL_NAME: il nome del pool di nodi scelto.
  • CLUSTER_NAME: il nome del cluster.
  • LOCATION: la regione Compute Engine del cluster, ad esempio us-central1.

Questo comando di aggiornamento del pool di nodi comporta le seguenti modifiche alla configurazione:

  • Il flag --enable-queued-provisioning attiva Dynamic Workload Scheduler e aggiunge il taint cloud.google.com/gke-queued al pool di nodi.

Se vuoi, puoi anche aggiornare le seguenti impostazioni del pool di nodi:

Best practice:

Quando utilizzi Dynamic Workload Scheduler:

Abilita il provisioning automatico dei nodi per creare pool di nodi per Dynamic Workload Scheduler

Puoi utilizzare il provisioning automatico dei nodi per gestire i pool di nodi per Dynamic Workload Scheduler per i cluster che eseguono la versione 1.29.2-gke.1553000 o successive. Quando attivi il provisioning automatico dei nodi e Dynamic Workload Scheduler, GKE crea pool di nodi con le risorse richieste per il carico di lavoro associato.

Per attivare il provisioning automatico dei nodi, prendi in considerazione le seguenti impostazioni e completa i passaggi descritti in Configurare i limiti GPU:

Esegui i carichi di lavoro batch e AI con Dynamic Workload Scheduler

Per eseguire carichi di lavoro batch con Dynamic Workload Scheduler, utilizza una delle seguenti configurazioni:

  • Dynamic Workload Scheduler per i job con Kueue: puoi utilizzare Dynamic Workload Scheduler con Kueue per automatizzare il ciclo di vita delle richieste di Dynamic Workload Scheduler. Kueue implementa la coda dei job e osserva lo stato di Dynamic Workload Scheduler. Kueue decide quando i job devono attendere e quando devono iniziare, in base a quote e a una gerarchia per condividere equamente le risorse tra i team.

  • Dynamic Workload Scheduler per i job senza Kueue: puoi utilizzare Dynamic Workload Scheduler senza Kueue se utilizzi la tua piattaforma o i tuoi strumenti di pianificazione batch interni. Osserva e annulla manualmente le richieste di Dynamic Workload Scheduler.

Best practice:

Utilizza Kueue per eseguire i carichi di lavoro batch e AI con Dynamic Workload Scheduler.

Dynamic Workload Scheduler per i job con Kueue

Le seguenti sezioni mostrano come configurare Dynamic Workload Scheduler per i job con Kueue. Puoi configurare le seguenti configurazioni comuni dei pool di nodi:

  • Configurazione del pool di nodi di Dynamic Workload Scheduler.
  • Prenotazione e configurazione del pool di nodi Dynamic Workload Scheduler.

Questa sezione utilizza i sample nella directory dws-examples del repository ai-on-gke. Abbiamo pubblicato i sample nella directory dws-examples in base alla licenza Apache2.

Per installare Kueue devi disporre delle autorizzazioni di amministratore. Per ottenerli, assicurati di disporre del ruolo IAM roles/container.admin. Per scoprire di più sui ruoli IAM di GKE, consulta la guida alla creazione di criteri di autorizzazione IAM.

prepara l'ambiente

  1. In Cloud Shell, esegui questo comando:

    git clone https://github.com/GoogleCloudPlatform/ai-on-gke
    cd ai-on-gke/tutorials-and-examples/workflow-orchestration/dws-examples
    
  2. Installa la versione più recente di Kueue nel cluster:

    VERSION=v0.7.0
    kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/manifests.yaml
    

Se utilizzi Kueue in una versione precedente a 0.7.0, modifica la configurazione del gate delle funzionalità di Kueue impostando il gate delle funzionalità ProvisioningACC su true. Consulta la sezione Cancelli delle funzionalità di Kueue per una spiegazione più dettagliata e i valori predefiniti dei cancelli. Per scoprire di più sull'installazione di Kueue, consulta Installazione.

Crea le risorse Kueue per la configurazione solo del pool di nodi Dynamic Workload Scheduler

Con il seguente manifest, crei una coda a livello di cluster denominata dws-cluster-queue e lo spazio dei nomi LocalQueue denominato dws-local-queue. I job che fanno riferimento alla coda dws-cluster-queue in questo spazio dei nomi utilizzano Dynamic Workload Scheduler per ottenere le risorse GPU.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: "default-flavor"
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: AdmissionCheck
metadata:
  name: dws-prov
spec:
  controllerName: kueue.x-k8s.io/provisioning-request
  parameters:
    apiGroup: kueue.x-k8s.io
    kind: ProvisioningRequestConfig
    name: dws-config
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ProvisioningRequestConfig
metadata:
  name: dws-config
spec:
  provisioningClassName: queued-provisioning.gke.io
  managedResources:
  - nvidia.com/gpu
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
  name: "dws-cluster-queue"
spec:
  namespaceSelector: {} 
  resourceGroups:
  - coveredResources: ["cpu", "memory", "nvidia.com/gpu", "ephemeral-storage"]
    flavors:
    - name: "default-flavor"
      resources:
      - name: "cpu"
        nominalQuota: 10000  # Infinite quota.
      - name: "memory"
        nominalQuota: 10000Gi # Infinite quota.
      - name: "nvidia.com/gpu"
        nominalQuota: 10000  # Infinite quota.
      - name: "ephemeral-storage"
        nominalQuota: 10000Ti # Infinite quota.
  admissionChecks:
  - dws-prov
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  namespace: "default"
  name: "dws-local-queue"
spec:
  clusterQueue: "dws-cluster-queue"
---

La coda di questo cluster ha limiti di quota elevati ed è abilitata solo l'integrazione di Dynamic Workload Scheduler. Per scoprire di più sulle API Kueue e su come impostare i limiti, consulta Concetti di Kueue.

Esegui il deployment di LocalQueue:

kubectl create -f ./dws-queues.yaml

L'output è simile al seguente:

resourceflavor.kueue.x-k8s.io/default-flavor created
admissioncheck.kueue.x-k8s.io/dws-prov created
provisioningrequestconfig.kueue.x-k8s.io/dws-config created
clusterqueue.kueue.x-k8s.io/dws-cluster-queue created
localqueue.kueue.x-k8s.io/dws-local-queue created

Se vuoi eseguire job che utilizzano il programmatore del carico di lavoro dinamico in altri spazi dei nomi, puoi creare altri LocalQueues utilizzando il modello precedente.

Esegui il job

Nel seguente manifest, il job di esempio utilizza Dynamic Workload Scheduler:

apiVersion: batch/v1
kind: Job
metadata:
  name: sample-job
  namespace: default
  labels:
    kueue.x-k8s.io/queue-name: dws-local-queue
  annotations:
    provreq.kueue.x-k8s.io/maxRunDurationSeconds: "600"
spec:
  parallelism: 1
  completions: 1
  suspend: true
  template:
    spec:
      nodeSelector:
        cloud.google.com/gke-nodepool: NODEPOOL_NAME
      tolerations:
      - key: "nvidia.com/gpu"
        operator: "Exists"
        effect: "NoSchedule"
      containers:
      - name: dummy-job
        image: gcr.io/k8s-staging-perf-tests/sleep:v0.0.3
        args: ["120s"]
        resources:
          requests:
            cpu: "100m"
            memory: "100Mi"
            nvidia.com/gpu: 1
          limits:
            cpu: "100m"
            memory: "100Mi"
            nvidia.com/gpu: 1
      restartPolicy: Never

Questo manifest include i seguenti campi pertinenti per la configurazione di Dynamic Workload Scheduler:

  • L'etichetta kueue.x-k8s.io/queue-name: dws-local-queue indica a GKE che Kueue è responsabile dell'orchestrazione del job. Questa etichetta definisce anche la coda in cui è in coda il job.
  • Il flag suspend: true indica a GKE di creare la risorsa Job, ma di non pianificare ancora i pod. Kueue modifica questo flag in false quando i nodi sono pronti per l'esecuzione del job.
  • nodeSelector indica a GKE di pianificare il compito solo nel pool di nodi specificato. Il valore deve corrispondere a NODEPOOL_NAME, il nome del pool di nodi con il provisioning in coda abilitato.
  1. Esegui il job:

    kubectl create -f ./job.yaml
    

    L'output è simile al seguente:

    job.batch/sample-job created
    
  2. Controlla lo stato del tuo job:

    kubectl describe job sample-job
    

    L'output è simile al seguente:

    Events:
      Type    Reason            Age    From                        Message
      ----    ------            ----   ----                        -------
      Normal  Suspended         5m17s  job-controller              Job suspended
      Normal  CreatedWorkload   5m17s  batch/job-kueue-controller  Created Workload: default/job-sample-job-7f173
      Normal  Started           3m27s  batch/job-kueue-controller  Admitted by clusterQueue dws-cluster-queue
      Normal  SuccessfulCreate  3m27s  job-controller              Created pod: sample-job-9qsfd
      Normal  Resumed           3m27s  job-controller              Job resumed
      Normal  Completed         12s    job-controller              Job completed
    

Dynamic Workload Scheduler con integrazione di Kueue supporta anche altri tipi di carichi di lavoro disponibili nell'ecosistema open source, ad esempio:

  • RayJob
  • JobSet versione 0.5.2 o successive
  • Kubeflow MPIJob, TFJob, PyTorchJob.
  • Pod Kubernetes utilizzati di frequente dagli orchestratori dei flussi di lavoro
  • Mini cluster Flux

Per scoprire di più su questo supporto, consulta Utente batch di Kueue.

Crea le risorse Kueue per la configurazione del pool di nodi di prenotazione e Dynamic Workload Scheduler

Con il seguente manifest, crei due ResourceFlavors associati a due diversi node pool: reservation-nodepool e dws-nodepool. I nomi di questi pool di nodi sono solo esempi. Modifica questi nomi in base alla configurazione del pool di nodi. Inoltre, con la configurazione ClusterQueue, i job in arrivo tentano di utilizzare reservation-nodepool e, se non è presente alcuna capacità, questi job utilizzano Dynamic Workload Scheduler per ottenere le risorse GPU.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: "reservation"
spec:
  nodeLabels:
    cloud.google.com/gke-nodepool: "reservation-nodepool" # placeholder value
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: "dws"
spec:
  nodeLabels:
    cloud.google.com/gke-nodepool: "dws-nodepool" # placeholder value
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
  name: "cluster-queue"
spec:
  namespaceSelector: {} # match all.
  resourceGroups:
  - coveredResources: ["cpu", "memory", "nvidia.com/gpu"]
    flavors:
    - name: "reservation" # first we try reservation
      resources:
      - name: "cpu"
        nominalQuota: 9
      - name: "memory"
        nominalQuota: 36Gi
      - name: "nvidia.com/gpu"
        nominalQuota: 9
    - name: "dws"         # if reservation is saturated we try dws
      resources:
      - name: "cpu"
        nominalQuota: 10000   # Infinite quota.
      - name: "memory"
        nominalQuota: 10000Gi # Infinite quota.
      - name: "nvidia.com/gpu"
        nominalQuota: 10000   # Infinite quota.
  admissionChecksStrategy:
    admissionChecks:
      - name: "dws-prov"
        onFlavors: [dws]
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  namespace: "default"
  name: "user-queue"
spec:
  clusterQueue: "cluster-queue"
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: AdmissionCheck
metadata:
  name: dws-prov
spec:
  controllerName: kueue.x-k8s.io/provisioning-request
  parameters:
    apiGroup: kueue.x-k8s.io
    kind: ProvisioningRequestConfig
    name: dws-config
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ProvisioningRequestConfig
metadata:
  name: dws-config
spec:
  provisioningClassName: queued-provisioning.gke.io
  managedResources:
  - nvidia.com/gpu

La coda di questo cluster ha limiti di quota elevati ed è abilitata solo l'integrazione di Dynamic Workload Scheduler. Per scoprire di più sulle API Kueue e su come impostare i limiti, consulta Concetti di Kueue.

Esegui il deployment del manifest utilizzando il seguente comando:

kubectl create -f ./dws_and_reservation.yaml

L'output è simile al seguente:

resourceflavor.kueue.x-k8s.io/reservation created
resourceflavor.kueue.x-k8s.io/dws created
clusterqueue.kueue.x-k8s.io/cluster-queue created
localqueue.kueue.x-k8s.io/user-queue created
admissioncheck.kueue.x-k8s.io/dws-prov created
provisioningrequestconfig.kueue.x-k8s.io/dws-config created

Esegui il job

A differenza della configurazione precedente, questo manifest non include il campo nodeSelector, in quanto viene compilato da Kueue, a seconda della capacità libera in ClusterQueue.

apiVersion: batch/v1
kind: Job
metadata:
  generateName: sample-job-
  namespace: default
  labels:
    kueue.x-k8s.io/queue-name: user-queue
  annotations:
    provreq.kueue.x-k8s.io/maxRunDurationSeconds: "600"
spec:
  parallelism: 1
  completions: 1
  suspend: true
  template:
    spec:
      tolerations:
      - key: "nvidia.com/gpu"
        operator: "Exists"
        effect: "NoSchedule"
      containers:
      - name: dummy-job
        image: gcr.io/k8s-staging-perf-tests/sleep:v0.0.3
        args: ["120s"]
        resources:
          requests:
            cpu: "100m"
            memory: "100Mi"
            nvidia.com/gpu: 1
          limits:
            cpu: "100m"
            memory: "100Mi"
            nvidia.com/gpu: 1
      restartPolicy: Never
  1. Esegui il job:

    kubectl create -f ./job-without-node-selector.yaml
    

    L'output è simile al seguente:

    job.batch/sample-job-v8xwm created
    

Per scoprire quale pool di nodi utilizza il tuo job, devi sapere quale ResourceFlavor utilizza il tuo job.

Risoluzione dei problemi

Per scoprire di più sulla risoluzione dei problemi di Kueue, consulta Risoluzione dei problemi relativi alla richiesta di provisioning in Kueue

Dynamic Workload Scheduler per job senza coda

Definisci un oggetto ProvisioningRequest

Crea una richiesta tramite l'API ProvisioningRequest per ogni job. Dynamic Workload Scheduler non avvia i pod, ma esegue solo il provisioning dei nodi.

  1. Crea il seguente manifest provisioning-request.yaml:

    Standard

    apiVersion: v1
    kind: PodTemplate
    metadata:
      name: POD_TEMPLATE_NAME
      namespace: NAMESPACE_NAME
      labels:
        cloud.google.com/apply-warden-policies: "true"
    template:
      spec:
        nodeSelector:
          cloud.google.com/gke-nodepool: NODEPOOL_NAME
        tolerations:
          - key: "nvidia.com/gpu"
            operator: "Exists"
            effect: "NoSchedule"
        containers:
          - name: pi
            image: perl
            command: ["/bin/sh"]
            resources:
              limits:
                cpu: "700m"
                nvidia.com/gpu: 1
              requests:
                cpu: "700m"
                nvidia.com/gpu: 1
        restartPolicy: Never
    ---
    apiVersion: autoscaling.x-k8s.io/API_VERSION
    kind: ProvisioningRequest
    metadata:
      name: PROVISIONING_REQUEST_NAME
      namespace: NAMESPACE_NAME
    spec:
      provisioningClassName: queued-provisioning.gke.io
      parameters:
        maxRunDurationSeconds: "MAX_RUN_DURATION_SECONDS"
      podSets:
      - count: COUNT
        podTemplateRef:
          name: POD_TEMPLATE_NAME
    

    Sostituisci quanto segue:

    • API_VERSION: la versione dell'API, v1 o v1beta1. Per la versione GKE 1.31.1-gke.1678000 e successive, consigliamo di utilizzare v1 per la stabilità e l'accesso alle funzionalità più recenti.
    • NAMESPACE_NAME: il nome dello spazio dei nomi Kubernetes. Lo spazio dei nomi deve essere lo stesso dello spazio dei nomi dei pod.
    • PROVISIONING_REQUEST_NAME: il nome del ProvisioningRequest. Farai riferimento a questo nome nell'annotazione del pod.
    • MAX_RUN_DURATION_SECONDS: facoltativo, il tempo di esecuzione massimo di un nodo in secondi, fino al valore predefinito di sette giorni. Per scoprire di più, consulta Come funziona Dynamic Workload Scheduler. Non puoi modificare questo valore dopo la creazione della richiesta. Questo campo è disponibile in GKE versione 1.28.5-gke.1355000 o successive.
    • COUNT: numero di pod richiesti. I nodi vengono pianificati in modo atomico in una zona.
    • POD_TEMPLATE_NAME: il nome del PodTemplate.
    • NODEPOOL_NAME: il nome scelto per il pool di nodi. Rimuovi se vuoi utilizzare un pool di nodi con provisioning automatico.

    GKE potrebbe applicare convalide e mutazioni ai pod durante la loro creazione. L'etichetta cloud.google.com/apply-warden-policies consente a GKE di applicare le stesse convalide e mutazioni agli oggetti PodTemplate. Questa etichetta è necessaria per consentire a GKE di calcolare i requisiti delle risorse dei nodi per i pod.

    Provisioning automatico dei nodi

    apiVersion: v1
    kind: PodTemplate
    metadata:
      name: POD_TEMPLATE_NAME
      namespace: NAMESPACE_NAME
      labels:
        cloud.google.com/apply-warden-policies: "true"
    template:
      spec:
        nodeSelector:
          cloud.google.com/gke-accelerator: GPU_TYPE
        tolerations:
          - key: "nvidia.com/gpu"
            operator: "Exists"
            effect: "NoSchedule"
        containers:
          - name: pi
            image: perl
            command: ["/bin/sh"]
            resources:
              limits:
                cpu: "700m"
                nvidia.com/gpu: 1
              requests:
                cpu: "700m"
                nvidia.com/gpu: 1
        restartPolicy: Never
    ---
    apiVersion: autoscaling.x-k8s.io/API_VERSION
    kind: ProvisioningRequest
    metadata:
      name: PROVISIONING_REQUEST_NAME
      namespace: NAMESPACE_NAME
    spec:
      provisioningClassName: queued-provisioning.gke.io
      parameters:
        maxRunDurationSeconds: "MAX_RUN_DURATION_SECONDS"
      podSets:
      - count: COUNT
        podTemplateRef:
          name: POD_TEMPLATE_NAME
    

    Sostituisci quanto segue:

    • API_VERSION: la versione dell'API, v1 o v1beta1. Per la versione GKE 1.31.1-gke.1678000 e successive, consigliamo di utilizzare v1 per la stabilità e l'accesso alle funzionalità più recenti.
    • NAMESPACE_NAME: il nome dello spazio dei nomi Kubernetes. Lo spazio dei nomi deve essere lo stesso dello spazio dei nomi dei pod.
    • PROVISIONING_REQUEST_NAME: il nome del ProvisioningRequest. Farai riferimento a questo nome nell'annotazione del pod.
    • MAX_RUN_DURATION_SECONDS: facoltativo, il tempo di esecuzione massimo di un nodo in secondi, fino al valore predefinito di sette giorni. Per scoprire di più, consulta Come funziona Dynamic Workload Scheduler. Non puoi modificare questo valore dopo la creazione della richiesta. Questo campo è disponibile in GKE versione 1.28.5-gke.1355000 o successive.
    • COUNT: numero di pod richiesti. I nodi vengono pianificati in modo atomico in una zona.
    • POD_TEMPLATE_NAME: il nome del PodTemplate.
    • GPU_TYPE: il tipo di hardware della GPU.

    GKE potrebbe applicare convalide e mutazioni ai pod durante la loro creazione. L'etichetta cloud.google.com/apply-warden-policies consente a GKE di applicare le stesse convalide e mutazioni agli oggetti PodTemplate. Questa etichetta è necessaria per consentire a GKE di calcolare i requisiti delle risorse dei nodi per i pod.

  2. Applica il manifest:

    kubectl apply -f provisioning-request.yaml
    

Configura i pod

Questa sezione utilizza Kubernetes Jobs per configurare i pod. Tuttavia, puoi anche utilizzare un JobSet Kubernetes o qualsiasi altro framework come Kubeflow, Ray o controller personalizzati. Nella specifica Job, collega i pod a ProvisioningRequest utilizzando le seguenti annotazioni:

apiVersion: batch/v1
kind: Job
spec:
  template:
    metadata:
      annotations:
        autoscaling.x-k8s.io/consume-provisioning-request: PROVISIONING_REQUEST_NAME
        autoscaling.x-k8s.io/provisioning-class-name: "queued-provisioning.gke.io"
    spec:
      ...

Prima della versione GKE 1.30.3-gke.1854000, devi utilizzare le seguenti annotazioni legacy:

      annotations:
        cluster-autoscaler.kubernetes.io/consume-provisioning-request: PROVISIONING_REQUEST_NAME
        cluster-autoscaler.kubernetes.io/provisioning-class-name: "queued-provisioning.gke.io"

Tieni presente che, a partire dalla versione GKE 1.31.1-gke.1678000, le annotazioni cluster-autoscaler.kubernetes.io/consume-provisioning-request e cluster-autoscaler.kubernetes.io/provisioning-class-name sono ritirate.

La chiave di annotazione del pod consume-provisioning-request definisce quale ProvisioningRequest consumare. GKE utilizza le annotazioni consume-provisioning-request e provisioning-class-name per eseguire quanto segue:

  • Per pianificare i pod solo nei nodi di cui è stato eseguito il provisioning da Dynamic Workload Scheduler.
  • Per evitare il conteggio doppio delle richieste di risorse tra i pod e lo scheduler dei carichi di lavoro dinamici nel gestore della scalabilità automatica dei cluster.
  • Per iniettare l'annotazione safe-to-evict: false, per impedire al gestore della scalabilità automatica del cluster di spostare i pod tra i nodi e interrompere i calcoli batch. Puoi modificare questo comportamento specificando safe-to-evict: true nelle annotazione del pod.

Osservare lo stato di Dynamic Workload Scheduler

Lo stato di un pianificatore dei carichi di lavoro dinamico definisce se un pod può essere pianificato o meno. Puoi utilizzare Kubernetes Watches per osservare le modifiche in modo efficiente o altri strumenti che utilizzi già per monitorare gli stati degli oggetti Kubernetes. La tabella seguente descrive il possibile stato di un pianificatore dei carichi di lavoro dinamico e ogni possibile esito:

Stato di Dynamic Workload Scheduler Descrizione Possibile esito
In attesa La richiesta non è stata ancora visualizzata ed elaborata. Dopo l'elaborazione, la richiesta passa allo stato Accepted o Failed.
Accepted=true La richiesta è accettata e attende che le risorse siano disponibili. La richiesta deve passare allo stato Provisioned se sono state trovate risorse e sono stati eseguiti il provisioning dei nodi o allo stato Failed se non è stato possibile.
Provisioned=true I nodi sono pronti. Hai 10 minuti di tempo per avviare i pod in modo da consumare le risorse di cui è stato eseguito il provisioning. Dopo questo periodo di tempo, il gestore della scalabilità automatica del cluster considera i nodi come non necessari e li rimuove.
Failed=true Non è possibile eseguire il provisioning dei nodi a causa di errori. Failed=true è uno stato terminale. Risolvi i problemi relativi alla condizione in base alle informazioni contenute nei campi Reason e Message della condizione. Crea e riprova una nuova richiesta di Dynamic Workload Scheduler.
Provisioned=false Il provisioning dei nodi non è ancora stato eseguito.

Se Reason=NotProvisioned, si tratta di uno stato temporaneo prima che tutte le risorse siano disponibili.

Se Reason=QuotaExceeded, risolvi il problema della condizione in base a questo motivo e alle informazioni nel campo Message della condizione. Potresti dover richiedere una quota maggiore. Per maggiori dettagli, consulta la sezione Verificare se il pianificatore dei carichi di lavoro dinamico è limitato dalla quota. Questo Reason è disponibile solo con GKE 1.29.2-gke.1181000 o versioni successive.

Se Reason=ResourcePoolExhausted e Message contengono Expected time is indefinite, seleziona una zona o una regione diversa o modifica le risorse richieste.

Avvia i pod

Quando la richiesta di Dynamic Workload Scheduler raggiunge lo stato Provisioned=true, puoi eseguire il tuo job per avviare i pod. In questo modo si evita la proliferazione di pod non pianificabili per richieste in attesa o non riuscite, che possono influire sul rendimento di kube-scheduler e del gestore della scalabilità automatica dei cluster.

In alternativa, se non ti interessa avere pod non pianificabili, puoi creare pod in parallelo con Dynamic Workload Scheduler.

Annullare la richiesta di Dynamic Workload Scheduler

Per annullare la richiesta prima del provisioning, puoi eliminare il ProvisioningRequest:

kubectl delete provreq PROVISIONING_REQUEST_NAME -n NAMESPACE

Nella maggior parte dei casi, l'eliminazione di ProvisioningRequest impedisce la creazione di nodi. Tuttavia, a seconda dei tempi, ad esempio se il provisioning dei nodi è già in corso, i nodi potrebbero comunque essere creati. In questi casi, il gestore della scalabilità automatica del cluster rimuove i nodi dopo 10 minuti se non vengono creati pod.

Come funziona Dynamic Workload Scheduler

Con ProvisioningRequest API, Dynamic Workload Scheduler esegue le seguenti operazioni:

  1. Comunichi a GKE che il tuo carico di lavoro può attendere per un periodo di tempo indeterminato finché tutti i nodi richiesti non saranno pronti per l'uso contemporaneamente.
  2. Il gestore della scalabilità automatica dei cluster accetta la richiesta e calcola il numero di nodi necessari, trattandoli come una singola unità.
  3. La richiesta attende che tutte le risorse necessarie siano disponibili in una singola zona. Per i cluster che eseguono 1.29.1-gke.1708000 e versioni successive, questa zona viene scelta utilizzando informazioni sulla capacità disponibile per garantire tempi di attesa inferiori. Per i cluster che eseguono versioni precedenti, la zona è stata scelta senza queste informazioni, il che può comportare la formazione di code nelle zone in cui i tempi di attesa sono molto più lunghi.
  4. Il gestore della scalabilità automatica del cluster esegue il provisioning dei nodi necessari, se disponibili, contemporaneamente.
  5. Tutti i pod del workload possono essere eseguiti insieme sui nodi appena provisionati.
  6. I nodi di cui è stato eseguito il provisioning sono limitati a sette giorni di tempo di esecuzione o meno se impostate il parametro maxRunDurationSeconds per indicare che i carichi di lavoro richiedono meno tempo per l'esecuzione. Per saperne di più, consulta Limitare il runtime di una VM. Questa funzionalità è disponibile con GKE 1.28.5-gke.1355000 o versioni successive. Dopo questo periodo, i nodi e i pod in esecuzione vengono prenotati. Se i pod terminano prima e i nodi non vengono utilizzati, l'autoscaler del cluster li rimuove in base al profilo di scalabilità automatica.
  7. I nodi non vengono riutilizzati tra Dynamic Workload Scheduler. Ogni ProvisioningRequest ordina la creazione di nuovi nodi con il nuovo tempo di esecuzione di sette giorni.

GKE misura il tempo di esecuzione a livello di nodo. Il tempo a disposizione per l'esecuzione dei pod potrebbe essere leggermente inferiore a causa di ritardi durante l'avvio. I retry dei pod condividono questo runtime, il che significa che dopo il retry è disponibile meno tempo per i pod. GKE conteggia separatamente il tempo di esecuzione di ogni richiesta di Dynamic Workload Scheduler.

Quota

Tutte le VM di cui viene eseguito il provisioning dalle richieste di Dynamic Workload Scheduler utilizzano quote preassegnate.

Il numero di ProvisioningRequests in stato Accepted è limitato da una quota dedicata. Configura la quota per ogni progetto, una configurazione della quota per regione.

Controllare la quota nella console Google Cloud

Per controllare il nome del limite di quota e l'utilizzo corrente nella console Google Cloud:

  1. Vai alla pagina Quote nella console Google Cloud:

    Vai a Quote

  2. Nella casella Filtro, seleziona la proprietà Metrica, inserisci active_resize_requests e premi Invio.

Il valore predefinito è 100. Per aumentare la quota, segui i passaggi descritti nella guida per richiedere un limite di quota più alto.

Verificare se Dynamic Workload Scheduler è limitato dalla quota

Se la richiesta di pianificatore dei carichi di lavoro dinamici richiede più tempo del previsto per essere soddisfatta, verifica che la richiesta non sia limitata dalla quota. Potresti dover richiedere un aumento della quota.

Per i cluster che eseguono la versione 1.29.2-gke.1181000 o successive, controlla se limitazioni specifiche delle quote impediscono l'accettazione della tua richiesta:

kubectl describe provreq PROVISIONING_REQUEST_NAME \
    --namespace NAMESPACE

L'output è simile al seguente:

…
Last Transition Time:  2024-01-03T13:56:08Z
    Message:               Quota 'NVIDIA_P4_GPUS' exceeded. Limit: 1.0 in region europe-west4.
    Observed Generation:   1
    Reason:                QuotaExceeded
    Status:                False
    Type:                  Provisioned
…

In questo esempio, GKE non può eseguire il deployment dei nodi perché la quota nella regione europe-west4 non è sufficiente.

Gestire le interruzioni nei carichi di lavoro utilizzando Dynamic Workload Scheduler

I carichi di lavoro che richiedono la disponibilità di tutti i nodi o della maggior parte dei nodi in un pool di nodi sono sensibili agli sfollamenti. La riparazione o l'upgrade automatico di un nodo eseguito il provisioning con ProvisioningRequest API non è supportato perché queste operazioni espellono tutti i workload in esecuzione sul nodo e li rendono non pianificabili.

Best practice per ridurre al minimo l'interruzione del workload

Per ridurre al minimo l'interruzione dei carichi di lavoro in esecuzione utilizzando Dynamic Workload Scheduler, svolgi le seguenti attività:

  • A seconda della registrazione al canale di rilascio del tuo cluster, segui le best practice riportate di seguito per evitare che gli upgrade automatici dei nodi interrompano i tuoi carichi di lavoro:
  • Disattiva la riparazione automatica dei nodi.
  • Utilizza i periodi di manutenzione ed esclusioni per ridurre al minimo le interruzioni dei workload in esecuzione, assicurandoti al contempo che GKE abbia ancora tempo per eseguire la manutenzione automatica. Assicurati di specificare questo momento quando non sono in esecuzione carichi di lavoro.
  • Per assicurarti che il pool di nodi rimanga aggiornato, esegui l'upgrade manuale del pool di nodi quando non ci sono richieste di Dynamic Workload Scheduler attive e il pool di nodi è vuoto.

Limitazioni

  • L'anti-affinità tra pod non è supportata. Il gestore della scalabilità automatica dei cluster non prende in considerazione le regole di anti-affinità tra pod durante il provisioning dei nodi, il che potrebbe portare a carichi di lavoro non pianificabili. Ciò può accadere quando è stato eseguito il provisioning dei nodi per due o più oggetti Dynamic Workload Scheduler nello stesso pool di nodi.
  • Sono supportati solo i nodi GPU.
  • Le prenotazioni non sono supportate con Dynamic Workload Scheduler. Devi specificare --reservation-affinity=none durante la creazione del pool di nodi. Dynamic Workload Scheduler richiede e supporta solo il ANY criterio della località per la scalabilità automatica del cluster.
  • Una singola richiesta di Dynamic Workload Scheduler può creare fino a 1000 VM, ovvero il numero massimo di nodi per zona per un singolo pool di nodi.
  • GKE utilizza la quota ACTIVE_RESIZE_REQUESTS di Compute Engine per controllare il numero di richieste di pianificatore dei carichi di lavoro dinamici in attesa in una coda. Per impostazione predefinita, questa quota ha un limite di 100 a livello di progetto Google Cloud. Se provi a creare una richiesta di pianificatore del carico di lavoro dinamico superiore a questa quota, la nuova richiesta non va a buon fine.
  • I pool di nodi che utilizzano Dynamic Workload Scheduler sono sensibili alle interruzioni poiché il provisioning dei nodi viene eseguito insieme. Per scoprire di più, consulta Configurare le impostazioni di interruzione per i pool di nodi con i workload che utilizzano lo scheduler dei workload dinamici.
  • Potresti vedere altre VM di breve durata elencate nella console Google Cloud. Questo comportamento è intenzionale perché Compute Engine potrebbe creare e rimuovere tempestivamente le VM finché non sarà disponibile la capacità di eseguire il provisioning di tutte le macchine richieste.
  • L'integrazione di Dynamic Workload Scheduler supporta un solo PodSet. Se vuoi combinare diversi modelli di pod, utilizza quello con il maggior numero di risorse richieste. La combinazione di diversi tipi di macchine, ad esempio VM con diversi tipi di GPU, non è supportata.

Passaggi successivi