Exécuter une charge de travail à grande échelle avec le démarrage flexible et le provisionnement en file d'attente

Cette page explique comment optimiser l'obtention de GPU pour les charges de travail par lot et d'IA à grande échelle avec des GPU à l'aide du démarrage flexible avec provisionnement en file d'attente optimisé par le planificateur de charges de travail dynamique.

Avant de lire cette page, assurez-vous de connaître les éléments suivants :

Ce guide est destiné aux ingénieurs en machine learning (ML), aux administrateurs et opérateurs de plate-forme, ainsi qu'aux spécialistes des données et de l'IA qui souhaitent utiliser les fonctionnalités d'orchestration de conteneurs Kubernetes pour exécuter des charges de travail par lot. Pour en savoir plus sur les rôles courants et les exemples de tâches que nous citons dans le contenu Google Cloud , consultez Rôles utilisateur et tâches courantes de GKE.

Fonctionnement du démarrage flexible avec provisionnement en file d'attente

Avec le démarrage flexible avec provisionnement en file d'attente, GKE alloue toutes les ressources demandées en même temps. Le démarrage flexible avec provisionnement en file d'attente utilise les outils suivants :

Pour utiliser le démarrage flexible avec le provisionnement en file d'attente, vous devez ajouter les options --flex-start et --enable-queued-provisioning lorsque vous créez le pool de nœuds.

Bonne pratique:

Utilisez le démarrage flexible avec provisionnement en file d'attente pour les charges de travail par lot et d'IA à grande échelle lorsque vos charges de travail répondent aux critères suivants :

  • Vos charges de travail ont des heures de début flexibles.
  • Vos charges de travail doivent s'exécuter sur plusieurs nœuds simultanément.

Pour les charges de travail plus petites qui peuvent s'exécuter sur un seul nœud, utilisez des VM à démarrage flexible. Pour en savoir plus sur le provisionnement de GPU dans GKE, consultez Obtenir des accélérateurs pour les charges de travail d'IA.

Avant de commencer

Avant de commencer, effectuez les tâches suivantes :

  • Activez l'API Google Kubernetes Engine.
  • Activer l'API Google Kubernetes Engine
  • Si vous souhaitez utiliser Google Cloud CLI pour cette tâche, installez puis initialisez gcloud CLI. Si vous avez déjà installé la gcloud CLI, obtenez la dernière version en exécutant la commande gcloud components update. Il est possible que les versions antérieures de gcloud CLI ne permettent pas d'exécuter les commandes de ce document.

Utiliser des pools de nœuds avec le démarrage flexible avec provisionnement en file d'attente

Cette section ne s'applique qu'aux clusters standards.

Vous pouvez utiliser l'une des méthodes suivantes pour indiquer que le démarrage flexible avec provisionnement en file d'attente peut fonctionner avec des pools de nœuds spécifiques dans votre cluster :

Créer un pool de nœuds

Créez un pool de nœuds avec flex-start et provisionnement en file d'attente activés à l'aide de la 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 \
    --flex-start \
    --enable-autoscaling  \
    --num-nodes=0   \
    --total-max-nodes TOTAL_MAX_NODES  \
    --location-policy=ANY  \
    --reservation-affinity=none  \
    --no-enable-autorepair

Remplacez les éléments suivants :

  • NODEPOOL_NAME : nom que vous avez choisi pour le pool de nœuds.
  • CLUSTER_NAME : nom du cluster.
  • LOCATION : région Compute Engine du cluster, telle que us-central1.
  • GPU_TYPE : type de GPU.
  • AMOUNT : nombre de GPU à associer aux nœuds du pool.
  • DRIVER_VERSION : version du pilote NVIDIA à installer. La valeur peut être l'une des suivantes :
    • default : installe la version de pilote par défaut pour votre version de GKE.
    • latest : installe la dernière version de pilote disponible pour votre version de GKE. Disponible seulement pour les nœuds qui utilisent Container-Optimized OS.
  • TOTAL_MAX_NODES : nombre maximal de nœuds pour effectuer le scaling automatique du pool de nœuds entier.
  • MACHINE_TYPE : type de machine Compute Engine pour vos nœuds.

    Bonne pratique:

    Utilisez un type de machine optimisé pour les accélérateurs afin d'améliorer les performances et l'efficacité des charges de travail d'IA/ML.

Vous pouvez éventuellement utiliser les options suivantes :

  • --node-locations=COMPUTE_ZONES : liste d'une ou de plusieurs zones, séparées par une virgule, dans lesquelles GKE crée les nœuds GPU. Ces zones doivent se trouver dans la même région que le cluster. Choisissez des zones disposant de GPU disponibles.
  • --enable-gvnic : cette option permet à gVNIC sur les pools de nœuds GPU d'augmenter la vitesse du trafic réseau.

Cette commande crée un pool de nœuds avec la configuration suivante :

  • L'indicateur --flex-start combiné à l'indicateur --enable-queued-provisioning indique à GKE de créer un pool de nœuds avec l'option de démarrage flexible et l'approvisionnement en file d'attente activés, et d'ajouter le taint cloud.google.com/gke-queued au pool de nœuds.
  • GKE active le provisionnement en file d'attente et l'autoscaling des clusters.
  • Le pool de nœuds ne contient initialement aucun nœud.
  • L'option --no-enable-autorepair désactive les réparations automatiques, ce qui peut perturber les charges de travail qui s'exécutent sur les nœuds réparés.

Activer le provisionnement automatique des nœuds afin de créer des pools de nœuds pour le démarrage flexible avec provisionnement en file d'attente

Vous pouvez utiliser le provisionnement automatique des nœuds pour gérer les pools de nœuds pour le démarrage flexible avec provisionnement en file d'attente pour les clusters exécutant la version 1.29.2-gke.1553000 ou ultérieure. Lorsque vous activez le provisionnement automatique des nœuds, GKE crée des pools de nœuds avec les ressources requises pour la charge de travail associée.

Pour activer le provisionnement automatique des nœuds, examinez les paramètres suivants et effectuez les étapes décrites dans la section Configurer les limites de GPU :

  • Spécifiez les ressources requises pour le démarrage flexible avec provisionnement mis en file d'attente lorsque vous activez la fonctionnalité. Pour lister les resourceTypes disponibles, exécutez la commande gcloud compute accelerator-types list.
  • Utilisez le flag --no-enable-autoprovisioning-autorepair pour désactiver la réparation automatique des nœuds.
  • Autorisez GKE à installer automatiquement les pilotes de GPU dans les nœuds GPU provisionnés automatiquement. Pour en savoir plus, consultez Installer des pilotes à l'aide du provisionnement automatique des nœuds avec des GPU.

Exécuter vos charges de travail par lot et d'IA avec le démarrage flexible avec provisionnement en file d'attente

Pour exécuter des charges de travail par lot avec démarrage flexible et provisionnement en file d'attente, utilisez l'une des configurations suivantes :

Bonne pratique :

Utilisez Kueue pour exécuter vos charges de travail par lot et d'IA avec un démarrage flexible et un provisionnement en file d'attente.

Démarrage flexible avec provisionnement en file d'attente pour les jobs avec Kueue

Les sections suivantes vous expliquent comment configurer le démarrage flexible avec provisionnement en file d'attente pour les jobs avec Kueue :

  • Configuration d'un pool de nœuds avec démarrage flexible et provisionnement en file d'attente.
  • Configuration d'un pool de nœuds avec réservation et démarrage flexible avec provisionnement en file d'attente.

Cette section utilise les exemples du répertoire dws-examples du dépôt ai-on-gke. Nous avons publié les exemples dans le répertoire dws-examples sous la licence Apache2.

Vous devez disposer des droits d'administrateur pour installer Kueue. Pour les obtenir, assurez-vous de disposer du rôle IAM roles/container.admin. Pour en savoir plus sur les rôles IAM GKE, consultez le guide de création de stratégies d'autorisation IAM.

Préparer votre environnement

  1. Dans Cloud Shell, exécutez la commande suivante :

    git clone https://github.com/GoogleCloudPlatform/ai-on-gke
    cd ai-on-gke/tutorials-and-examples/workflow-orchestration/dws-examples
    
  2. Installez la dernière version de Kueue dans votre cluster :

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

    Remplacez KUEUE_VERSION par la dernière version de Kueue.

Si vous utilisez Kueue dans une version antérieure à 0.7.0, modifiez la configuration de la feature gate Kueue en définissant la feature gate ProvisioningACC sur true. Pour en savoir plus et connaître les valeurs des portes par défaut, consultez la section Feature gates de Kueue. Pour en savoir plus sur l'installation de Kueue, consultez la section Installation.

Créer les ressources Kueue pour la configuration du pool de nœuds du planificateur de charges de travail dynamique uniquement

Avec le fichier manifeste suivant, vous créez une file d'attente au niveau du cluster nommée dws-cluster-queue et l'espace de noms LocalQueue nommé dws-local-queue. Les jobs qui font référence à la file d'attente dws-cluster-queue dans cet espace de noms utilisent le démarrage flexible avec provisionnement en file d'attente pour obtenir les ressources 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: 1000000000 # "Infinite" quota
            - name: "memory"
              nominalQuota: 1000000000Gi # "Infinite" quota
            - name: "nvidia.com/gpu"
              nominalQuota: 1000000000 # "Infinite" quota
            - name: "ephemeral-storage"
              nominalQuota: 1000000000Ti # "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"
---
apiVersion: monitoring.googleapis.com/v1
kind: PodMonitoring
metadata:
  labels:
    control-plane: controller-manager
  name: controller-manager-metrics-monitor
  namespace: kueue-system
spec:
  endpoints:
    - path: /metrics
      port: 8080
      scheme: http
      interval: 30s
  selector:
    matchLabels:
      control-plane: controller-manager
---

La file d'attente de ce cluster présente des limites de quota élevées. Seule l'intégration du démarrage flexible avec provisionnement en file d'attente est activée. Pour en savoir plus sur les API Kueue et sur la configuration des limites, consultez Concepts de Kueue.

Déployez la file d'attente locale :

kubectl create -f ./dws-queues.yaml

Le résultat ressemble à ce qui suit :

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

Si vous souhaitez exécuter des jobs qui utilisent le démarrage Flex avec provisionnement en file d'attente dans d'autres espaces de noms, vous pouvez créer des LocalQueues supplémentaires à l'aide du modèle précédent.

Exécuter votre tâche

Dans le fichier manifeste suivant, l'exemple de job utilise le démarrage flexible avec provisionnement mis en file d'attente :

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

Ce fichier manifeste inclut les champs suivants qui sont pertinents pour la configuration du démarrage flexible avec provisionnement en file d'attente :

  • Le libellé kueue.x-k8s.io/queue-name: dws-local-queue indique à GKE que Kueue est responsable de l'orchestration de ce job. Ce libellé définit également la file d'attente dans laquelle le job est mis en file d'attente.
  • L'option suspend: true indique à GKE de créer la ressource de job, mais de ne pas encore planifier les pods. Kueue remplace cet indicateur par false lorsque les nœuds sont prêts pour l'exécution du job.
  • nodeSelector indique à GKE de ne planifier le job que sur le pool de nœuds spécifié. La valeur doit correspondre à NODEPOOL_NAME, le nom du pool de nœuds avec le provisionnement en file d'attente activé.
  1. Exécutez votre tâche :

    kubectl create -f ./job.yaml
    

    Le résultat ressemble à ce qui suit :

    job.batch/sample-job created
    
  2. Vérifiez l'état de votre job :

    kubectl describe job sample-job
    

    Le résultat ressemble à ce qui suit :

    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
    

L'intégration de flex-start avec provisionnement en file d'attente avec Kueue est également compatible avec d'autres types de charges de travail disponibles dans l'écosystème Open Source, comme par exemple :

  • RayJob
  • JobSet v0.5.2 ou version ultérieure
  • Kubeflow MPIJob, TFJob, PyTorchJob.
  • Pods Kubernetes fréquemment utilisés par les orchestrateurs de workflow
  • Mini-cluster de flux

Pour en savoir plus sur cette compatibilité, consultez Utilisateur de lot de Kueue.

Créer les ressources Kueue pour la configuration des pools de nœuds de réservation et du planificateur de charges de travail dynamique

Avec le fichier manifeste suivant, vous créez deux ResourceFlavors associés à deux pools de nœuds différents : reservation-nodepool et dws-nodepool. Les noms de ces pools de nœuds ne sont fournis qu'à titre d'exemple. Modifiez ces noms en fonction de la configuration de votre pool de nœuds. De plus, avec la configuration ClusterQueue, les jobs entrants tentent d'utiliser reservation-nodepool. S'il n'y a pas de capacité, ces jobs utilisent le planificateur de charges de travail dynamique pour obtenir les ressources 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: 1000000000 # "Infinite" quota
            - name: "memory"
              nominalQuota: 1000000000Gi # "Infinite" quota
            - name: "nvidia.com/gpu"
              nominalQuota: 1000000000 # "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 file d'attente de ce cluster présente des limites de quota élevées. Seule l'intégration du démarrage flexible avec provisionnement en file d'attente est activée. Pour en savoir plus sur les API Kueue et sur la configuration des limites, consultez Concepts de Kueue.

Déployez le fichier manifeste à l'aide de la commande suivante :

kubectl create -f ./dws_and_reservation.yaml

Le résultat ressemble à ce qui suit :

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

Exécuter votre tâche

Contrairement à la configuration précédente, ce fichier manifeste n'inclut pas le champ nodeSelector, car il est rempli par Kueue en fonction de la capacité disponible dans 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. Exécutez votre tâche :

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

    Le résultat ressemble à ce qui suit :

    job.batch/sample-job-v8xwm created
    

Pour identifier le pool de nœuds utilisé par votre job, vous devez déterminer le ResourceFlavor utilisé par votre job.

Dépannage

Pour en savoir plus sur le dépannage de Kueue, consultez Résoudre les problèmes liés aux requêtes de provisionnement dans Kueue.

Démarrage flexible avec provisionnement en file d'attente pour les jobs sans Kueue

Définir un objet ProvisioningRequest

Créez une requête via la demande de provisionnement pour chaque job. Le démarrage flexible avec provisionnement en file d'attente ne démarre pas les pods. Il provisionne uniquement les nœuds.

  1. Créez le fichier manifeste provisioning-request.yaml suivant :

    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
          cloud.google.com/gke-flex-start: "true"
        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
    

    Remplacez les éléments suivants :

    • API_VERSION : version de l'API, v1 ou v1beta1. Nous vous recommandons d'utiliser la version v1 pour plus de stabilité et pour accéder aux dernières fonctionnalités.
    • NAMESPACE_NAME : nom de votre espace de noms Kubernetes. L'espace de noms doit être identique à celui des pods.
    • PROVISIONING_REQUEST_NAME : le nom du ProvisioningRequest. Vous ferez référence à ce nom dans l'annotation de pod.
    • MAX_RUN_DURATION_SECONDS (facultatif) : durée d'exécution maximale d'un nœud en secondes, jusqu'à la valeur par défaut de sept jours. Pour en savoir plus, consultez Fonctionnement du démarrage flexible avec provisionnement en file d'attente. Vous ne pouvez pas modifier cette valeur après la création de la requête. Ce champ est disponible dans GKE version 1.28.5-gke.1355000 ou ultérieure.
    • COUNT : nombre de pods demandés. Les nœuds sont programmés de manière atomique dans une zone.
    • POD_TEMPLATE_NAME : le nom du PodTemplate.
    • NODEPOOL_NAME : nom que vous avez choisi pour le pool de nœuds. Supprimez cette ligne si vous souhaitez utiliser un pool de nœuds provisionné automatiquement.

    GKE peut appliquer des validations et des mutations aux pods lors de leur création. Le libellé cloud.google.com/apply-warden-policies permet à GKE d'appliquer les mêmes validations et mutations aux objets PodTemplate. Ce libellé est nécessaire pour que GKE puisse calculer les besoins en ressources des nœuds pour vos pods. L'intégration du démarrage flexible avec provisionnement en file d'attente n'accepte qu'une seule spécification PodSet. Si vous souhaitez combiner différents modèles de pods, utilisez celui qui présente le plus grand nombre de demandes de ressources. Il n'est pas possible de combiner différents types de machines tels que des VM avec différents types de GPU.

    Provisionnement automatique des nœuds

    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
          cloud.google.com/gke-flex-start: "true"
        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
    

    Remplacez les éléments suivants :

    • API_VERSION : version de l'API, v1 ou v1beta1. Nous vous recommandons d'utiliser la version v1 pour plus de stabilité et pour accéder aux dernières fonctionnalités.
    • NAMESPACE_NAME : nom de votre espace de noms Kubernetes. L'espace de noms doit être identique à celui des pods.
    • PROVISIONING_REQUEST_NAME : le nom du ProvisioningRequest. Vous ferez référence à ce nom dans l'annotation de pod.
    • MAX_RUN_DURATION_SECONDS (facultatif) : durée d'exécution maximale d'un nœud en secondes, jusqu'à la valeur par défaut de sept jours. Pour en savoir plus, consultez Fonctionnement du démarrage flexible avec provisionnement en file d'attente. Vous ne pouvez pas modifier cette valeur après la création de la requête. Ce champ est disponible dans GKE version 1.28.5-gke.1355000 ou ultérieure.
    • COUNT : nombre de pods demandés. Les nœuds sont programmés de manière atomique dans une zone.
    • POD_TEMPLATE_NAME : le nom du PodTemplate.
    • GPU_TYPE : type de matériel GPU.

    GKE peut appliquer des validations et des mutations aux pods lors de leur création. Le libellé cloud.google.com/apply-warden-policies permet à GKE d'appliquer les mêmes validations et mutations aux objets PodTemplate. Ce libellé est nécessaire pour que GKE puisse calculer les besoins en ressources des nœuds pour vos pods.

  2. Appliquez le fichier manifeste :

    kubectl apply -f provisioning-request.yaml
    

Configurer les pods

Cette section utilise des jobs Kubernetes pour configurer les pods. Cependant, vous pouvez aussi utiliser un JobSet Kubernetes ou tout autre framework tel que Kubeflow, Ray ou des contrôleurs personnalisés. Dans la spécification Job, associez les pods à ProvisioningRequest à l'aide des annotations suivantes :

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:
      ...

La clé d'annotation de pod consume-provisioning-request définit la ProvisioningRequest à utiliser. GKE utilise les annotations consume-provisioning-request et provisioning-class-name pour effectuer les opérations suivantes :

  • Programmer les pods uniquement dans les nœuds provisionnés par démarrage flexible avec provisionnement en file d'attente.
  • Éviter de comptabiliser deux fois les demandes de ressources entre les pods et le démarrage flexible avec provisionnement en file d'attente dans l'autoscaler de cluster.
  • Injecter une annotation safe-to-evict: false afin d'empêcher l'autoscaler de cluster de déplacer des pods entre les nœuds et d'interrompre les calculs par lot. Vous pouvez modifier ce comportement en spécifiant safe-to-evict: true dans les annotations de pod.

Observer l'état d'une demande de provisionnement

L'état d'une requête ProvisioningRequest indique si un pod peut être planifié ou non. Vous pouvez utiliser les requêtes watch Kubernetes pour observer les modifications efficacement ou d'autres outils que vous utilisez déjà pour suivre l'état des objets Kubernetes. Le tableau suivant décrit l'état possible d'une requête ProvisioningRequest et chaque résultat possible :

État de la demande de provisionnement Description Résultat possible
En attente La requête n'a pas encore été consultée et traitée. Après le traitement, la requête passe à l'état Accepted ou Failed.
Accepted=true La requête est acceptée et attend que des ressources soient disponibles. La requête doit passer à l'état Provisioned si des ressources ont été trouvées et que les nœuds ont été provisionnés, ou à l'état Failed si cela n'est pas possible.
Provisioned=true Les nœuds sont prêts. Vous avez 10 minutes pour démarrer les pods et utiliser les ressources provisionnées. Passé ce délai, l'autoscaler de cluster considère les nœuds comme non nécessaires et les supprime.
Failed=true Les nœuds ne peuvent pas être provisionnés en raison d'erreurs. Failed=true correspond à un état final. Résolvez la condition en fonction des informations spécifiées dans ses champs Reason et Message. Créez et relancez une requête ProvisioningRequest.
Provisioned=false Les nœuds n'ont pas encore été provisionnés.

Si la valeur est Reason=NotProvisioned, il s'agit d'un état temporaire avant que toutes les ressources ne soient disponibles.

Si la valeur est Reason=QuotaExceeded, corrigez la condition en fonction de ce motif et des informations contenues dans le champ Message de la condition. Vous devrez peut-être demander plus de quota. Pour en savoir plus, consultez la section Vérifier si la requête de provisionnement est limitée par un quota. Ce Reason n'est disponible qu'avec GKE version 1.29.2-gke.1181000 ou ultérieure.

Si Reason=ResourcePoolExhausted et que Message contient Expected time is indefinite, sélectionnez une autre zone ou région, ou ajustez les ressources demandées.

Démarrer les pods

Lorsque la requête ProvisioningRequest atteint l'état Provisioned=true, vous pouvez exécuter votre job pour démarrer les pods. Cela évite la prolifération des pods non programmables pour les requêtes en attente ou ayant échoué, ce qui peut affecter les performances de kube-scheduler et de l'autoscaler de cluster.

Si vous n'avez pas besoin de pods non programmables, vous pouvez également créer des pods en parallèle avec la demande de requête de provisionnement.

Annuler la demande ProvisioningRequest

Pour annuler la requête avant son provisionnement, vous pouvez supprimer ProvisioningRequest :

kubectl delete provreq PROVISIONING_REQUEST_NAME -n NAMESPACE

Dans la plupart des cas, la suppression de ProvisioningRequest empêche la création de nœuds. Toutefois, selon la planification, par exemple si des nœuds étaient déjà provisionnés, ils peuvent quand même être créés. Dans ce cas, l'autoscaler de cluster supprime les nœuds au bout de 10 minutes si aucun pod n'est créé.

Résoudre les problèmes de quota

Toutes les VM provisionnées par les requêtes de provisionnement utilisent des quotas préemptifs.

Le nombre de ProvisioningRequests à l'état Accepted est limité par un quota dédié. Vous configurez le quota pour chaque projet, une configuration de quota par région.

Vérifier le quota dans la console Google Cloud

Pour vérifier le nom de la limite de quota et l'utilisation actuelle dans la consoleGoogle Cloud , procédez comme suit :

  1. Accédez à la page Quotas dans la console Google Cloud  :

    Accéder à la section "Quotas"

  2. Dans la zone Filtre , sélectionnez la propriété Métrique, saisissez active_resize_requests, puis appuyez sur Entrée.

La valeur par défaut est 100. Pour augmenter le quota, suivez les étapes décrites dans Demander un ajustement de quota.

Vérifier si la requête ProvisioningRequest est limitée par un quota

Si le traitement de votre requête ProvisioningRequest prend plus de temps que prévu, vérifiez qu'elle n'est pas limitée par un quota. Vous devrez peut-être demander une augmentation de quota.

Pour les clusters exécutant la version 1.29.2-gke.1181000 ou ultérieure, vérifiez si des limites de quota spécifiques empêchent le traitement de votre requête :

kubectl describe provreq PROVISIONING_REQUEST_NAME \
    --namespace NAMESPACE

Le résultat ressemble à ce qui suit :

…
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
…

Dans cet exemple, GKE ne peut pas déployer les nœuds, car le quota est insuffisant dans la région europe-west4.

Migrer des pools de nœuds du provisionnement en file d'attente vers le démarrage Flex

L'option de consommation Démarrage flexible permet de créer des VM à démarrage flexible. Pour migrer des pools de nœuds existants créés à l'aide de l'option --enable-queued-provisioning afin d'utiliser le démarrage flexible, procédez comme suit :

  1. Assurez-vous que le pool de nœuds est vide :

    kubectl get nodes -l cloud.google.com/gke-nodepool=NODEPOOL_NAME
    
  2. Mettez à jour le pool de nœuds pour utiliser des VM à démarrage flexible :

    gcloud container node-pools update NODEPOOL_NAME \
      --cluster=CLUSTER_NAME --flex-start
    

Cette opération effectue les opérations suivantes :

  • Mettez à jour le pool de nœuds pour qu'il devienne un pool de nœuds de VM Flex-start.
  • Appliquez la tarification des nœuds qui utilisent des VM à démarrage flexible.

Tous les nœuds des clusters exécutés sur la version 1.32.2-gke.1652000 ou ultérieure (version minimale pour les nœuds qui utilisent des VM à démarrage flexible) utilisent des mises à niveau de courte durée.

Étapes suivantes