GKE で TPU のトラブルシューティングを行う


このページでは、Google Kubernetes Engine(GKE)の TPU に関連する問題を解決する方法について説明します。

さらにサポートが必要な場合は、Cloud カスタマーケアにお問い合わせください。

TPU リクエストに対応できる十分な割り当てがない

Insufficient quota to satisfy the request のようなエラーは、リクエストを満たすのに十分な割り当てが Google Cloud プロジェクトにないことを示します。

この問題を解決するには、プロジェクトの割り当ての上限と現在の使用量を確認します。必要に応じて、TPU 割り当ての増加をリクエストしてください。

割り当ての上限と現在の使用量を確認する

次のセクションでは、GKE で TPU を使用するときに十分な割り当てを確保できるようにします。

TPU 用の Compute Engine API の割り当ての上限と現在の使用量を確認するには、次の操作を行います。

  1. Google Cloud コンソールで [割り当て] ページに移動します。

    [割り当て] に移動

  2. [フィルタ] ボックスで次の操作を行います。

    1. [サービス] プロパティを選択し、「Compute Engine API」と入力して Enter キーを押します。

    2. [タイプ] プロパティを選択し、[Quota] を選択します。

    3. [名前] プロパティを選択し、TPU のバージョンに基づいて割り当ての名前を入力します。たとえば、オンデマンド TPU v5e ノードを作成する場合は、「TPU v5 Lite PodSlice chips」と入力します。

      TPU バージョン オンデマンド インスタンスの割り当て名 Spot2 インスタンスの割り当ての名前
      TPU v3 TPU v3 Device chips Preemptible TPU v3 Device chips
      TPU v3 TPU v3 PodSlice chips Preemptible TPU v3 PodSlice chips
      TPU v4 TPU v4 PodSlice chips Preemptible TPU v4 PodSlice chips
      TPU v5e TPU v5 Lite Device chips Preemptible TPU v5 Lite Device chips
      TPU v5e TPU v5 Lite PodSlice chips Preemptible TPU v5 Lite PodSlice chips
      TPU v5p TPU v5p chips Preemptible TPU v5p chips
      TPU v6e(プレビュー) TPU v6e Slice chips Preemptible TPU v6e Lite PodSlice chips
    4. [項目(ロケーションなど)] プロパティを選択し、「region:」に続けて、GKE で TPU を作成するリージョンの名前を入力します。たとえば、ゾーン us-west4-a で TPU スライスノードを作成する場合は、「region:us-west4」と入力します。TPU の割り当てはリージョン単位であるため、同じリージョン内のすべてのゾーンで同じ TPU の割り当てが使用されます。

入力したフィルタに一致する割り当てがない場合、プロジェクトには目的のリージョンで指定した割り当てのいずれも付与されていないため、TPU 割り当ての増加をリクエストする必要があります。

TPU 予約が作成されると、対応する割り当ての上限と現在の使用量の値は、TPU 予約のチップ数の分だけ増加します。たとえば、TPU v5 Lite PodSlice chips 割り当ての上限現在の使用量の両方が 16 増加します。

追加の GKE リソースの割り当て

GKE がリソースを作成するリージョンで、次の GKE 関連の割り当てを増やす必要がある場合があります。

  • Persistent Disk SSD(GB)割り当て: 各 Kubernetes ノードのブートディスクにはデフォルトで 100 GB 必要です。そのため、この割り当ては、少なくとも、作成する予定の GKE ノードの最大数と 100 GB の積(ノード × 100 GB)以上の値に設定する必要があります。
  • 使用中の IP アドレスの割り当て: 各 Kubernetes ノードは 1 つの IP アドレスを消費します。そのため、この割り当てには、少なくとも作成することが予想される GKE ノードの最大数を設定する必要があります。
  • max-pods-per-node がサブネット範囲と一致していることを確認する: 各 Kubernetes ノードは、Pod にセカンダリ IP 範囲を使用します。たとえば、max-pods-per-node が 32 の場合、64 個の IP アドレスが必要になります。これはノードあたり /26 サブネットに相当します。この範囲は他のクラスタと共有しないでください。IP アドレス範囲が使い果たされないようにするには、--max-pods-per-node フラグを使用して、ノードでスケジュールできる Pod の数を制限します。max-pods-per-node の割り当ては、作成する予定の GKE ノードの最大数と同じ値に設定する必要があります。

割り当ての増加をリクエストするには、割り当ての増加をリクエストするをご覧ください。

TPU スライス ノードプールでノードの自動プロビジョニングを有効にする際のエラー

TPU をサポートしていない GKE クラスタでノードの自動プロビジョニングを有効にすると、次のエラーが発生します。

次のようなエラー メッセージが表示されます。

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

この問題を解決するには、GKE クラスタをバージョン 1.27.6 以降にアップグレードします。

GKE で TPU スライスノードが自動的にプロビジョニングされない

以降のセクションでは、GKE が TPU スライスノードを自動的にプロビジョニングしない場合とその修正方法について説明します。

上限の構成ミス

クラスタに定義した自動プロビジョニングの上限が低すぎる場合、GKE は TPU スライスノードを自動的にプロビジョニングしません。このようなシナリオでは、次のエラーが発生することがあります。

  • TPU スライス ノードプールが存在しても、リソース上限違反で GKE がノードをスケールアップできない場合、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
    

    また、このシナリオでは、Google Cloud コンソールで次のような警告メッセージが表示されます。

    "Your cluster has one or more unschedulable Pods"
    
  • リソースの上限を超える TPU スライス ノードプールを GKE が自動プロビジョニングしようとすると、クラスタ オートスケーラーのログに次のエラー メッセージが表示されます。

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

    また、このシナリオでは、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"
    

これらの問題を解決するには、クラスタ内の TPU チップ、CPU コア、メモリの最大数を増やします。

手順は次のとおりです。

  1. 特定の TPU マシンタイプのリソース要件と数を計算します。システム ワークロードなど、TPU スライス以外のノードプールで使用されるリソースを追加する必要があります。
  2. 特定のマシンタイプとゾーンで使用可能な TPU、CPU、メモリの説明を取得します。gcloud CLI を使用します。

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

    次のように置き換えます。

    出力には、次のような説明行が含まれます。

      description: 240 vCPUs, 407 GB RAM, 4 Google TPUs
      ```
    
  3. CPU とメモリの合計数を計算するには、これらの量に必要なノード数を掛けます。たとえば、ct4p-hightpu-4t マシンタイプは 240 個の CPU コア、407 GB の RAM、4 個の TPU チップを使用します。20 個の TPU チップ(5 つのノードに相当)が必要な場合は、次の値を定義する必要があります。

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

    システム ワークロードなどの TPU スライス以外のノードに対応するには、ある程度の余裕を見て制限を定義する必要があります。

  4. クラスタの上限を更新します。

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

    次のように置き換えます。

    • CLUSTER_NAME: クラスタの名前。
    • TPU_ACCELERATOR: TPU アクセラレータの名前。
    • MAXIMUM_ACCELERATOR: クラスタ内の TPU チップの最大数。
    • MAXIMUM_CPU: クラスタの最大コア数。
    • MAXIMUM_MEMORY: クラスタの最大メモリ量(GB)。

すべてのインスタンスが実行されていない

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.

このエラーは、GKE オペレーションがタイムアウトした場合、またはリクエストを満たせず単一ホストまたはマルチホスト TPU ノードプールのプロビジョニングのキューに追加できない場合に表示されます。容量の問題を軽減するには、予約を使用するか、Spot VM を検討してください。

ワークロードの構成ミス

このエラーは、ワークロードの構成ミスが原因で発生します。このエラーの最も一般的な原因は次のとおりです。

  • Pod 仕様で cloud.google.com/gke-tpu-accelerator ラベルと cloud.google.com/gke-tpu-topology ラベルが正しくないか、欠落しています。GKE は TPU スライス ノードプールをプロビジョニングせず、ノードの自動プロビジョニングでクラスタをスケールアップできません。
  • Pod 仕様で、リソース要件に google.com/tpu が指定されていません。

この問題を解決するには、以下のいずれかを行います。

  1. ワークロード ノードセレクタに、サポートされていないラベルがないことを確認します。たとえば、cloud.google.com/gke-nodepool ラベルのノードセレクタの場合、GKE は Pod に追加のノードプールを作成できません。
  2. TPU ワークロードが実行される Pod テンプレートの仕様に次の値が含まれていることを確認します。
    • nodeSelector 内の cloud.google.com/gke-tpu-accelerator ラベルと cloud.google.com/gke-tpu-topology ラベル。
    • リクエスト内の google.com/tpu

TPU ワークロードを GKE にデプロイする方法については、TPU スライス ノードプールで使用可能な TPU チップの数を表示するワークロードを実行するをご覧ください。

TPU を使用する Pod を GKE にデプロイする際のスケジュールに関するエラー

次の問題は、GKE が TPU スライスノード上の TPU をリクエストする Pod をスケジュールできない場合に発生します。たとえば、TPU 以外のスライスがすでに TPU ノードでスケジュールされている場合に発生することがあります。

Pod で FailedScheduling イベントとして次のようなエラー メッセージが出力されます。

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

この問題を解決するには、次の操作を行います。

TPU 以外のノードでシステム クリティカルな Pod を実行できるように、クラスタに少なくとも 1 つの CPU ノードプールがあることを確認します。詳細については、Pod を特定のノードプールにデプロイするをご覧ください。

GKE の JobSet に関する一般的な問題のトラブルシューティング

JobSet に関する一般的な問題とトラブルシューティングの候補については、JobSet のトラブルシューティング ページをご覧ください。このページでは、「Webhook を使用できません」エラー、子 Job、Pod が作成されない、JobSet と Kueue を使用したプリエンプトされたワークロードの再開に関する問題など、一般的な問題について説明します。

TPU の初期化に失敗した

次の問題は、TPU デバイスへのアクセス権限がないために GKE が新しい TPU ワークロードをプロビジョニングできない場合に発生します。

次のようなエラー メッセージが表示されます。

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

この問題を解決するには、TPU コンテナを特権モードで実行するか、コンテナ内の ulimit を増やします。

スケジューリングのデッドロック

2 つ以上のジョブ スケジューリングがデッドロックにより失敗する場合があります。たとえば、次のすべてが起こりうるシナリオです。

  • Pod アフィニティ ルールを持つ 2 つのジョブ(ジョブ A とジョブ B)があるとします。GKE は、v4-32 の TPU トポロジを使用して、両方のジョブに TPU スライスをスケジュールします。
  • クラスタに v4-32 TPU スライスが 2 つあります。
  • クラスタには、両方のジョブをスケジュールするのに十分な容量があり、理論上は各ジョブを各 TPU スライスで迅速にスケジュールできます。
  • Kubernetes スケジューラは、1 つのスライスでジョブ A から 1 つのポッドをスケジュールし、同じスライスでジョブ B から 1 つのポッドをスケジュールします。

この場合、ジョブ A の Pod アフィニティ ルールに基づいて、スケジューラはジョブ A とジョブ B の残りのすべての Pod を、それぞれ 1 つの TPU スライスでスケジュールしようとします。その結果、GKE はジョブ A またはジョブ B を完全にスケジュールできなくなります。したがって、両方のジョブのステータスは保留中のままになります。

この問題を解決するには、次の例に示すように、cloud.google.com/gke-nodepooltopologyKey として Pod のアンチ アフィニティを使用します。

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

us-central2 でクラスタの作成中に権限が拒否される

us-central2(TPU v4 が利用可能な唯一のリージョン)にクラスタを作成しようとすると、次のようなエラー メッセージが表示されることがあります。

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

このエラーは、リージョン us-central2 が限定公開リージョンであるために発生しています。

この問題を解決するには、サポートケースを送信するか、アカウント チームに連絡して、us-central2 を Google Cloud プロジェクト内で公開するよう依頼してください。

us-central2 で TPU ノードプールを作成する際に割り当てが足りない

us-central2(TPU v4 を使用できる唯一のリージョン)に TPU スライス ノードプールを作成する場合は、最初に TPU v4 ノードプールを作成するときに、次の GKE 関連の割り当てを増やす必要があるかもしれません。

  • us-central2 における Persistent Disk SSD(GB)の割り当て: 各 Kubernetes ノードのブートディスクには、デフォルトで 100 GB が必要です。そのため、この割り当てには、少なくとも、us-central2 で作成することが予想される GKE ノードの最大数と 100 GB の積(maximum_nodes × 100 GB)以上の値を設定する必要があります。
  • us-central2 における使用中の IP アドレスの割り当て: 各 Kubernetes ノードは、それぞれ 1 つの IP アドレスを使用します。そのため、この割り当てには、少なくとも us-central2 に作成することが予想される GKE ノードの最大数を設定する必要があります。

GKE クラスタの作成時にサブネットが見つからない

us-central2(TPU v4 が利用可能な唯一のリージョン)にクラスタを作成しようとすると、次のようなエラー メッセージが表示されることがあります。

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

GKE ノードへの接続を提供するには、VPC ネットワークにサブネットが必要です。ただし、us-central2 などの特定のリージョンでは、サブネットを作成するためにデフォルトの VPC ネットワークを自動モードで使用しても、デフォルトのサブネットが作成されないことがあります。

この問題を解決するには、GKE クラスタを作成する前に、リージョンにカスタム サブネットを作成していることを確認します。このサブネットは、同じ VPC ネットワーク内の他のリージョンで作成された他のサブネットと重ならないようにする必要があります。

GKE TPU ログを表示する

特定のワークロードの TPU 関連のすべてのログを表示するには、GKE システムとワークロードのロギングが有効になっている場合、Cloud Logging で一元的にこれらのログをクエリできます。Cloud Logging では、ログはログエントリに編成され、各ログエントリには構造化形式があります。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"
}

TPU スライスノードの各ログエントリには、値がノード名として設定されたラベル compute.googleapis.com/resource_name があります。特定のノードからのログを表示し、ノード名がわかっている場合は、クエリでそのノードによってログをフィルタできます。たとえば、次のクエリは TPU ノード gke-tpu-9243ec28-wwf5 のログを示します。

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

GKE は、TPU を含むすべてのノードにラベル cloud.google.com/gke-tpu-acceleratorcloud.google.com/gke-tpu-topology を適用します。ノード名がわからない場合や、すべての TPU スライス ノードを一覧表示する場合は、次のコマンドを実行します。

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

出力例:

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

ノードラベルとその値に基づいて、さらにフィルタリングを行うことができます。たとえば、次のコマンドは、特定のタイプとトポロジを持つ TPU ノードを一覧表示します。

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

TPU スライスノード全体のすべてのログを表示するには、ラベルを TPU スライスノードの接尾辞に一致させるクエリを使用します。たとえば、次のクエリを使用します。

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

Kubernetes Job を使用して特定の TPU ワークロードに関連付けられたログを表示するには、batch.kubernetes.io/job-name ラベルを使用してログをフィルタします。たとえば、ジョブ mnist-training-job の場合、STDOUT ログに対して次のクエリを実行できます。

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

Kubernetes JobSet を使用して TPU ワークロードのログを表示するには、k8s-pod/jobset_sigs_k8s_io/jobset-name ラベルを使用してログをフィルタします。次に例を示します。

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

さらにドリルダウンするには、他のワークロードラベルに基づいてフィルタします。たとえば、ワーカー 0 とスライス 1 のマルチスライス ワークロードのログを表示するには、ラベル job-complete-indexjob-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"

Pod 名のパターンを使用してフィルタすることもできます。

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

たとえば、次のクエリでは、jobSetName はマルチスライスジョブで、replicateJobName はスライスです。job-indexworker-index の両方が 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"

単一の GKE Pod ワークロードなどの他の TPU ワークロードでは、Pod 名でログをフィルタできます。次に例を示します。

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

TPU デバイス プラグインが正しく実行されているかどうかを確認するには、次のクエリを使用してコンテナログを確認します。

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

次のクエリを実行して、関連するイベントを確認します。

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

すべてのクエリで、クラスタ名、ロケーション、プロジェクト ID などのフィルタを追加できます。条件を組み合わせて結果を絞り込むこともできます。次に例を示します。

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")

AND 演算子は比較間で省略可能です。クエリ言語の詳細については、Logging のクエリ言語仕様をご覧ください。その他のクエリの例については、Kubernetes 関連のログクエリをご覧ください。

Log Analytics で SQL を使用する場合は、Log Analytics での SQL クエリでクエリの例をご覧ください。ログ エクスプローラではなく、Google Cloud CLI を使用してクエリを実行することもできます。次に例を示します。

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

次のステップ

さらにサポートが必要な場合は、Cloud カスタマーケアにお問い合わせください。