使用 Kueue 和 TAS 调度动态切片

本文档介绍了如何使用 Kueue拓扑感知调度 (TAS) 在 Google Kubernetes Engine (GKE) 中预配 TPU 节点池和调度动态切片 。

您还可以通过直接与 Slice 自定义资源 互动来使用动态切片。如需了解详情,请参阅使用自定义调度器进行动态切片

在按照这些说明操作之前,请确保您了解动态切片的概念。

要求

如需在 GKE 中使用动态切片,您必须满足以下要求:

  • 在快速渠道中使用以下版本之一的 Standard 集群:
    • 如需进行动态超级切片配置(拓扑等于或大于 4x4x4),请使用 1.35.2-gke.1842000 版或更高版本。
    • 如需进行动态子切片配置(拓扑小于 4x4x4),请使用 1.36.0-gke.3712000 版或更高版本。
  • 使用 Ironwood (TPU7x) 版本。
  • 为节点使用 Container-Optimized OS 映像。
  • 如需使用增量预配,请使用 全容量模式预留。全容量模式是 TPU Cluster Director 启用的一项功能。
  • 对于动态子切片,请确保您的节点有待处理的维护事件。 监控实例是否有待处理的维护事件。 如果您的任何节点有待处理的维护事件,且结束时间介于 2026 年 9 月 18 日和 2026 年 9 月 30 日之间,您必须先手动 触发这些节点上的主机维护事件 ,然后才能使用子切片。

准备工作

在开始之前,请确保您已执行以下任务:

  • 启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 如需使用 Google Cloud CLI 执行此任务, 请安装初始化 gcloud CLI。如果您之前安装了 gcloud CLI,请通过运行 gcloud components update 命令来获取最新 版本。较早版本的 gcloud CLI 可能不支持运行本文档中的命令。

使用 Kueue 在 GKE 中进行动态切片

本部分介绍了在 GKE 中使用动态切片的工作流。

  1. 查看全容量模式预留的拓扑和健康状况
  2. 在集群中启用切片控制器
  3. 安装 Kueue、JobSet 和 LWS
  4. 创建 TPU 节点池
  5. 配置 Kueue 以创建 Slice 自定义资源
  6. 使用 Kueue 在动态切片上运行工作负载
  7. 清理

启用切片控制器

如需使用动态切片,请在集群中启用切片控制器。

  1. 更新集群:

    gcloud container clusters update CLUSTER_NAME \
        --location=LOCATION \
        --enable-slice-controller
    

    替换以下内容:

    • CLUSTER_NAME:您的集群的名称。
    • LOCATION:具有可用 TPU 容量的区域。
  2. 获取凭据,以便您可以使用 kubectl 命令与集群通信:

    gcloud config set container/cluster CLUSTER_NAME
    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=LOCATION
    
  3. 在以下命令的输出中,验证是否存在 slices.accelerator.gke.io 值:

    kubectl get crd slices.accelerator.gke.io
    

    输出类似于以下内容:

    slices.accelerator.gke.io                2026-01-09T23:58:02Z
    

安装 Kueue、JobSet 和 LWS

如果您已安装 Kueue、JobSet 和 LWS,则可以跳过本部分。

安装 Kueue

按照 Kueue 文档中的说明操作,或运行以下命令:

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

KUEUE_VERSION 替换为根据您的拓扑要求所需的 Kueue 版本。对于动态子切片,请使用 Kueue v0.18.2 或更高版本。对于动态超级切片,请使用 Kueue v0.16.6 或更高版本。

安装 JobSet

按照 JobSet 文档中的说明操作,或运行以下命令:

kubectl apply --server-side -f https://github.com/kubernetes-sigs/jobset/releases/download/JOBSET_VERSION/manifests.yaml

JOBSET_VERSION 替换为根据您的拓扑要求所需的 JobSet 版本。对于动态子切片,请使用 JobSet v0.12.0 或更高版本。对于动态超级切片,请使用 JobSet v0.11.1 或更高版本。

安装 LWS

只有动态子切片才需要 LeaderWorkerSet (LWS)。

按照 LWS 文档 中的说明操作,或运行以下命令:

kubectl apply --server-side -f https://github.com/kubernetes-sigs/lws/releases/download/LWS_VERSION/manifests.yaml

LWS_VERSION 替换为所需的 LWS 版本。使用 LWS v0.8.0 或更高版本。

使用增量预配创建节点池

本部分介绍了如何使用增量预配创建 TPU 节点池。GKE 会将您的所有 TPU 容量转换为由 16 个节点的 Ironwood (TPU7x) 虚拟机组或子块组成的节点池。即使 GKE 无法找到所有健康状况良好的虚拟机,它也会预配这些节点池,方法是将节点放置在宿主机健康状况良好的部分,并在修复健康状况不佳的机器时以增量方式预配这些机器。

您可以将节点池的目标设置为属于以下任一项:

  • 特定 TPU 块,在全容量模式预留中公开。 通过块定位,GKE 可以在指定块中的任何可用子块中创建节点池。
  • 特定子块或特定 16 节点组的 Ironwood (TPU7x) 虚拟机,以实现更精细的控制。

创建工作负载政策

如需使用 Ironwood (TPU7x) 创建 TPU 切片节点池,您必须先创建一个工作负载政策,并将 accelerator-topology-mode 字段设置为 provision_only。此设置会触发增量预配流程。

创建工作负载政策:

gcloud compute resource-policies create workload-policy WORKLOAD_POLICY_NAME \
        --project=PROJECT_ID \
        --region=REGION  \
        --type=HIGH_THROUGHPUT \
        --accelerator-topology=4x4x4 \
        --accelerator-topology-mode=provision_only

替换以下内容:

  • WORKLOAD_POLICY_NAME:工作负载政策的名称。
  • PROJECT_ID:您的 Google Cloud 项目 ID。
  • REGION:工作负载政策的区域。

在此命令中,请执行以下操作::

  • 始终将 accelerator-topology 字段设置为 4x4x4,以匹配单个子块中的芯片总数。
  • 始终将 accelerator-topology-mode 字段设置为 provision_only,以确保触发增量预配流程。设置 provision_only 字段后,节点池会预配 TPU 节点,而不会形成 ICI 或 OCS 链接。

将节点池的目标设置为属于块或子块

您可以将目标设置为全容量模式预留中的特定子块或块。

  • 将目标设置为块 :每个节点池都使用指定块中的容量。GKE 会将节点池放置在该块中的可用子块内。您必须创建与要使用的块中的子块数量相同的节点池。
  • 将目标设置为子块 :每个节点池都映射到特定的可用子块。使用子块定位时,如果至少有一个虚拟机健康状况良好,GKE 会创建节点池。 增量预配有助于确保所有节点都放置在指定的子块内。

  1. 如需检索预留中块的名称以及块中可用子块的数量,请在 查看全容量模式预留的拓扑和健康状况文档中完成以下步骤:

    1. 列出所有预留块并复制 name: 字段中的值,以确定块的名称。此值是块的名称,或本文档中的 BLOCK_NAME

    2. 通过 描述预留块 并确定 reservationSubBlockCount 字段中的值,确定要创建的节点池数量。此值是可用子块的数量。例如,reservationSubBlockCount: 4 值表示该块有 4 个可用子块,您需要创建 4 个单独的节点池。

  2. 设置预留路径:

    export RESERVATION_PATH="projects/PROJECT_ID/reservations/RESERVATION_NAME/reservationBlocks/BLOCK_NAME"
    

    替换以下内容:

    • RESERVATION_NAME:TPU 预留的名称。
    • BLOCK_NAME:块的名称。
  3. 为上一步中确定的每个子块创建一个节点池。 例如,如果数量为 4,请运行此命令四次。为每个节点池使用唯一的名称。

    gcloud container node-pools create NODE_POOL_NAME \
          --cluster=CLUSTER_NAME \
          --node-locations=ZONE \
          --machine-type=tpu7x-standard-4t \
          --num-nodes=16 \
          --placement-policy=WORKLOAD_POLICY_NAME \
          --reservation-affinity=specific \
          --reservation=${RESERVATION_PATH}
    

    替换以下内容:

    • NODE_POOL_NAME:新节点池的名称。
    • CLUSTER_NAME:GKE 集群的名称。
    • WORKLOAD_POLICY_NAME:您创建的工作负载政策的名称。
    • ZONE:节点池的可用区,例如 us-central1-a

子块

  1. 如需检索块的名称和可用 子块的 ID,请在查看全容量模式 预留的拓扑和 健康状况文档中完成以下步骤:

    1. 如需确定块的名称,列出所有预留 块 并复制 name: 字段中的值。此值是块的名称,或本文档中的 BLOCK_NAME

    2. 如需确定子块的名称, 请列出块的所有子块 并复制 name: 字段中的值,以获取 reservationSubBlocks 下的每个条目。此值是子块的名称,或本文档中的 SUBBLOCK_NAME

  2. 设置预留路径:

    export RESERVATION_PATH="projects/PROJECT_ID/reservations/RESERVATION_NAME/reservationBlocks/BLOCK_NAME/reservationSubBlocks/SUBBLOCK_NAME"
    

    替换以下内容:

    • RESERVATION_NAME:TPU 预留的名称。
    • BLOCK_NAME:块的名称。
    • SUBBLOCK_NAME:子块的名称。
  3. 创建节点池:

    gcloud container node-pools create NODE_POOL_NAME \
            --project=PROJECT_ID \
            --cluster=CLUSTER_NAME \
            --node-locations=ZONE \
            --machine-type=tpu7x-standard-4t \
            --num-nodes=16 \
            --placement-policy=WORKLOAD_POLICY_NAME \
            --reservation-affinity=specific \
            --reservation=${RESERVATION_PATH}
    

    替换以下内容:

    • NODE_POOL_NAME:新节点池的唯一名称,例如 sub-block-pool-1
    • PROJECT_ID:您的 Google Cloud 项目 ID。
    • CLUSTER_NAME:GKE 集群的名称。
    • ZONE:节点池的可用区,例如 us-central2-b
    • WORKLOAD_POLICY_NAME:您创建的工作负载政策的名称。

在此阶段,节点已创建,但其芯片间互连 (ICI) 链接尚未处于活跃状态。因此,您无法直接在这些节点池上运行工作负载。

如需启用所有必要的 ICI 链接以形成切片并允许调度工作负载,请使用以下方法之一创建动态切片:

  • 创建 Slice 自定义资源。您可以使用 Slice 自定义资源(而不是 Pod)来定义指定的拓扑,切片控制器会激活该拓扑。
  • 使用 KueueTAS调度 GKE 工作负载。 Kueue 会自动处理 Slice 自定义资源的创建和删除。避免手动修改 Kueue 创建的 Slice 自定义资源。

使用 Kueue 和 TAS 创建动态切片

在本部分中,您将使用 Kueue 和 TAS 调度 GKE 工作负载。

安装 Kueue 切片控制器

  1. 如需安装 Kueue 切片控制器,请将以下清单保存为 slice-controller.yaml

    # Copyright 2026 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #      http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    apiVersion: v1
    kind: Namespace
    metadata:
      labels:
        app.kubernetes.io/managed-by: kustomize
        app.kubernetes.io/name: slice-controller
        control-plane: controller-manager
      name: slice-controller-system
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      labels:
        app.kubernetes.io/managed-by: kustomize
        app.kubernetes.io/name: slice-controller
        control-plane: controller-manager
      name: slice-controller-controller-manager
      namespace: slice-controller-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      labels:
        app.kubernetes.io/managed-by: kustomize
        app.kubernetes.io/name: slice-controller
        control-plane: controller-manager
      name: slice-controller-leader-election-role
      namespace: slice-controller-system
    rules:
    - apiGroups:
      - ""
      resources:
      - configmaps
      verbs:
      - get
      - list
      - watch
      - create
      - update
      - patch
      - delete
    - apiGroups:
      - coordination.k8s.io
      resources:
      - leases
      verbs:
      - get
      - list
      - watch
      - create
      - update
      - patch
      - delete
    - apiGroups:
      - ""
      resources:
      - events
      verbs:
      - create
      - patch
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      labels:
        control-plane: controller-manager
      name: slice-controller-manager-role
    rules:
    - apiGroups:
      - ""
      resources:
      - events
      verbs:
      - create
      - patch
      - update
      - watch
    - apiGroups:
      - ""
      resources:
      - nodes
      - pods
      verbs:
      - get
      - list
      - watch
    - apiGroups:
      - ""
      resources:
      - secrets
      verbs:
      - get
      - list
      - update
      - watch
    - apiGroups:
      - accelerator.gke.io
      resources:
      - slices
      verbs:
      - create
      - delete
      - get
      - list
      - patch
      - update
      - watch
    - apiGroups:
      - accelerator.gke.io
      resources:
      - slices/finalizers
      verbs:
      - update
    - apiGroups:
      - admissionregistration.k8s.io
      resources:
      - mutatingwebhookconfigurations
      verbs:
      - get
      - list
      - update
      - watch
    - apiGroups:
      - batch
      resources:
      - jobs
      verbs:
      - get
      - list
      - patch
      - update
      - watch
    - apiGroups:
      - jobset.x-k8s.io
      resources:
      - jobsets
      verbs:
      - get
      - list
      - patch
      - update
      - watch
    - apiGroups:
      - leaderworkerset.x-k8s.io
      resources:
      - leaderworkersets
      verbs:
      - get
      - list
      - patch
      - update
      - watch
    - apiGroups:
      - kueue.x-k8s.io
      resources:
      - admissionchecks
      - admissionchecks/status
      - workloads/status
      verbs:
      - get
      - patch
      - update
    - apiGroups:
      - kueue.x-k8s.io
      resources:
      - workloads
      verbs:
      - create
      - get
      - list
      - patch
      - update
      - watch
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      labels:
        control-plane: controller-manager
      name: slice-controller-metrics-auth-role
    rules:
    - apiGroups:
      - authentication.k8s.io
      resources:
      - tokenreviews
      verbs:
      - create
    - apiGroups:
      - authorization.k8s.io
      resources:
      - subjectaccessreviews
      verbs:
      - create
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      labels:
        control-plane: controller-manager
      name: slice-controller-metrics-reader
    rules:
    - nonResourceURLs:
      - /metrics
      verbs:
      - get
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      labels:
        app.kubernetes.io/managed-by: kustomize
        app.kubernetes.io/name: slice-controller
        control-plane: controller-manager
      name: slice-controller-leader-election-rolebinding
      namespace: slice-controller-system
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: slice-controller-leader-election-role
    subjects:
    - kind: ServiceAccount
      name: slice-controller-controller-manager
      namespace: slice-controller-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      labels:
        app.kubernetes.io/managed-by: kustomize
        app.kubernetes.io/name: slice-controller
        control-plane: controller-manager
      name: slice-controller-manager-rolebinding
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: slice-controller-manager-role
    subjects:
    - kind: ServiceAccount
      name: slice-controller-controller-manager
      namespace: slice-controller-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      labels:
        control-plane: controller-manager
      name: slice-controller-metrics-auth-rolebinding
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: slice-controller-metrics-auth-role
    subjects:
    - kind: ServiceAccount
      name: slice-controller-controller-manager
      namespace: slice-controller-system
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      labels:
        control-plane: controller-manager
      name: slice-controller-webhook-server-cert
      namespace: slice-controller-system
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app.kubernetes.io/managed-by: kustomize
        app.kubernetes.io/name: slice-controller
        control-plane: controller-manager
      name: slice-controller-controller-manager-metrics-service
      namespace: slice-controller-system
    spec:
      ports:
      - name: https
        port: 8443
        protocol: TCP
        targetPort: 8443
      selector:
        app.kubernetes.io/name: slice-controller
        control-plane: controller-manager
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        control-plane: controller-manager
      name: slice-controller-webhook-service
      namespace: slice-controller-system
    spec:
      ports:
      - port: 443
        protocol: TCP
        targetPort: 9443
      selector:
        control-plane: controller-manager
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app.kubernetes.io/managed-by: kustomize
        app.kubernetes.io/name: slice-controller
        control-plane: controller-manager
      name: slice-controller-controller-manager
      namespace: slice-controller-system
    spec:
      replicas: 1
      selector:
        matchLabels:
          app.kubernetes.io/name: slice-controller
          control-plane: controller-manager
      template:
        metadata:
          annotations:
            kubectl.kubernetes.io/default-container: manager
          labels:
            app.kubernetes.io/name: slice-controller
            control-plane: controller-manager
        spec:
          containers:
          - args:
            - --metrics-bind-address=:8443
            - --leader-elect
            - --health-probe-bind-address=:8081
            - --zap-log-level=3
            - --feature-gates=UseRetryMechanismForSliceCreation=true
            - --activation-timeout=6m
            command:
            - /manager
            image: tpuongke/kueue-slice-controller:latest
            livenessProbe:
              httpGet:
                path: /healthz
                port: 8081
              initialDelaySeconds: 15
              periodSeconds: 20
            name: manager
            ports:
            - containerPort: 9443
              name: webhook-server
              protocol: TCP
            readinessProbe:
              httpGet:
                path: /readyz
                port: 8081
              initialDelaySeconds: 5
              periodSeconds: 10
            resources:
              limits:
                cpu: 12000m
                memory: 32Gi
              requests:
                cpu: 8000m
                memory: 16Gi
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - ALL
            volumeMounts:
            - mountPath: /tmp/k8s-webhook-server/serving-certs
              name: cert
              readOnly: true
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          serviceAccountName: slice-controller-controller-manager
          terminationGracePeriodSeconds: 10
          volumes:
          - name: cert
            secret:
              defaultMode: 420
              secretName: slice-controller-webhook-server-cert
    ---
    apiVersion: admissionregistration.k8s.io/v1
    kind: MutatingWebhookConfiguration
    metadata:
      labels:
        control-plane: controller-manager
      name: slice-controller-mutating-webhook-configuration
    webhooks:
    - admissionReviewVersions:
      - v1
      clientConfig:
        service:
          name: slice-controller-webhook-service
          namespace: slice-controller-system
          path: /mutate-batch-v1-job
      failurePolicy: Fail
      name: mjob.kb.io
      rules:
      - apiGroups:
        - batch
        apiVersions:
        - v1
        operations:
        - CREATE
        resources:
        - jobs
      sideEffects: None
    - admissionReviewVersions:
      - v1
      clientConfig:
        service:
          name: slice-controller-webhook-service
          namespace: slice-controller-system
          path: /mutate-jobset-x-k8s-io-v1alpha2-jobset
      failurePolicy: Fail
      name: mjobset.kb.io
      rules:
      - apiGroups:
        - jobset.x-k8s.io
        apiVersions:
        - v1alpha2
        operations:
        - CREATE
        resources:
        - jobsets
      sideEffects: None
    - admissionReviewVersions:
      - v1
      clientConfig:
        service:
          name: slice-controller-webhook-service
          namespace: slice-controller-system
          path: /mutate-leaderworkerset-x-k8s-io-v1-leaderworkerset
      failurePolicy: Fail
      name: mleaderworkerset.kb.io
      rules:
      - apiGroups:
        - leaderworkerset.x-k8s.io
        apiVersions:
        - v1
        operations:
        - CREATE
        resources:
        - leaderworkersets
      sideEffects: None
    
  2. 应用 slice-controller.yaml 清单:

    kubectl apply -f slice-controller.yaml
    
  3. 如需为动态切片配置 Kueue,请将以下清单保存为 dynamic-slice-topology.yaml

    # Copyright 2026 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #      http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    apiVersion: kueue.x-k8s.io/v1beta1
    kind: Topology
    metadata:
      name: superslice-topology
    spec:
      levels:
      # Label to identify the physical block a sub-block belongs to.
      # Only sub-blocks from the same block can form a slice.
      - nodeLabel: cloud.google.com/gce-topology-block
      # Label to identify individual TPU sub-blocks (4x4x4 topology).
      - nodeLabel: cloud.google.com/gke-tpu-partition-4x4x4-id
      # Standard Kubernetes label for individual nodes.
      # Required to assign Pods to specific VMs.
      - nodeLabel: kubernetes.io/hostname
    ---
    apiVersion: kueue.x-k8s.io/v1beta1
    kind: ResourceFlavor
    metadata:
      name: superslice-rf
    spec:
      nodeLabels:
        cloud.google.com/gke-tpu-accelerator: tpu7x
      topologyName: superslice-topology
    ---
    apiVersion: kueue.x-k8s.io/v1beta1
    kind: AdmissionCheck
    metadata:
      name: superslice-ac
    spec:
      controllerName: accelerator.gke.io/slice
    ---
    apiVersion: kueue.x-k8s.io/v1beta1
    kind: ClusterQueue
    metadata:
      name: cq
    spec:
      namespaceSelector: {}
      admissionChecks:
      - superslice-ac
      resourceGroups:
      - coveredResources:
        - google.com/tpu
        flavors:
        - name: superslice-rf
          resources:
          - name: google.com/tpu
            nominalQuota: "999999"  # modeling unlimited quota
    ---
    apiVersion: kueue.x-k8s.io/v1beta1
    kind: LocalQueue
    metadata:
      name: lq
      namespace: default
    spec:
      clusterQueue: cq
    
  4. 应用 dynamic-slice-topology.yaml 清单:

    kubectl apply -f dynamic-slice-topology.yaml
    

    在此清单中,您可以通过定义以下资源来为动态切片配置 Kueue:

    • Ironwood (TPU7x) 动态切片拓扑 (superslice-topology) :拓扑定义了 Kueue 在调度动态切片工作负载时考虑的级别。这些级别如下所示:
      • cloud.google.com/gce-topology-block 标签:此级别是了解哪些子块属于哪些块所必需的,因为只有来自同一块的子块才能形成切片。
      • cloud.google.com/gke-tpu-partition-4x4x4-id 标签:此级别 表示各个 Ironwood (TPU7x) 子块(4x4x4 拓扑)。
      • kubernetes.io/hostname 标签:此级别是为特定虚拟机分配 Pod 以及观察其标签和污点所必需的。
    • Ironwood (TPU7x) SuperSlice ResourceFlavor (superslice-rf) :Ironwood (TPU7x) 子块的资源变种包含 cloud.google.com/gke-tpu-accelerator: tpu7x 标签,以匹配具有 Ironwood (TPU7x) 机器的节点。
    • SuperSlice AdmissionCheck (superslice-ac) :此准入检查会告知 Kueue,在 GKE 切片控制器确认切片已处于活跃状态之前,不要调度工作负载。首先定义准入检查,然后将其添加到处理动态切片工作负载的 ClusterQueue
    • ClusterQueue (cq) 和 LocalQueue (lq) :这些字段用于管理 google.com/tpu 资源。cq ClusterQueue 包含 superslice-ac 准入检查。可以通过两种方式配置 google.com/tpunominalQuota 字段:
      • 特定配额:设置 nominalQuota 字段以匹配现有容量 ,从而实现公平共享和配额管理。
      • 无限配额:将 nominalQuota 字段设置为非常高的值(例如 "999999"),以模拟无限配额。为了专注于 TAS 和动态切片,此配置会绕过 Kueue 的配额管理功能。

定义分区健康状况选择

除了标准节点健康状况和就绪状态之外,GKE 还使用 cloud.google.com/gke-tpu-partition-[shape]-state 标签 (其中[shape] 与分区 ID 形状匹配,例如2x2x12x2x22x2x42x4x4、 或4x4x4)公开每个分区形状的特定状态。此标签可让 GKE 考虑影响切片 形成的因素,例如 TPU 链接的状态。动态子切片配置(拓扑小于 4x4x4)需要 GKE 1.36.0-gke.3712000 版或更高版本。

您可以按如下方式定义分区状态标签的值:

  • HEALTHY:分区健康状况良好且功能齐全。
  • DEGRADED:分区的基础架构处于降级状态,例如,由于 OCS 链接降级。分区仍可以形成切片,但与健康状况良好的分区相比,整体性能可能会降低。此状态仅适用于顶级 4x4x4 拓扑。 较小的拓扑没有降级状态。
  • UNHEALTHY:分区健康状况不佳,无法形成切片。
  • UNSET:由于 GKE 切片控制器初始化失败,状态未定义。
  • INCOMPLETE:分区内的并非所有节点都已预配。

Kueue Slice Controller webhook 会验证工作负载是否包含特定的分区健康状况要求。如果未指明偏好设置,webhook 会注入默认节点亲和性。

行为如下:

  • 如果存在以 cloud.google.com/gke-tpu-partition-[shape]-state 标签为目标的 nodeSelectornodeAffinity,则它保持不变。
  • 如果不存在此类标签配置,webhook 会注入以下默认节点亲和性,以确保仅使用可用分区:

    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: cloud.google.com/gke-tpu-partition-4x4x4-state
            operator: In
            values:
            - "HEALTHY"
            - "DEGRADED"
    

以下部分包含一些示例,其中配置了 cloud.google.com/gke-tpu-partition-4x4x4-state 标签以指定不同的子块健康状况配置。

使用 Kueue 在动态切片上运行测试工作负载

本部分介绍了如何使用 Kueue 和 TAS 在动态切片上部署工作负载。它包含一些示例,展示了如何创建动态切片工作负载和由多个切片组成的工作负载。工作负载以 JobSet 的形式提交。

示例 1:单个工作负载使用单个动态切片

以下示例介绍了如何使用具有 4x12x16 拓扑的切片创建工作负载,该拓扑由 12 个子块组成。Pod 数量的计算方式如下:(4 * 12 * 16) / 每个节点的 4 个芯片 = 192 个 Pod。

  1. 将以下清单保存为 big-super-slice.yaml

    # Copyright 2026 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #      http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    apiVersion: jobset.x-k8s.io/v1alpha2
    kind: JobSet
    metadata:
      name: big-super-slice
      labels:
        kueue.x-k8s.io/queue-name: lq
    spec:
      replicatedJobs:
        - name: job-jax
          replicas: 1
          template:
            spec:
              parallelism: 192  # pods per slice calculation: 4*12*16 / 4 = 192
              completions: 192
              backoffLimit: 10
              template:
                metadata:
                  annotations:
                    cloud.google.com/gke-tpu-slice-topology: 4x12x16
                spec:
                  tolerations:
                    - key: "google.com/tpu"
                      operator: "Equal"
                      value: "present"
                      effect: "NoSchedule"
                  nodeSelector:
                    cloud.google.com/gke-tpu-accelerator: tpu7x
                  containers:
                    - name: jax
                      image: python:latest
                      command:
                        - bash
                        - -c
                        - |
                          printenv
                          pip install "jax[tpu]" -f https://storage.googleapis.com/jax-releases/libtpu_releases.html
                          python -c 'import jax; print("Global device count:", jax.device_count(), "Local device count:", jax.local_device_count())'
                      resources:
                        limits:
                          google.com/tpu: 4
                  restartPolicy: Never
    

    在此清单中,以下注解会告知 Kueue 切片特征和拓扑,以配置以下内容:

    • cloud.google.com/gke-tpu-slice-topology:指定 "4x12x16" 作为 动态切片拓扑。tpu7x 加速器拓扑的要求包括以下规则:
      • 对于动态子切片 :您可以指定小于 4x4x4 的拓扑,例如 2x2x12x2x22x2x42x4x4。 这些较小的拓扑需要 GKE 1.36.0-gke.3712000 版或更高版本。
      • 对于动态超级切片 :您可以指定等于或大于 4x4x4 的拓扑。对于动态超级切片配置,所请求拓扑的每个维度都必须是 4 的倍数,例如 4A x 4B x 4C
      • 拓扑必须是 AxBxC 格式的三维字符串,例如 4x8x8
      • 维度必须按非递减顺序排序:A <= B <= C。例如,4x8x4 无效;它应该是 4x4x8
      • 维度的乘积 (ABC) 不得超过 9,216。
      • 支持的最大切片拓扑最多可以包含 32 个子块。例如,包含 32 个子块的 8x16x16、包含 30 个子块的 8x12x20 或包含 27 个子块的 12x12x12 都在可接受的范围内。
    • cloud.google.com/gke-tpu-accelerator: tpu7x:在运行 Ironwood (TPU7x) 的虚拟机上调度 Pod。
    • kueue.x-k8s.io/queue-name:将 JobSet 分配给 Kueue LocalQueue。
    • webhook 会注入默认节点亲和性,以确保使用 HEALTHYDEGRADED 节点。
  2. 应用 big-super-slice.yaml 清单:

    kubectl apply -f big-super-slice.yaml
    

    应用清单后,Kueue 会创建一个名为 big-super-sliceJobSet。 然后,Kueue 会尝试形成具有 4x12x16 拓扑的单个动态切片。 切片处于活跃状态后,Kueue 会允许工作负载,并在节点上调度 192 个 Pod,以形成运行工作负载的动态切片。

示例 2:具有多个副本的工作负载

以下示例演示了如何创建使用两个动态切片的工作负载,每个切片由四个子块组成,仅以 HEALTHY 节点为目标。

  1. 将以下清单保存为 two-super-slices.yaml

    # Copyright 2026 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #      http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    apiVersion: jobset.x-k8s.io/v1alpha2
    kind: JobSet
    metadata:
      name: two-super-slices
      labels:
        kueue.x-k8s.io/queue-name: lq
    spec:
      replicatedJobs:
        - name: job-jax
          replicas: 2
          template:
            spec:
              parallelism: 64  # Pods per slice calculation: (4*8*8) / 4 = 64
              completions: 64
              backoffLimit: 10
              template:
                metadata:
                  annotations:
                    cloud.google.com/gke-tpu-slice-topology: 4x8x8
                spec:
                  tolerations:
                    - key: "google.com/tpu"
                      operator: "Equal"
                      value: "present"
                      effect: "NoSchedule"
                  nodeSelector:
                    cloud.google.com/gke-tpu-accelerator: tpu7x
                    cloud.google.com/gke-tpu-partition-4x4x4-state: "HEALTHY"
                  containers:
                    - name: jax
                      image: python:latest
                      command:
                        - bash
                        - -c
                        - |
                          printenv
                          pip install "jax[tpu]" -f https://storage.googleapis.com/jax-releases/libtpu_releases.html
                          python -c 'import jax; print("Global device count:", jax.device_count(), "Local device count:", jax.local_device_count())'
                      resources:
                        limits:
                          google.com/tpu: 4
                  restartPolicy: Never
    
  2. 应用 two-super-slices.yaml 清单:

    kubectl apply -f two-super-slices.yaml
    

在此清单中,您在 replicatedJobs 部分中将 replicas 字段设置为 2。 应用清单后,Kueue 会尝试形成两个具有 4x8x8 拓扑的单独切片。Kueue 会为 jobset.spec.replicatedJobs[].replicas 中定义的每个副本创建一个动态切片。 如果指定了 n 个副本,Kueue 会为工作负载创建 n 个动态切片,并等待所有切片处于活跃状态,然后才允许工作负载。

监控切片

您可以使用 GKE 系统指标 查看切片的状态并监控切片指标。

监控切片的状态

如需检查动态切片的状态,请运行以下命令:

kubectl describe slice SLICE_NAME

SLICE_NAME 替换为切片的名称。切片名称通常派生自 JobSet 名称和副本索引。对于 示例 1,Kueue 创建的切片的名称类似于 default-jobset-big-super-slice-yyyyy-job-jax-0

输出类似于以下内容:

Name:         test-slice
Namespace:
Labels:       <none>
Annotations:  <none>
API Version:  accelerator.gke.io/v1beta1
Kind:         Slice
Metadata:
  Creation Timestamp:  2026-02-12T23:44:28Z
  Finalizers:
    accelerator.gke.io/slice-finalizer
  Generation:        1
  Resource Version:  1770939905695871008
  UID:               6dbbfe14-4486-4462-864d-e078d0ca8b5b
Spec:
  Partition Ids:
    5eae6a4f59d59cf30a9bf49de618eb2b
  Topology:  4x4x4
  Type:      tpu7x
Status:
  Conditions:
    Last Transition Time:  2026-02-12T23:45:05Z
    Message:
    Reason:                ACTIVE
    Status:                True
    Type:                  Ready
    Last Transition Time:  2026-02-12T23:45:05Z
    Message:               NodeLabelingCompleted
    Reason:                NodeLabelIsAdded
    Status:                True
    Type:                  NodeLabeled
Events:                    <none>

切片名称遵循以下规则,以确保与底层 Compute Engine 资源命名惯例兼容:

  • 模板{namespace}-jobset-{jobset.metadata.name}-kueueHash[5-character]-{jobset.spec.replicatedJobs[].name}-sliceIndex
  • 长度:名称包含 49 个或更少的字符。控制器会附加连字符和 8 个字符的集群哈希值来创建 Compute Engine 资源名称,这些名称的长度限制为 63 个字符。
  • 格式:名称与正则表达式 ^[a-z]([-a-z0-9]*[a-z0-9])?$ 匹配。名称具有以下 特征:
    • 以小写字母开头。
    • 仅包含小写字母、数字和连字符 (-)。
    • 以小写字母或数字结尾(不能以 连字符结尾)。

监控切片的指标

您可以监控以下 GKE 系统指标,这些指标会显示切片的状态:

  • kubernetes.io/accelerator/slice/state
  • kubernetes.io/accelerator/partition/state
  • kubernetes.io/accelerator/slice/deformation_durations
  • kubernetes.io/accelerator/slice/formation_durations

如需详细了解这些指标,请参阅 GKE 系统指标

清理

为避免意外收费,请先删除切片,然后再删除节点池。

  1. 删除 JobSet。此操作会触发 Kueue 删除关联的 Slice 自定义资源。

    kubectl delete jobset JOBSET_NAME
    

    JOBSET_NAME 替换为 JobSet 的名称,例如 big-super-slice

  2. 删除 TPU 节点池:

    gcloud container node-pools delete NODE_POOL_NAME \
        --cluster=CLUSTER_NAME \
        --location=LOCATION
    

(可选)使用您自己的调度器进行动态切片

本文档重点介绍如何使用 Kueue 和 TAS。不过,您也可以使用自己的自定义调度器管理动态切片。如果您选择使用其他 调度器,请遵循 Slice 自定义资源 参考信息。

后续步骤