Résoudre les problèmes liés aux TPU dans GKE


Cette page explique comment résoudre les problèmes liés aux TPU dans Google Kubernetes Engine (GKE).

Si vous avez besoin d'aide supplémentaire, contactez l'assistance Cloud Customer Care.

Quota insuffisant pour répondre à la demande de TPU

Une erreur semblable à Insufficient quota to satisfy the request indique que votre projet Google Cloud ne dispose pas d'un quota suffisant pour répondre à la requête.

Pour résoudre ce problème, vérifiez la limite de quota et l'utilisation actuelle de votre projet. Si nécessaire, demandez une augmentation de votre quota de TPU.

Vérifier la limite de quota et l'utilisation actuelle

Pour vérifier la limite et l'utilisation actuelle de votre quota d'API Compute Engine pour les TPU, procédez comme suit :

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

    Accéder à la section "Quotas"

  2. Dans la zone  Filtre, procédez comme suit :

    1. Sélectionnez la propriété Service, saisissez API Compute Engine, puis appuyez sur Entrée.

    2. Sélectionnez la propriété Type et choisissez Quota.

    3. Sélectionnez la propriété Dimensions (par exemple, emplacements) et saisissez region: suivi du nom de la région dans laquelle vous prévoyez de créer des TPU dans GKE. Par exemple, saisissez region:us-west4 si vous envisagez de créer des nœuds de tranche TPU dans la zone us-west4-a. Le quota de TPU est régional. Par conséquent, toutes les zones d'une même région consomment le même quota de TPU.

Si aucun quota ne correspond au filtre que vous avez saisi, le projet ne dispose d'aucun quota pour la région souhaitée et vous devez demander une augmentation de quota TPU.

Erreur lors de l'activation du provisionnement automatique des nœuds dans un pool de nœuds de tranche TPU

L'erreur suivante se produit lorsque vous activez le provisionnement automatique des nœuds dans un cluster GKE non compatible avec les TPU.

Le message d'erreur ressemble à ceci :

ERROR: (gcloud.container.clusters.create) ResponseError: code=400,
  message=Invalid resource: tpu-v4-podslice.

Pour résoudre ce problème, mettez à niveau votre cluster GKE vers la version 1.27.6 ou ultérieure.

GKE ne provisionne pas automatiquement les nœuds des tranches TPU

Les sections suivantes décrivent les cas où GKE ne provisionne pas automatiquement les nœuds des tranches TPU, et comment les résoudre.

Limiter les erreurs de configuration

GKE ne provisionne pas automatiquement les nœuds des tranches TPU si les limites de provisionnement automatique que vous avez définies pour un cluster sont trop faibles. Vous pouvez rencontrer les erreurs suivantes dans de tels scénarios :

  • Si un pool de nœuds des tranches TPU existe, mais que GKE ne peut pas effectuer un scaling à la hausse des nœuds en raison des limites de ressources, le message d'erreur suivant peut s'afficher lors de l'exécution de la commande kubectl get events :

    11s Normal NotTriggerScaleUp pod/tpu-workload-65b69f6c95-ccxwz pod didn't
    trigger scale-up: 1 node(s) didn't match Pod's node affinity/selector, 1 max
    cluster cpu, memory limit reached
    

    En outre, dans ce scénario, des messages d'avertissement semblables à ceux-ci peuvent s'afficher dans la console Google Cloud :

    "Your cluster has one or more unschedulable Pods"
    
  • Lorsque GKE tente de provisionner automatiquement un pool de nœuds des tranches TPU dépassant les limites de ressources, les journaux de visibilité de l'autoscaler de cluster affichent le message d'erreur suivant :

    messageId: "no.scale.up.nap.pod.zonal.resources.exceeded"
    

    En outre, dans ce scénario, des messages d'avertissement semblables à ceux-ci peuvent s'afficher dans la console Google Cloud :

    "Can't scale up because node auto-provisioning can't provision a node pool for
    the Pod if it would exceed resource limits"
    

Pour résoudre ces problèmes, augmentez le nombre maximal de puces TPU, de cœurs de processeur et de mémoire dans le cluster.

Pour effectuer cette procédure, procédez comme suit :

  1. Calculez les besoins en ressources d'un type de machine TPU et d'un nombre donné. Notez que vous devez ajouter des ressources pour les pools de nœuds des tranches non TPU, tels que les charges de travail système.
  2. Obtenez une description du TPU, du processeur et de la mémoire disponibles pour un type de machine et une zone spécifiques. Utiliser la CLI gcloud

    gcloud compute machine-types describe MACHINE_TYPE \
        --zone COMPUTE_ZONE
    

    Remplacez les éléments suivants :

    • MACHINE_TYPE : type de machine à rechercher.
    • COMPUTE_ZONE : nom de la zone de calcul.

    Le résultat inclut une ligne de description semblable à celle-ci :

      description: 240 vCPUs, 407 GB RAM, 4 Google TPUs
      ```
    
  3. Calculez le nombre total de processeurs et de mémoire en multipliant ces quantités par le nombre de nœuds requis. Par exemple, le type de machine ct4p-hightpu-4t utilise 240 cœurs de processeur et 407 Go de RAM avec 4 puces TPU. En supposant que vous ayez besoin de 20 puces TPU, correspondant à cinq nœuds, vous devez définir les valeurs suivantes :

    • --max-accelerator=type=tpu-v4-podslice,count=20.
    • CPU = 1200 (240 x 5)
    • memory = 2035 (407 x 5)

    Vous devez définir des limites avec une certaine marge pour les nœuds des tranches non TPU, tels que les charges de travail système.

  4. Mettez à jour les limites du cluster :

    gcloud container clusters update CLUSTER_NAME \
        --max-accelerator type=TPU_ACCELERATOR \
        count=MAXIMUM_ACCELERATOR \
        --max-cpu=MAXIMUM_CPU \
        --max-memory=MAXIMUM_MEMORY
    

    Remplacez les éléments suivants :

    • CLUSTER_NAME : nom du cluster.
    • TPU_ACCELERATOR : nom de l'accélérateur TPU.
    • MAXIMUM_ACCELERATOR : nombre maximal de puces TPU dans le cluster.
    • MAXIMUM_CPU : nombre maximal de cœurs dans le cluster.
    • MAXIMUM_MEMORY : quantité maximale de mémoire dans le cluster, en gigaoctets.

Toutes les instances ne sont pas en cours d'exécution

ERROR: nodes cannot be created due to lack of capacity. The missing nodes
will be created asynchronously once capacity is available. You can either
wait for the nodes to be up, or delete the node pool and try re-creating it
again later.

Cette erreur peut s'afficher lorsque l'opération GKE a expiré ou que la requête ne peut pas être traitée et mise en file d'attente pour le provisionnement de pools de nœuds TPU à hôte unique ou multi-hôte. Pour éviter les problèmes de capacité, vous pouvez utiliser des réservations ou envisager des VM Spot.

Mauvaise configuration de la charge de travail

Cette erreur se produit en raison d'une mauvaise configuration de la charge de travail. Voici quelques-unes des causes d'erreur les plus courantes :

  • Les libellés cloud.google.com/gke-tpu-accelerator et cloud.google.com/gke-tpu-topology sont incorrects ou manquants dans la spécification de pod. GKE ne provisionne pas de pools de nœuds des tranches TPU et le provisionnement automatique des nœuds ne peut pas effectuer un scaling à la hausse du cluster.
  • La spécification de pod ne spécifie pas google.com/tpu dans ses besoins en ressources.

Pour résoudre ce problème, effectuez l'une des opérations suivantes :

  1. Vérifiez qu'il n'existe aucun libellé non compatible dans le sélecteur de nœud de votre charge de travail. Par exemple, un sélecteur de nœuds pour le libellé cloud.google.com/gke-nodepool empêche GKE de créer des pools de nœuds supplémentaires pour vos pods.
  2. Assurez-vous que les spécifications du modèle de pod, dans lesquelles la charge de travail de votre TPU s'exécute, incluent les valeurs suivantes :
    • Les libellés cloud.google.com/gke-tpu-accelerator et cloud.google.com/gke-tpu-topology dans son nodeSelector.
    • google.com/tpu dans sa requête.

Pour savoir comment déployer des charges de travail TPU dans GKE, consultez la page Exécuter une charge de travail qui affiche le nombre de puces TPU disponibles dans un pool de nœuds des tranches TPU.

Erreurs de programmation lors du déploiement de pods consommant des TPU dans GKE

Le problème suivant se produit lorsque GKE ne peut pas planifier les pods demandant des TPU sur des nœuds des tranches TPU. Par exemple, cela peut se produire si certaines tranches non TPU ont déjà été programmées sur des nœuds TPU.

Le message d'erreur, émis en tant qu'événement FailedScheduling sur le pod, se présente comme suit :

Cannot schedule pods: Preemption is not helpful for scheduling.

Error message: 0/2 nodes are available: 2 node(s) had untolerated taint
{google.com/tpu: present}. preemption: 0/2 nodes are available: 2 Preemption is
not helpful for scheduling

Pour résoudre ce problème, procédez comme suit :

Vérifiez que votre cluster comporte au moins un pool de nœuds CPU afin que les pods critiques du système puissent s'exécuter dans les nœuds non TPU. Pour en savoir plus, consultez la page Déployer un pod sur un pool de nœuds spécifique.

Résoudre les problèmes courants liés aux JobSets dans GKE

Pour connaître les problèmes courants liés à JobSet et obtenir des suggestions de dépannage, consultez la page Dépannage JobSet. Cette page traite des problèmes courants tels que l'erreur "Webhook non disponible", les jobs enfants ou les pods qui ne sont pas créés, et le problème de reprise des charges de travail préemptées à l'aide de JobSet et de Kueue.

Échec de l'initialisation du TPU

Le problème suivant se produit lorsque GKE ne peut pas provisionner de nouvelles charges de travail TPU en raison d'un manque d'autorisation d'accès aux appareils TPU.

Le message d'erreur ressemble à ceci :

TPU platform initialization failed: FAILED_PRECONDITION: Couldn't mmap: Resource
temporarily unavailable.; Unable to create Node RegisterInterface for node 0,
config: device_path: "/dev/accel0" mode: KERNEL debug_data_directory: ""
dump_anomalies_only: true crash_in_debug_dump: false allow_core_dump: true;
could not create driver instance

Pour résoudre ce problème, veillez à exécuter votre conteneur TPU en mode privilégié ou à augmenter ulimit dans votre conteneur.

Planifier un interblocage

La programmation d'au moins deux tâches peut résulter en un interblocage. Par exemple, dans le scénario où tous les événements suivants se produisent :

  • Vous avez deux jobs (job A et job B) avec des règles d'affinité de pod. GKE planifie les tranches de TPU des deux jobs avec une topologie TPU de v4-32.
  • Vous disposez de deux tranches de TPU v4-32 dans le cluster.
  • Votre cluster dispose d'une capacité suffisante pour planifier les deux jobs et, en théorie, chaque job peut être rapidement planifié sur chaque tranche de TPU.
  • Le programmeur Kubernetes planifie un pod du job A sur une tranche, puis en planifie un autre pour le job B sur la même tranche.

Dans ce cas, en fonction des règles d'affinité de pod du job A, le programmeur tente de planifier tous les pods restants des jobs A et B, chacun sur une seule tranche de TPU. Par conséquent, GKE ne peut pas planifier entièrement le job A ou le job B. L'état des deux jobs reste donc en attente.

Pour résoudre ce problème, utilisez l'anti-affinité de pod avec cloud.google.com/gke-nodepool comme topologyKey, comme indiqué dans l'exemple suivant :

apiVersion: batch/v1
kind: Job
metadata:
 name: pi
spec:
 parallelism: 2
 template:
   metadata:
     labels:
       job: pi
   spec:
     affinity:
       podAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
         - labelSelector:
             matchExpressions:
             - key: job
               operator: In
               values:
               - pi
           topologyKey: cloud.google.com/gke-nodepool
       podAntiAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
         - labelSelector:
             matchExpressions:
             - key: job
               operator: NotIn
               values:
               - pi
           topologyKey: cloud.google.com/gke-nodepool
           namespaceSelector:
             matchExpressions:
             - key: kubernetes.io/metadata.name
               operator: NotIn
               values:
               - kube-system
     containers:
     - name: pi
       image: perl:5.34.0
       command: ["sleep",  "60"]
     restartPolicy: Never
 backoffLimit: 4

Autorisation refusée lors de la création du cluster dans us-central2

Si vous essayez de créer un cluster dans la région us-central2 (seule région où les TPU v4 sont disponibles), vous pouvez rencontrer un message d'erreur semblable à celui-ci :

ERROR: (gcloud.container.clusters.create) ResponseError: code=403,
message=Permission denied on 'locations/us-central2' (or it may not exist).

Cette erreur est due au fait que la région us-central2 est une région privée.

Pour résoudre ce problème, envoyez une demande d'assistance ou contactez l'équipe chargée de votre compte pour demander à ce que la région us-central2 soit rendue visible au sein de votre projet Google Cloud.

Quota insuffisant lors de la création d'un pool de nœuds TPU dans la région us-central2

Si vous essayez de créer un pool de nœuds des tranches TPU dans us-central2 (seule région où les TPU v4 sont disponibles), vous devrez peut-être augmenter les quotas suivants liés à GKE lors de la création initiale des pools de nœuds TPU v4 :

  • SSD Persistent Disk (Go) dans la région us-central2 : le disque de démarrage de chaque nœud Kubernetes nécessite 100 Go par défaut. Par conséquent, ce quota doit être défini au moins aussi haut que le produit du nombre maximal de nœuds GKE que vous prévoyez de créer dans us-central2 et 100 Go (maximum_nodes X 100 GB).
  • Quota d'adresses IP en cours d'utilisation dans la région us-central2 : chaque nœud Kubernetes consomme une adresse IP. Par conséquent, ce quota doit être défini au moins aussi haut que le nombre maximal de nœuds GKE que vous prévoyez de créer dans us-central2.

Sous-réseau manquant lors de la création du cluster GKE

Si vous essayez de créer un cluster dans la région us-central2 (seule région où les TPU v4 sont disponibles), vous pouvez rencontrer un message d'erreur semblable à celui-ci :

ERROR: (gcloud.container.clusters.create) ResponseError: code=404,
message=Not found: project <PROJECT> does not have an auto-mode subnetwork
for network "default" in region <REGION>.

Vous devez ajouter un sous-réseau dans votre réseau VPC pour fournir la connectivité à vos nœuds GKE. Toutefois, dans certaines régions telles que us-central2, un sous-réseau par défaut ne peut pas être créé, même lorsque vous utilisez le réseau VPC par défaut en mode automatique (pour la création de sous-réseau).

Pour résoudre ce problème, assurez-vous d'avoir créé un sous-réseau personnalisé dans la région avant de créer votre cluster GKE. Ce sous-réseau ne doit pas chevaucher d'autres sous-réseaux créés dans d'autres régions sur le même réseau VPC.

Afficher les journaux TPU GKE

Pour afficher tous les journaux liés aux TPU pour une charge de travail spécifique, Cloud Logging propose un emplacement centralisé permettant d'interroger ces journaux lorsque la journalisation du système et de la charge de travail GKE est activée. Dans Cloud Logging, les journaux sont organisés en entrées de journal, et chaque entrée de journal a un format structuré. Voici un exemple d'entrée de journal de tâche d'entraînement TPU.

{
  insertId: "gvqk7r5qc5hvogif"
  labels: {
  compute.googleapis.com/resource_name: "gke-tpu-9243ec28-wwf5"
  k8s-pod/batch_kubernetes_io/controller-uid: "443a3128-64f3-4f48-a4d3-69199f82b090"
  k8s-pod/batch_kubernetes_io/job-name: "mnist-training-job"
  k8s-pod/controller-uid: "443a3128-64f3-4f48-a4d3-69199f82b090"
  k8s-pod/job-name: "mnist-training-job"
}
logName: "projects/gke-tpu-demo-project/logs/stdout"
receiveTimestamp: "2024-06-26T05:52:39.652122589Z"
resource: {
  labels: {
    cluster_name: "tpu-test"
    container_name: "tensorflow"
    location: "us-central2-b"
    namespace_name: "default"
    pod_name: "mnist-training-job-l74l8"
    project_id: "gke-tpu-demo-project"
}
  type: "k8s_container"
}
severity: "INFO"
textPayload: "
  1/938 [..............................] - ETA: 13:36 - loss: 2.3238 - accuracy: 0.0469
  6/938 [..............................] - ETA: 9s - loss: 2.1227 - accuracy: 0.2995   
 13/938 [..............................] - ETA: 8s - loss: 1.7952 - accuracy: 0.4760
 20/938 [..............................] - ETA: 7s - loss: 1.5536 - accuracy: 0.5539
 27/938 [..............................] - ETA: 7s - loss: 1.3590 - accuracy: 0.6071
 36/938 [>.............................] - ETA: 6s - loss: 1.1622 - accuracy: 0.6606
 44/938 [>.............................] - ETA: 6s - loss: 1.0395 - accuracy: 0.6935
 51/938 [>.............................] - ETA: 6s - loss: 0.9590 - accuracy: 0.7160
……
937/938 [============================>.] - ETA: 0s - loss: 0.2184 - accuracy: 0.9349"
timestamp: "2024-06-26T05:52:38.962950115Z"
}

Chaque entrée de journal des nœuds de tranche de TPU porte le libellé compute.googleapis.com/resource_name avec la valeur définie comme nom de nœud. Si vous souhaitez afficher les journaux d'un nœud spécifique et que vous connaissez son nom, vous pouvez filtrer les journaux par ce nœud dans votre requête. Par exemple, la requête suivante affiche les journaux du nœud TPU gke-tpu-9243ec28-wwf5 :

resource.type="k8s_container"
labels."compute.googleapis.com/resource_name" = "gke-tpu-9243ec28-wwf5"

GKE associe les étiquettes cloud.google.com/gke-tpu-accelerator et cloud.google.com/gke-tpu-topology à tous les nœuds contenant des TPU. Par conséquent, si vous ne connaissez pas le nom du nœud ou si vous souhaitez lister tous les nœuds de segment TPU, vous pouvez exécuter la commande suivante :

kubectl get nodes -l cloud.google.com/gke-tpu-accelerator

Exemple de résultat :

NAME                    STATUS   ROLES    AGE     VERSION
gke-tpu-9243ec28-f2f1   Ready    <none>   25m     v1.30.1-gke.1156000
gke-tpu-9243ec28-wwf5   Ready    <none>   7d22h   v1.30.1-gke.1156000

Vous pouvez effectuer un filtrage supplémentaire en fonction des libellés de nœud et de leurs valeurs. Par exemple, la commande suivante liste les nœuds TPU avec un type et une topologie spécifiques :

kubectl get nodes -l cloud.google.com/gke-tpu-accelerator=tpu-v5-lite-podslice,cloud.google.com/gke-tpu-topology=1x1

Pour afficher tous les journaux des nœuds de tranches TPU, vous pouvez utiliser la requête qui fait correspondre le libellé au suffixe du nœud de tranche TPU. Par exemple, utilisez la requête suivante :

resource.type="k8s_container"
labels."compute.googleapis.com/resource_name" =~ "gke-tpu-9243ec28.*"
log_id("stdout")

Pour afficher les journaux associés à une charge de travail TPU spécifique à l'aide d'une tâche Kubernetes, vous pouvez filtrer les journaux à l'aide du libellé batch.kubernetes.io/job-name. Par exemple, pour la tâche mnist-training-job, vous pouvez exécuter la requête suivante pour les journaux STDOUT :

resource.type="k8s_container"
labels."k8s-pod/batch_kubernetes_io/job-name" = "mnist-training-job"
log_id("stdout")

Pour afficher les journaux d'une charge de travail TPU à l'aide d'un JobSet Kubernetes, vous pouvez filtrer les journaux à l'aide du libellé k8s-pod/jobset_sigs_k8s_io/jobset-name. Exemple :

resource.type="k8s_container"
labels."k8s-pod/jobset_sigs_k8s_io/jobset-name"="multislice-job"

Pour aller plus loin, vous pouvez filtrer en fonction des autres libellés de charge de travail. Par exemple, pour afficher les journaux d'une charge de travail multisegment à partir du nœud de calcul 0 et du segment 1, vous pouvez filtrer en fonction des libellés job-complete-index et job-index :

​​resource.type="k8s_container"
labels."k8s-pod/jobset_sigs_k8s_io/jobset-name"="multislice-job"
labels."k8s-pod/batch_kubernetes_io/job-completion-index"="0"
labels."k8s-pod/jobset_sigs_k8s_io/job-index"="1"

Vous pouvez également filtrer à l'aide du format de nom de pod :

resource.labels.pod_name:<jobSetName>-<replicateJobName>-<job-index>-<worker-index>

Par exemple, dans la requête suivante, jobSetName est un job multi-tranches et replicateJobName est une tranche. job-index et worker-index sont tous deux définis sur 0 :

resource.type="k8s_container"
labels."k8s-pod/jobset_sigs_k8s_io/jobset-name"="multislice-job"
resource.labels.pod_name:"multislice-job-slice-0-0"

Pour les autres charges de travail TPU, comme une charge de travail d'un seul pod GKE, vous pouvez filtrer les journaux par nom de pod. Exemple :

resource.type="k8s_container"
resource.labels.pod_name="tpu-job-jax-demo"

Si vous souhaitez vérifier si le plug-in de l'appareil TPU s'exécute correctement, vous pouvez utiliser la requête suivante pour vérifier ses journaux de conteneur :

resource.type="k8s_container"
labels.k8s-pod/k8s-app="tpu-device-plugin"
resource.labels.namespace_name="kube-system"

Exécutez la requête suivante pour vérifier les événements associés :

jsonPayload.involvedObject.name=~"tpu-device-plugin.*"
log_id("events")

Pour toutes les requêtes, vous pouvez ajouter des filtres supplémentaires, tels que le nom du cluster, l'emplacement et l'ID de projet. Vous pouvez également combiner des conditions pour affiner les résultats. Exemple :

resource.type="k8s_container" AND
resource.labels.project_id="gke-tpu-demo-project" AND
resource.labels.location="us-west1" AND
resource.labels.cluster_name="tpu-demo" AND
resource.labels.namespace_name="default" AND
labels."compute.googleapis.com/resource_name" =~ "gke-tpu-9243ec28.*" AND
labels."k8s-pod/batch_kubernetes_io/job-name" = "mnist-training-job" AND
log_id("stdout")

L'opérateur AND est facultatif entre les comparaisons et peut être omis. Pour en savoir plus sur le langage de requête, consultez la spécification du langage de requête Logging. Vous pouvez également consulter les requêtes de journaux associées à Kubernetes pour obtenir d'autres exemples de requêtes.

Si vous préférez utiliser SQL avec l'Analyse de journaux, vous trouverez des exemples de requêtes dans Requête SQL avec l'Analyse de journaux. Vous pouvez également exécuter les requêtes à l'aide de Google Cloud CLI plutôt que dans l'explorateur de journaux. Exemple :

gcloud logging read 'resource.type="k8s_container" labels."compute.googleapis.com/resource_name" =~ "gke-tpu-9243ec28.*" log_id("stdout")' --limit 10 --format json

Étape suivante

Si vous avez besoin d'une aide supplémentaire, contactez Cloud Customer Care.