排查 GKE 中的 TPU 问题


本页面介绍了如何解决与 Google Kubernetes Engine (GKE) 中的 TPU 相关的问题。

如果您需要其他帮助,请与 Cloud Customer Care 联系。

配额不足,无法满足 TPU 请求

类似于 Insufficient quota to satisfy the request 的错误表示 Google Cloud 项目没有足够的配额来满足请求。

如需解决此问题,请检查项目的配额限制和当前使用量。如果需要,请申请增加 TPU 配额。

检查配额限制和当前使用量

如需查看 TPU 的 Compute Engine API 配额的限制和当前用量,请按照以下步骤操作:

  1. 转到 Google Cloud 控制台中的配额页面。

    转到“配额”

  2. 过滤条件框中,执行以下操作:

    1. 选择服务属性,输入 Compute Engine API,然后按 Enter 键。

    2. 选择类型属性,然后选择配额

    3. 选择维度(例如位置)属性,然后输入 region:,后跟您计划在其中创建 GKE 中 TPU 的区域的名称。例如,如果您计划在可用区 us-west4-a 中创建 TPU 切片节点,请输入 region:us-west4。TPU 配额是区域性的,因此同一区域内的所有可用区都使用同一 TPU 配额。

如果没有配额与您输入的过滤条件匹配,则说明项目尚未获得所需区域的任何指定配额,您必须申请增加 TPU 配额

在 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"
    
  • 当 GKE 尝试自动预配超出资源限制的 TPU 切片节点池时,集群自动扩缩器可见性日志将显示以下错误消息:

    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
    

    替换以下内容:

    • MACHINE_TYPE:要搜索的机器的类型。
    • COMPUTE_ZONE计算可用区的名称。

    输出包括类似于以下内容的说明行:

      description: 240 vCPUs, 407 GB RAM, 4 Google TPUs
      ```
    
  3. 将 CPU 和内存量乘以所需节点数来计算 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 x 5 )
    • memory = 2035 (407 x 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 虚拟机。

工作负载配置错误

此错误是由于工作负载配置错误导致。以下是导致这些错误的一些最常见原因:

  • Pod 规范中的 cloud.google.com/gke-tpu-acceleratorcloud.google.com/gke-tpu-topology 标签不正确或缺失。GKE 不会预配 TPU 切片节点池,并且节点自动预配无法扩容集群。
  • Pod 规范未在其资源要求中指定 google.com/tpu

如需解决此问题,请执行以下某项操作:

  1. 检查工作负载节点选择器中是否没有不受支持的标签。例如,cloud.google.com/gke-nodepool 标签的节点选择器会阻止 GKE 为 Pod 创建其他节点池。
  2. 确保 TPU 工作负载在其中运行的 Pod 模板规范包含以下值:
    • cloud.google.com/gke-tpu-acceleratorcloud.google.com/gke-tpu-topology 标签(在其 nodeSelector 中)。
    • google.com/tpu(在其请求中)。

如需了解如何在 GKE 中部署 TPU 工作负载,请参阅运行显示 TPU 切片节点池中的可用 TPU 芯片数量的工作负载

在 GKE 中部署使用 TPU 的 Pod 时出现调度错误

如果 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

如需解决此问题,请执行以下操作:

检查集群中是否至少有一个 CPU 节点池,以便系统关键 Pod 可以在非 TPU 节点中运行。如需了解详情,请参阅将 Pod 部署到特定节点池

排查 GKE 中的 JobSet 的常见问题

如需了解 JobSet 的常见问题和问题排查建议,请参阅 JobSet 问题排查页面。本页面介绍了常见问题,例如“Webhook 不可用”错误、子作业或 Pod 未创建,以及使用 JobSet 和 Kueue 的抢占工作负载的恢复问题。

TPU 初始化失败

如果 GKE 因缺少访问 TPU 设备的权限而无法预配新的 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

调度出现死锁

两个或更多作业调度可能因死锁而失败。例如,在发生以下所有情况的场景下:

  • 您有两个作业(作业 A 和作业 B),且采用 Pod 亲和性规则。GKE 使用 TPU 拓扑 v4-32 为两个作业调度 TPU 切片。
  • 集群中有两个 v4-32 TPU 切片。
  • 您的集群具有充足的容量来调度作业,理论上可以针对每个 TPU 切片快速调度每个作业。
  • Kubernetes 调度器会将作业 A 中的一个 Pod 调度到一个切片上,然后将作业 B 中的一个 Pod 调度到同一切片上。

在这种情况下,鉴于作业 A 的 Pod 亲和性规则,调度器会尝试将作业 A 和作业 B 的所有剩余 Pod 调度到单个 TPU 切片上。因此,GKE 将无法完全调度作业 A 或作业 B。因此,两个作业将保持“待处理”状态。

如需解决此问题,请使用 Pod 反亲和性,并将 cloud.google.com/gke-nodepool 作为 topologyKey,如以下示例所示:

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 是专用区域。

如需解决此问题,请提交支持请求,或联系您的客户支持团队,要求在 Google Cloud 项目中显示 us-central2

在 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 X 100 GB)。
  • us-central2 中使用的 IP 地址配额:每个 Kubernetes 节点使用一个 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>.

VPC 网络中需要有一个子网来提供与 GKE 节点的连接。但是,在 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 会将标签 cloud.google.com/gke-tpu-acceleratorcloud.google.com/gke-tpu-topology 附加到包含 TPU 的所有节点。因此,如果您不确定节点名称,或者想要列出所有 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 作业的特定 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"

对于其他 TPU 工作负载(例如单个 GKE Pod 工作负载),您可以按 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(而不是在 Logs Explorer 中)运行查询。例如:

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

后续步骤

如果您需要其他帮助,请与 Cloud Customer Care 联系。