Deployment di un sistema batch utilizzando Kueue


Questo tutorial mostra come eseguire il deployment di un sistema batch utilizzando Kueue uno scheduler cloud-native per eseguire Lavoro in coda su Google Kubernetes Engine (GKE). Completa questo tutorial per scoprire come: configura GKE e Kueue per eseguire job in modalità FIFO (first-in-first-out) ordine.

Contesto

I job sono applicazioni che vengono eseguite fino al completamento, come ad esempio machine learning, rendering simulazione, analisi, CI/CD e carichi di lavoro simili.

Kueue è uno scheduler di job cloud-native che funziona con lo strumento scheduler Kubernetes, il controller Job e il gestore della scalabilità automatica dei cluster per fornire in un sistema batch end-to-end. Kueue implementa l'accodamento dei job, decidendo quando i job devono attendere e quando iniziare, in base alle quote e a una gerarchia per la condivisione delle risorse in modo equo tra i team.

Kueue ha le seguenti caratteristiche:

  • È ottimizzato per le architetture cloud, in cui le risorse eterogenei, intercambiabili e scalabili.
  • Fornisce un insieme di API per gestire le quote elastiche e l'accodamento dei job.
  • Non reimplementa funzionalità esistenti come la scalabilità automatica, la pianificazione dei pod o la gestione del ciclo di vita dei job.
  • Kueue dispone del supporto integrato per l'API batch/v1.Job Kubernetes.
  • Può integrarsi con altre API per i job.

Kueue si riferisce ai job definiti con qualsiasi API come carichi di lavoro, per evitare confusione con l'API Kubernetes Job specifica.

Obiettivi

Questo tutorial è rivolto agli operatori di cluster e agli altri utenti che vogliono di implementare un sistema batch su Kubernetes. In questo tutorial hai configurato un per due team tenant. Ogni team ha il proprio spazio dei nomi in cui creare job e condividere le stesse risorse globali controllate con il quote corrispondenti.

Questo tutorial illustra i seguenti passaggi:

  1. Crea un cluster GKE
  2. Crea l'elemento ResourceFlavor.
  3. Crea il cluster ClusterQueue
  4. Crea la LocalQueue
  5. Creare job e osservare i carichi di lavoro ammessi

Costi

Questo tutorial utilizza i seguenti componenti fatturabili di Google Cloud:

Utilizza il Calcolatore prezzi per generare una stima dei costi in base all'utilizzo previsto.

Al termine di questo tutorial, per evitare di continuare a fatturare, elimina il le risorse che hai creato. Per maggiori informazioni, vedi Pulizia.

Prima di iniziare

Configura il progetto

  1. Accedi al tuo account Google Cloud. Se non conosci Google Cloud, crea un account per valutare le prestazioni dei nostri prodotti in scenari reali. I nuovi clienti ricevono anche 300 $di crediti gratuiti per l'esecuzione, il test e il deployment dei carichi di lavoro.
  2. In the Google Cloud console, on the project selector page, click Create project to begin creating a new Google Cloud project.

    Go to project selector

  3. Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.

  4. Attiva l'API GKE.

    Abilita l'API

  5. In the Google Cloud console, on the project selector page, click Create project to begin creating a new Google Cloud project.

    Go to project selector

  6. Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.

  7. Attiva l'API GKE.

    Abilita l'API

Configura impostazioni predefinite per Google Cloud CLI

  1. Nella console Google Cloud, avvia un'istanza di Cloud Shell:
    Apri Cloud Shell

  2. Scarica il codice sorgente per questa app di esempio:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    cd kubernetes-engine-samples/batch/kueue-intro
    
  3. Imposta le variabili di ambiente predefinite:

    gcloud config set project PROJECT_ID
    gcloud config set compute/region COMPUTE_REGION
    

    Sostituisci i seguenti valori:

Crea un cluster GKE

  1. Crea un cluster GKE Autopilot denominato kueue-autopilot:

    gcloud container clusters create-auto kueue-autopilot \
      --release-channel "rapid" --region COMPUTE_REGION
    

    I cluster Autopilot sono completamente gestiti e hanno la scalabilità automatica integrata. Scopri di più su GKE Autopilot.

    Kueue supporta anche GKE standard con Node Provisioning automatico e normali pool di nodi con scalabilità automatica.

    Una volta creato il cluster, il risultato è simile al seguente:

      NAME: kueue-autopilot
      LOCATION: us-central1
      MASTER_VERSION: 1.26.2-gke.1000
      MASTER_IP: 35.193.173.228
      MACHINE_TYPE: e2-medium
      NODE_VERSION: 1.26.2-gke.1000
      NUM_NODES: 3
      STATUS: RUNNING
    

    Dove STATUS è RUNNING per kueue-autopilot.

  2. Recupera le credenziali di autenticazione per il cluster:

    gcloud container clusters get-credentials kueue-autopilot
    
  3. Installa Kueue sul cluster:

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

    Sostituisci VERSION con l'ultima versione di Kueue. Per scoprire di più sulle versioni di Kueue, consulta Release di Kueuue.

  4. Attendi che i pod Kueue siano pronti:

    watch kubectl -n kueue-system get pods
    

    Per poter continuare, l'output dovrebbe essere simile al seguente:

    NAME                                        READY   STATUS    RESTARTS   AGE
    kueue-controller-manager-66d8bb946b-wr2l2   2/2     Running   0          3m36s
    
  5. Crea due nuovi spazi dei nomi chiamati team-a e team-b:

    kubectl create namespace team-a
    kubectl create namespace team-b
    

Crea ResourceFlavor

Un ResourceFlavor è un oggetto che rappresenta le variazioni dei nodi disponibili nel cluster associandole a etichette dei nodi e incompatibilità. Ad esempio, puoi utilizzare ResourceFlavors rappresentano VM con garanzie di provisioning diverse (ad esempio spot e on demand), architetture (ad esempio, CPU x86 rispetto a ARM), brand e modelli (ad es. GPU Nvidia A100 rispetto a T4).

In questo tutorial, il cluster kueue-autopilot ha risorse omogenee. Di conseguenza, crea un singolo ResourceFlavor per CPU, memoria, archiviazione temporanea e GPU, senza etichette o incompatibilità.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: default-flavor # This ResourceFlavor will be used for all the resources
Esegui il deployment di ResourceFlavor:

kubectl apply -f flavors.yaml

Crea la ClusterQueue

Un ClusterQueue è un oggetto con ambito cluster che gestisce un pool di risorse come CPU, memoria e GPU. Gestisce i ResourceFlavors e limita l'utilizzo e determina l'ordine in cui sono ammessi i carichi di lavoro.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
  name: cluster-queue
spec:
  namespaceSelector: {} # Available to all namespaces
  queueingStrategy: BestEffortFIFO # Default queueing strategy
  resourceGroups:
  - coveredResources: ["cpu", "memory", "nvidia.com/gpu", "ephemeral-storage"]
    flavors:
    - name: "default-flavor"
      resources:
      - name: "cpu"
        nominalQuota: 10
      - name: "memory"
        nominalQuota: 10Gi
      - name: "nvidia.com/gpu"
        nominalQuota: 10
      - name: "ephemeral-storage"
        nominalQuota: 10Gi

Esegui il deployment di ClusterQueue:

kubectl apply -f cluster-queue.yaml

L'ordine di consumo è determinato da .spec.queueingStrategy, dove sono presenti due configurazioni:

  • BestEffortFIFO

    • La configurazione predefinita della strategia di accodamento.
    • L'ammissione al carico di lavoro segue la regola FIFO, ma se la quota non è sufficiente per ammettere il carico di lavoro in cima alla coda, si prova quello successivo.
  • StrictFIFO

    • Garantisce la semantica FIFO.
    • Il carico di lavoro in cima alla coda può bloccare l'accodamento fino a quando il carico di lavoro non può essere ammesso.

In cluster-queue.yaml crei una nuova ClusterQueue denominata cluster-queue. Questo ClusterQueue gestisce quattro risorse: cpu, memory, nvidia.com/gpu e ephemeral-storage con il gusto creato in flavors.yaml. La quota viene utilizzata dalle richieste nelle specifiche dei pod dei carichi di lavoro.

Ogni versione include limiti di utilizzo rappresentati come .spec.resourceGroups[].flavors[].resources[].nominalQuota. In questo caso, ClusterQueue ammette carichi di lavoro solo se:

  • La somma delle richieste di CPU è minore o uguale a 10
  • La somma delle richieste di memoria è minore o uguale a 10 Gi
  • La somma delle richieste GPU è minore o uguale a 10
  • La somma dello spazio di archiviazione utilizzato è minore o uguale a 10 Gi

Crea la LocalQueue

Un LocalQueue è un oggetto con spazio dei nomi che accetta carichi di lavoro dagli utenti nello spazio dei nomi. LocalQueues da diversi spazi dei nomi possono indirizzare a nella stessa ClusterQueue dove possono condividere quota. In questo caso, La coda LocalQueue dallo spazio dei nomi team-a e team-b punta alla stessa ClusterQueue cluster-queue sotto .spec.clusterQueue.

apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  namespace: team-a # LocalQueue under team-a namespace
  name: lq-team-a
spec:
  clusterQueue: cluster-queue # Point to the ClusterQueue
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  namespace: team-b # LocalQueue under team-b namespace
  name: lq-team-b
spec:
  clusterQueue: cluster-queue # Point to the ClusterQueue

Ogni team invia i propri carichi di lavoro a LocalQueue nel proprio spazio dei nomi. che vengono poi allocate da ClusterQueue.

Esegui il deployment di LocalQueues:

kubectl apply -f local-queue.yaml

Creare job e osservare i carichi di lavoro ammessi

apiVersion: batch/v1
kind: Job
metadata:
  namespace: team-a # Job under team-a namespace
  generateName: sample-job-team-a-
  annotations:
    kueue.x-k8s.io/queue-name: lq-team-a # Point to the LocalQueue
spec:
  ttlSecondsAfterFinished: 60 # Job will be deleted after 60 seconds
  parallelism: 3 # This Job will have 3 replicas running at the same time
  completions: 3 # This Job requires 3 completions
  suspend: true # Set to true to allow Kueue to control the Job when it starts
  template:
    spec:
      nodeSelector:
        cloud.google.com/gke-accelerator: "nvidia-tesla-t4" # Specify the GPU hardware
      containers:
      - name: dummy-job
        image: gcr.io/k8s-staging-perf-tests/sleep:latest
        args: ["10s"] # Sleep for 10 seconds
        resources:
          requests:
            cpu: "500m"
            memory: "512Mi"
            ephemeral-storage: "512Mi"
            nvidia.com/gpu: "1"
          limits:
            cpu: "500m"
            memory: "512Mi"
            ephemeral-storage: "512Mi"
            nvidia.com/gpu: "1"
      restartPolicy: Never

I job vengono creati nello spazio dei nomi team-a. Questo job punta a LocalQueue lq-team-a. Per richiedere risorse GPU, il criterio nodeSelector è impostato su nvidia-tesla-t4.

Il job è composto da tre pod che rimangono in sospensione per 10 secondi in parallelo. I job vengono ripuliti dopo 60 secondi in base alle ttlSecondsAfterFinished.

Questo job richiede 1500 milliCPU, 1536 Mi di memoria, 1536 Mi di memoria temporanea e tre GPU, dato che ci sono tre pod.

I job vengono creati anche nel file job-team-b.yaml il cui spazio dei nomi appartiene a team-b, con richieste rappresentano team diversi con esigenze diverse.

Per scoprire di più, consulta Eseguire il deployment dei carichi di lavoro GPU in Autopilot.

  1. In un nuovo terminale, osserva lo stato di ClusterQueue che si aggiorna ogni due secondi:

    watch -n 2 kubectl get clusterqueue cluster-queue -o wide
    
  2. In un nuovo terminale, osserva lo stato dei nodi:

    watch -n 2 kubectl get nodes -o wide
    
  3. In un nuovo terminale, crea job in LocalQueue dallo spazio dei nomi team-a e team-b ogni 10 secondi:

    ./create_jobs.sh job-team-a.yaml job-team-b.yaml 10
    
  4. Osserva i job messi in coda, ammessi in ClusterQueue e i nodi creati con GKE Autopilot.

  5. Recupera un job dallo spazio dei nomi team-a:

    kubectl -n team-a get jobs
    

    Il risultato è simile al seguente:

    NAME                      COMPLETIONS   DURATION   AGE
    sample-job-team-b-t6jnr   3/3           21s        3m27s
    sample-job-team-a-tm7kc   0/3                      2m27s
    sample-job-team-a-vjtnw   3/3           30s        3m50s
    sample-job-team-b-vn6rp   0/3                      40s
    sample-job-team-a-z86h2   0/3                      2m15s
    sample-job-team-b-zfwj8   0/3                      28s
    sample-job-team-a-zjkbj   0/3                      4s
    sample-job-team-a-zzvjg   3/3           83s        4m50s
    
  6. Copia il nome di un job dal passaggio precedente e osserva lo stato di ammissione per un job tramite l'API Workloads:

    kubectl -n team-a describe workload JOB_NAME
    
  7. Quando i job in attesa iniziano ad aumentare dalla ClusterQueue, termina lo script premendo CTRL + C sullo script in esecuzione.

  8. Una volta completati tutti i job, vedrai lo scale down dei nodi.

Esegui la pulizia

Per evitare che al tuo Account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.

Elimina il progetto

  1. Nella console Google Cloud, vai alla pagina Gestisci risorse.

    Vai a Gestisci risorse

  2. Nell'elenco dei progetti, seleziona il progetto che vuoi eliminare, quindi fai clic su Elimina.
  3. Nella finestra di dialogo, digita l'ID del progetto e fai clic su Chiudi per eliminare il progetto.

Elimina la singola risorsa

  1. Elimina il sistema di quote Kueue:

    kubectl delete -n team-a localqueue lq-team-a
    kubectl delete -n team-b localqueue lq-team-b
    kubectl delete clusterqueue cluster-queue
    kubectl delete resourceflavor default-flavor
    
  2. Elimina il manifest Kueue:

    VERSION=VERSION
    kubectl delete -f \
      https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/manifests.yaml
    
  3. Elimina il cluster:

    gcloud container clusters delete kueue-autopilot --region=COMPUTE_REGION
    

Passaggi successivi