Gérer les interruptions de nœuds GKE pour les GPU et les TPU


Cette page vous aide à comprendre, configurer et surveiller les événements de perturbation susceptibles de se produire sur les nœuds Google Kubernetes Engine (GKE) exécutant des charges de travail d'intelligence artificielle (IA) ou de machine learning (ML), y compris :

Au cours du cycle de vie d'un cluster GKE de longue durée, des perturbations périodiques des charges de travail se produisent en raison d'événements de maintenance automatique émis par Google Cloud pour les ressources Compute Engine sous-jacentes à l'infrastructure GKE. Lorsque ces perturbations affectent vos nœuds GKE exécutant des charges de travail d'IA/de ML, GKE doit redémarrer à la fois les charges de travail en cours d'exécution et le nœud sous-jacent.

Pourquoi les GPU et les TPU nécessitent une gestion des interruptions

Vos clusters GKE gèrent le cycle de vie des nœuds GKE. Ces nœuds sont provisionnés sur des VM Compute Engine. Les VM Compute Engine sont régulièrement confrontées à des événements hôtes pour diverses raisons, telles que les mises à jour matérielles ou logicielles, la maintenance et les défaillances matérielles. Les événements hôtes sont émis pour l'infrastructure Google Cloud sous-jacente et contournent les règles et les exclusions de maintenance de GKE.

La plupart des VM Compute Engine, à quelques exceptions près, ont une stratégie de maintenance de l'hôte définie sur la migration à chaud, ce qui signifie que les charges de travail en cours d'exécution sont peu ou pas interrompues. Toutefois, certaines classes de VM ne sont pas compatibles avec la migration à chaud, y compris les VM avec des GPU et des TPU associés sur lesquels s'exécutent vos charges de travail d'IA/ML. De plus, GKE peut également redémarrer des TPU à la demande à l'aide de la préemption, ce qui lui permet de provisionner des TPU plus volumineux pour des raisons de défragmentation.

Lorsqu'un événement hôte se produit, GKE arrête le nœud et ses pods. Si les pods sont déployés dans le cadre d'une charge de travail plus importante, telle qu'un job ou un déploiement, GKE redémarre les pods sur le nœud concerné. C'est à vous ou aux frameworks que vous utilisez pour gérer les charges de travail ou les tâches de réagir de manière appropriée à l'interruption. Par exemple, vous pouvez enregistrer l'état de votre tâche d'entraînement d'IA pour réduire la perte de données.

Processus de résiliation concertée

Le workflow suivant montre comment GKE exécute l'arrêt optimal des nœuds après une interruption de Compute Engine :

  1. Compute Engine émet une valeur mise à jour de TERMINATE_ON_HOST_MAINTENANCE pour la clé de métadonnées de VM maintenance-event.
  2. Dans les 60 secondes qui suivent, les événements suivants se produisent :

    1. Les composants système appliquent le nouveau libellé de nœud suivant défini sur true pour indiquer que la maintenance est en cours : cloud.google.com/active-node-maintenance

    2. GKE applique le rejet de nœud pour empêcher la planification de nouveaux pods sur le nœud : cloud.google.com/impending-node-termination:NoSchedule. Nous vous recommandons de modifier les charges de travail afin de tolérer ce rejet en raison de l'arrêt connu qui se produit.

  3. Le composant maintenance-handler commence à évincer les pods par ordre de pods de charge de travail, puis de pods système (par exemple, kube-system).

  4. GKE envoie un signal d'arrêt SIGTERM pour alerter les pods de charge de travail en cours d'exécution sur le nœud d'un arrêt imminent. Les pods peuvent utiliser cette alerte pour terminer les tâches en cours. GKE s'efforce d'arrêter ces pods de manière élégante.

Les notifications maintenance-event se produisent lorsque la VM Compute Engine sous-jacente d'un nœud GKE subit un événement hôte perturbateur qui entraîne l'arrêt du nœud. Dans ce cas, Compute Engine met à jour la clé de métadonnées maintenance-event. L'intervalle de notification de maintenance avancée avant l'arrêt du nœud est le suivant :

  • GPU : 60 minutes.
  • TPU : 5 minutes.

Ensuite, l'arrêt du nœud se produit et un nœud de remplacement est attribué. GKE efface les libellés et les rejets une fois le processus terminé. Pour augmenter l'intervalle d'arrêt de vos charges de travail utilisant des GPU ou des TPU, suivez les étapes décrites dans la section Configurer GKE pour arrêter vos charges de travail en douceur.

Gérer les perturbations de la charge de travail dans GKE

Pour gérer les événements de fin de GKE et réduire les perturbations des charges de travail dans vos clusters, GKE surveille ces notifications à votre place et effectue les opérations suivantes :

  • GKE informe vos charges de travail à l'avance d'un arrêt imminent : lorsqu'un nœud GKE doit s'arrêter pour un événement de maintenance d'hôte, GKE envoie un signal SIGTERM aux pods en cours d'exécution sur le nœud au début de la période de préavis. Les signaux de l'OS tels que SIGTERM peuvent être gérés en mode natif par la plupart des bibliothèques standards, par exemple Python et Go. Les frameworks pouvant capturer SIGTERM incluent MaxText, Pax et JAX avec Orbax.
  • GKE arrête correctement vos charges de travail : vous pouvez configurer GKE pour qu'il arrête correctement vos charges de travail avec un délai de grâce de l'arrêt du pod. Les pods peuvent réagir au signal SIGTERM pour terminer toutes les tâches en cours et exécuter toute action d'arrêt que vous définissez, telle que la sauvegarde d'un état d'entraînement. Lors de l'arrêt progressif, GKE s'efforce d'arrêter les pods de manière appropriée et d'exécuter les processus de nettoyage ou l'action d'arrêt que vous définissez dans votre application, par exemple en stockant des données de charge de travail pour réduire la perte de données ou en enregistrant un état d'entraînement.

Configurer GKE pour qu'il arrête correctement vos charges de travail

Dans cette section, vous allez configurer GKE pour gérer le cycle de vie de votre application et minimiser les perturbations sur votre charge de travail. Si vous ne configurez pas de délai de grâce, celui-ci est défini par défaut sur 30 secondes.

GKE s'efforce d'arrêter ces pods correctement et d'exécuter l'action d'arrêt que vous définissez, par exemple en enregistrant un état d'entraînement. GKE envoie des signaux SIGTERM aux pods au début du délai de grâce. Si les pods ne s'arrêtent pas à la fin du délai de grâce, GKE envoie un signal SIGKILL de suivi à tous les processus toujours en cours d'exécution dans un conteneur du pod.

Pour configurer le délai de grâce pour les charges de travail, suivez les instructions pour les GPU ou les TPU.

GPU

Dans le fichier manifeste de votre pod, définissez le champ spec.terminationGracePeriodSeconds sur une valeur maximale de 3 600 secondes (60 minutes). Par exemple, pour obtenir une heure de notification de 10 minutes, dans le fichier manifeste de votre pod, définissez le champ spec.terminationGracePeriodSeconds sur 600 secondes comme suit :

    spec:
      terminationGracePeriodSeconds: 600

Nous vous recommandons de définir un délai de grâce avant l'arrêt suffisamment long pour que les tâches en cours se terminent dans le délai de notification.

TPU

Pour allouer la durée maximale d'exécution de vos processus de nettoyage, définissez le champ spec.terminationGracePeriodSeconds sur 300 secondes (cinq minutes) dans le fichier manifeste de votre pod. Exemple :

    spec:
      terminationGracePeriodSeconds: 300

Nous vous recommandons de définir un délai de grâce avant l'arrêt suffisamment long pour que les tâches en cours se terminent dans le délai de notification.

Si votre charge de travail utilise un framework de ML tel que MaxText, Pax ou JAX avec Orbax, les charges de travail peuvent capturer le signal SIGTERM et lancer un processus de création de points de contrôle. Pour en savoir plus, consultez la section Point de contrôle automatique TPU.

Surveiller la progression d'un délai de grâce avant arrêt actif

Dans les clusters GKE dont le plan de contrôle exécute la version 1.29.1-gke.1425000 ou ultérieure, GKE déploie un composant au niveau du nœud appelé gpu-maintenance-handler. Ce composant s'exécute sur tous les nœuds GPU et TPU, ainsi qu'un composant de plan de contrôle correspondant. Ces composants exercent les fonctions suivantes :

  • Traiter les événements de type arrêt progressif.
  • Répondre aux événements de perturbation imminents sur la VM GKE en transmettant un signal SIGTERM aux charges de travail en cours d'exécution d'un nœud. Ces interruptions sont consignées en tant que requêtes de répulsion de pod et de suppression.

GKE ajoute un libellé et un rejet aux nœuds dont l'arrêt est imminent. GKE surveille les notifications d'événements hôtes, comme la maintenance, à l'aide du composant système maintenance-handler exécuté sur chaque nœud GPU et TPU.

GKE consigne les événements d'arrêt progressif suivants :

Une fois que GKE termine l'arrêt progressif, les libellés et les rejets sont effacés.

Pour surveiller l'état d'un arrêt progressif actif causé par une interruption, vous pouvez afficher les journaux gpu-maintenance-handler à l'aide de la console ou de Google Cloud CLI.

gcloud

  1. Recherchez les noms des nœuds et des pods qui exécutent des instances de gpu-maintenance-handler à l'aide de la commande suivante :

    kubectl get pods -l name=maintenance-handler -A -o wide
    

    Chaque ligne de la sortie inclut le nom du nœud, le nom du pod et l'état.

  2. Vérifiez les journaux :

    kubectl logs -n=kube-system MAINTENANCE_HANDLER_POD_NAME
    

    Remplacez MAINTENANCE_HANDLER_POD_NAME par le nom de l'instance du gestionnaire.

    Si un événement de maintenance est détecté, le pod enregistre un message, applique les libellés et les évictions démarrent.

  3. Vérifiez les libellés et les rejets de nœuds :

    kubectl describe node NODE_NAME
    

    Remplacez NODE_NAME par le nom du nœud que vous souhaitez afficher.

    Le résultat affiche la liste des libellés de nœuds et rejets à surveiller.

Console

  1. Accédez à l'explorateur de journaux dans la console Google Cloud :

    Accéder à l'explorateur de journaux

  2. Dans le champ Requête, saisissez la requête suivante :

    resource.type="k8s_container"
    resource.labels.namespace_name="kube-system"
    resource.labels.container_name="maintenance-handler"
    resource.labels.cluster_name="CLUSTER_NAME"
    

    Remplacez CLUSTER_NAME par le nom de votre cluster.

Étape suivante