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


Ce tutoriel explique comment déployer un système de traitement par lots à l'aide de Kueue pour mettre un job en file d'attente sur Google Kubernetes Engine (GKE). Suivez ce tutoriel pour apprendre à configurer GKE et Kueue pour l'exécution des tâches dans un modèle de type "premier entré, premier sorti" (FIFO).

Contexte

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

Ce tutoriel s'adresse aux opérateurs de cluster et aux autres utilisateurs qui souhaitent mettre en œuvre un système de traitement par lots sur Kubernetes. Dans ce tutoriel, vous allez configurer un cluster partagé pour deux équipes locataires. Chaque équipe dispose de son propre espace de noms dans lequel elle crée des tâches et partage les mêmes ressources globales que celles contrôlées avec les quotas correspondants.

Ce tutoriel couvre les étapes suivantes :

  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 Google Cloud suivants :

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 compte Google Cloud. Si vous débutez sur Google Cloud, créez un compte pour évaluer les performances de nos produits en conditions réelles. Les nouveaux clients bénéficient également de 300 $ de crédits gratuits 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.

    Go to project selector

  3. Vérifiez que la facturation est activée pour votre projet Google Cloud.

  4. Activez l'API GKE

    Activer 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. Vérifiez que la facturation est activée pour votre projet Google Cloud.

  7. Activez l'API GKE

    Activer l'API

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

  1. Dans la console Google Cloud, 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 COMPUTE_REGION
    

    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" --region COMPUTE_REGION
    

    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 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 utilisé par les requêtes dans les spécifications du 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 processeurs 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 de l'espace 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

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 créés sous l'espace de noms team-a. Ce job pointe vers la ressource LocalQueue lq-team-a. Pour demander des ressources GPU, nodeSelector est défini sur nvidia-tesla-t4.

Le job est composé de trois pods qui dorment pendant 10 secondes en parallèle. Les jobs sont supprimés après 60 secondes selon ttlSecondsAfterFinished.

Ce job 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.

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 section 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 console Google Cloud, 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 sur 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 --region=COMPUTE_REGION
    

Étapes suivantes