Déployer un système de traitement par lots à l'aide de Kueue

Ce tutoriel vous explique comment optimiser les ressources disponibles en planifiant des jobs sur Google Kubernetes Engine (GKE) avec Kueue. Dans ce tutoriel, vous apprendrez à utiliser Kueue pour gérer et planifier efficacement les jobs par lots, améliorer l'utilisation des ressources et simplifier la gestion des charges de travail. Vous configurerez un cluster partagé pour deux équipes locataires, où chaque équipe dispose de son propre espace de noms et crée des jobs qui partagent des ressources globales. Vous configurerez également Kueue pour planifier les jobs en fonction des quotas de ressources que vous définissez.

Ce tutoriel est destiné aux architectes cloud et aux ingénieurs de plate-forme qui souhaitent implémenter un système de traitement par lots à l'aide de GKE. Pour en savoir plus sur les rôles courants et les exemples de tâches référencés dans Google Cloud le contenu, consultez Rôles et tâches courants des utilisateurs GKE.

Avant de lire cette page, assurez-vous de bien comprendre les points suivants :

Arrière-plan

Les jobs sont des applications qui s'exécutent jusqu'à la fin, telles que le machine learning, le rendu, la simulation, l'analyse, les pipelines CI/CD et d'autres charges de travail similaires.

Kueue est un planificateur de jobs cloud natif qui fonctionne avec le programmeur Kubernetes par défaut, le contrôleur de jobs et l'autoscaler de cluster pour fournir un système de traitement par lots de bout en bout. Kueue met en œuvre la mise en file d'attente des jobs, en déterminant quand les tâches doivent attendre et quand elles doivent démarrer, en fonction des quotas et d'une hiérarchie de partage équitable des ressources entre les équipes.

Kueue présente les caractéristiques suivantes :

  • Il est optimisé pour les architectures cloud, où les ressources sont hétérogènes, interchangeables et évolutives.
  • Il fournit un ensemble d'API pour gérer les quotas élastiques et la file d'attente des jobs.
  • Il ne remet pas en œuvre les fonctionnalités existantes telles que l'autoscaling, la planification des pods ou la gestion du cycle de vie des jobs.
  • Kueue est compatible avec l'API Kubernetes batch/v1.Job.
  • Il peut s'intégrer à d'autres API de jobs.

Kueue fait référence aux jobs définis avec n'importe quelle API en tant que charges de travail, afin d'éviter toute confusion avec l'API de tâches Kubernetes spécifique.

Objectifs

  1. Créer un cluster GKE
  2. Créer la ressource ResourceFlavor
  3. Créer la ressource ClusterQueue
  4. Créer la ressource LocalQueue
  5. Créer des jobs et observer les charges de travail acceptées

Coûts

Ce tutoriel utilise les composants facturables suivants de Google Cloud:

Utilisez le simulateur de coût pour générer une estimation des coûts en fonction de votre utilisation prévue.

Une fois que vous avez terminé ce tutoriel, évitez de continuer à payer des frais en supprimant les ressources que vous avez créées. Pour en savoir plus, consultez la section Effectuer un nettoyage.

Avant de commencer

Configurer votre projet

  1. Connectez-vous à votre Google Cloud compte. Si vous n'avez jamais utilisé Google Cloud, créez un compte pour évaluer les performances de nos produits dans des scénarios réels. Les nouveaux clients bénéficient également de 300 $de crédits sans frais pour exécuter, tester et déployer des charges de travail.
  2. In the Google Cloud console, on the project selector page, click Create project to begin creating a new Google Cloud project.

    Roles required to create a project

    To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the GKE API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

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

    Roles required to create a project

    To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the GKE API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

Définir des valeurs par défaut pour Google Cloud CLI

  1. Dans la Google Cloud console, démarrez une instance Cloud Shell :
    Ouvrir Cloud Shell

  2. Téléchargez le code source pour cet exemple d'application :

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    cd kubernetes-engine-samples/batch/kueue-intro
    
  3. Définissez les variables d'environnement par défaut :

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

    Remplacez les valeurs suivantes :

Créer un cluster GKE

  1. Créez un cluster GKE Autopilot nommé kueue-autopilot :

    gcloud container clusters create-auto kueue-autopilot \
      --release-channel "rapid" --location CONTROL_PLANE_LOCATION
    

    Les clusters Autopilot sont entièrement gérés et disposent d'un autoscaling intégré. En savoir plus sur GKE Autopilot.

    Kueue est également compatible avec le service GKE standard avec provisionnement automatique des nœuds et pools de nœuds avec autoscaling standard.

    Une fois le cluster créé, le résultat ressemble à ce qui suit :

      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
    

    STATUS est RUNNING pour kueue-autopilot.

  2. Obtenez des identifiants d'authentification pour le cluster :

    gcloud container clusters get-credentials kueue-autopilot
    
  3. Installez Kueue sur le cluster :

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

    Remplacez VERSION par la dernière version de Kueue. Pour en savoir plus sur les versions de Kueue, consultez la page Versions de Kueue.

  4. Attendez que les pods Kueue soient prêts :

    watch kubectl -n kueue-system get pods
    

    Avant de continuer, le résultat doit ressembler à ce qui suit :

    NAME                                        READY   STATUS    RESTARTS   AGE
    kueue-controller-manager-66d8bb946b-wr2l2   2/2     Running   0          3m36s
    
  5. Créez deux espaces de noms appelés team-a et team-b :

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

Créer la ressource ResourceFlavor

Une ressource ResourceFlavor est un objet qui représente les variations dans les nœuds disponibles dans votre cluster en les associant à des libellés de nœuds et à des rejets. Par exemple, vous pouvez utiliser des ressources ResourceFlavors pour représenter des VM avec différentes garanties de provisionnement (par exemple, spot ou à la demande), d'architectures (par exemple, processeurs x86 ou processeurs ARM), marques et modèles (par exemple, GPU Nvidia A100 et GPU T4).

Dans ce tutoriel, le cluster kueue-autopilot dispose de ressources homogènes. Par conséquent, créez une seule ressource ResourceFlavor pour le processeur, la mémoire, le stockage éphémère et les GPU, sans libellés ni rejets.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: default-flavor # This ResourceFlavor will be used for all the resources
Déployez la ressource ResourceFlavor :

kubectl apply -f flavors.yaml

Créer la ressource ClusterQueue

Une ressource ClusterQueue est un objet à l'échelle d'un cluster qui gère un pool de ressources telles que le processeur, la mémoire et le GPU. Elle gère la ressource ResourceFlavors, limite l'utilisation et détermine l'ordre d'admission des charges de travail.

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

Déployez le ClusterQueue :

kubectl apply -f cluster-queue.yaml

L'ordre de consommation est déterminé par .spec.queueingStrategy, qui permet deux configurations :

  • BestEffortFIFO

    • Configuration de la stratégie de mise en file d'attente par défaut.
    • L'admission de la charge de travail suit la première règle FIFO (premier entré, premier sorti), mais si le quota est insuffisant pour accepter la charge de travail en tête de la file d'attente, une nouvelle tentative sera exécutée avec la charge de travail suivante dans la liste.
  • StrictFIFO

    • Garantit la sémantique FIFO.
    • La charge de travail en tête de la file d'attente peut bloquer la file d'attente jusqu'à l'admission de la charge de travail.

Dans cluster-queue.yaml, vous créez une ressource ClusterQueue appelée cluster-queue. Cette ressource ClusterQueue gère quatre ressources : cpu, memory, nvidia.com/gpu et ephemeral-storage avec le type créé dans flavors.yaml. Le quota est consommé par les requêtes dans les spécifications de pod de la charge de travail.

Chaque type inclut des limites d'utilisation représentées par .spec.resourceGroups[].flavors[].resources[].nominalQuota. Dans ce cas, la ressource ClusterQueue n'accepte les charges de travail que si les conditions suivantes sont respectées :

  • La somme des requêtes de processeur est inférieure ou égale à 10.
  • La somme des requêtes de mémoire est inférieure ou égale à 10 Gi.
  • La somme des requêtes de GPU est inférieure ou égale à 10.
  • La somme de l'espace de stockage utilisé est inférieure ou égale à 10 Gi.

Créer la ressource LocalQueue

Une ressource LocalQueue est un objet d'espace de noms qui accepte les charges de travail des utilisateurs dans l'espace de noms. Les ressources LocalQueues de différents espaces de noms peuvent pointer vers la même ressource ClusterQueue, où elles peuvent partager le quota des ressources. Dans ce cas, la ressource LocalQueue des espaces de noms team-a et team-b pointe vers la même ressource ClusterQueue cluster-queue sous .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

Chaque équipe envoie ses charges de travail à la ressource LocalQueue dans son propre espace de noms. Ces ressources sont ensuite allouées par ClusterQueue.

Déployez les ressources LocalQueue :

kubectl apply -f local-queue.yaml

Créer des jobs et observer les charges de travail acceptées

Dans cette section, vous allez créer des jobs Kubernetes dans l'espace de noms team-a. Un contrôleur de jobs dans Kubernetes crée un ou plusieurs pods et s'assure qu'ils exécutent correctement une tâche spécifique.

Le job de l'espace de noms team-a présente les attributs suivants :

  • Il pointe vers la ressource LocalQueue lq-team-a.
  • Il demande des ressources GPU en définissant le champ nodeSelector sur nvidia-tesla-t4.
  • Il est composé de trois pods qui se mettent en veille pendant 10 secondes en parallèle. Les jobs sont nettoyés après 60 secondes, conformément à la valeur définie dans le champ ttlSecondsAfterFinished.
  • Il nécessite 1 500 milliCPU, 1 536 Mi de mémoire, 1 536 Mi de stockage éphémère et trois GPU, car il existe trois pods.
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

Les jobs sont également créés dans le fichier job-team-b.yaml où l'espace de noms appartient à team-b, avec des requêtes permettant de représenter différentes équipes avec des besoins différents.

Pour en savoir plus, consultez la page Déployer des charges de travail GPU dans Autopilot.

  1. Dans un nouveau terminal, observez l'état de la ressource ClusterQueue qui s'actualise toutes les deux secondes :

    watch -n 2 kubectl get clusterqueue cluster-queue -o wide
    
  2. Dans un nouveau terminal, observez l'état des nœuds :

    watch -n 2 kubectl get nodes -o wide
    
  3. Dans un nouveau terminal, créez des jobs pour la ressource LocalQueue à partir de l'espace de noms team-a et team-b toutes les 10 secondes :

    ./create_jobs.sh job-team-a.yaml job-team-b.yaml 10
    
  4. Observez les jobs en file d'attente, acceptés dans la ressource ClusterQueue et les nœuds restaurés avec GKE Autopilot.

  5. Obtenez un job à partir de l'espace de noms team-a :

    kubectl -n team-a get jobs
    

    Le résultat ressemble à ce qui suit :

    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. Copiez un nom de job obtenu à l'étape précédente, et observez l'état d'admission et les événements d'un job via l'API Workloads :

    kubectl -n team-a describe workload JOB_NAME
    
  7. Lorsque les jobs en attente commencent à augmenter à partir de la ressource ClusterQueue, arrêtez le script en appuyant sur CTRL + C sur le script en cours d'exécution.

  8. Une fois tous les jobs terminés, notez le scaling à la baisse des nœuds.

Effectuer un nettoyage

Pour éviter que les ressources utilisées lors de ce tutoriel soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et supprimez les ressources individuelles.

Supprimer le projet

  1. Dans la Google Cloud console, accédez à la page Gérer les ressources.

    Accéder à la page "Gérer les ressources"

  2. Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer.
  3. Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez Arrêter pour supprimer le projet.

Supprimer la ressource individuelle

  1. Supprimez le système de quota 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. Supprimez le fichier manifeste Kueue :

    VERSION=VERSION
    kubectl delete -f \
      https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/manifests.yaml
    
  3. Supprimez le cluster à l'aide de la commande suivante :

    gcloud container clusters delete kueue-autopilot --location=CONTROL_PLANE_LOCATION
    

Étapes suivantes