使用 Kueue 和 TAS 调度动态切片

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

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

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

要求

如需在 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 可能不支持运行本文档中的命令。

在 GKE 中将动态切片与 Kueue 搭配使用

本部分介绍了在 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 容量转换为节点池,这些节点池由 Ironwood (TPU7x) 虚拟机或子块的 16 节点组组成。即使 GKE 无法找到所有运行状况良好的虚拟机,它也会通过将节点放置在宿主机运行状况良好的部分,并在运行状况不佳的机器修复时以增量方式预配这些机器,来预配这些节点池。

您可以将节点池定位到以下任一位置:

  • 在全容量模式预留中公开的特定 TPU 块。通过块定位,GKE 可以在指定块内的任何可用子块中创建节点池。
  • TPU 的特定子块或特定 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 值表示该块有四个可用的子块,您需要创建四个单独的节点池。

  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. 如需确定子块的名称,请列出块的所有子块,并复制 reservationSubBlocks 下每个条目的 name: 字段中的值。此值是本文档中子块或 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 自定义资源(而非 Pod)来定义指定的拓扑,切片控制器会激活该拓扑。
  • 使用 Kueue 和 TAS 调度 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: Role
    metadata:
      labels:
        app.kubernetes.io/managed-by: kustomize
        app.kubernetes.io/name: slice-controller
        control-plane: controller-manager
      name: slice-controller-webhook-secrets-role
      namespace: slice-controller-system
    rules:
    - apiGroups:
      - ""
      resources:
      - secrets
      verbs:
      - get
      - list
      - watch
      - update
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      labels:
        control-plane: controller-manager
      name: slice-controller-manager-role
    rules:
    - apiGroups:
      - ""
      resources:
      - nodes
      - pods
      verbs:
      - get
      - list
      - 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:
      - accelerator.gke.io
      resources:
      - slices/status
      verbs:
      - get
      - patch
      - update
    - apiGroups:
      - admissionregistration.k8s.io
      resources:
      - mutatingwebhookconfigurations
      verbs:
      - get
      - list
      - update
      - watch
    - apiGroups:
      - batch
      resources:
      - jobs
      verbs:
      - get
      - list
      - patch
      - update
      - watch
    - apiGroups:
      - events.k8s.io
      resources:
      - events
      verbs:
      - create
      - patch
      - update
      - watch
    - apiGroups:
      - jobset.x-k8s.io
      resources:
      - jobsets
      verbs:
      - get
      - list
      - patch
      - update
      - watch
    - apiGroups:
      - kueue.x-k8s.io
      resources:
      - admissionchecks
      verbs:
      - get
      - list
      - watch
    - apiGroups:
      - kueue.x-k8s.io
      resources:
      - admissionchecks/status
      - workloads/status
      verbs:
      - get
      - patch
      - update
    - apiGroups:
      - kueue.x-k8s.io
      resources:
      - workloads
      verbs:
      - create
      - get
      - list
      - patch
      - update
      - watch
    - apiGroups:
      - leaderworkerset.x-k8s.io
      resources:
      - leaderworkersets
      verbs:
      - get
      - list
      - patch
      - update
      - watch
    - apiGroups:
      - ray.io
      resources:
      - rayclusters
      - rayjobs
      verbs:
      - 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: RoleBinding
    metadata:
      labels:
        app.kubernetes.io/managed-by: kustomize
        app.kubernetes.io/name: slice-controller
        control-plane: controller-manager
      name: slice-controller-webhook-secrets-rolebinding
      namespace: slice-controller-system
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: slice-controller-webhook-secrets-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=60m
            - --kube-api-qps=100
            - --kube-api-burst=200
            - --default-slice-health-node-affinity=HEALTHY_AND_DEGRADED
            - --reuse-slices=true
            - --add-preferred-node-affinity=true
            command:
            - /manager
            image: tpuongke/kueue-slice-controller:v0.10
            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: 12
                memory: 32Gi
              requests:
                cpu: 8
                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
    - admissionReviewVersions:
      - v1
      clientConfig:
        service:
          name: slice-controller-webhook-service
          namespace: slice-controller-system
          path: /mutate-ray-io-v1-raycluster
      failurePolicy: Fail
      name: mraycluster.kb.io
      rules:
      - apiGroups:
        - ray.io
        apiVersions:
        - v1
        operations:
        - CREATE
        resources:
        - rayclusters
      sideEffects: None
    - admissionReviewVersions:
      - v1
      clientConfig:
        service:
          name: slice-controller-webhook-service
          namespace: slice-controller-system
          path: /mutate-ray-io-v1-rayjob
      failurePolicy: Fail
      name: mrayjob.kb.io
      rules:
      - apiGroups:
        - ray.io
        apiVersions:
        - v1
        operations:
        - CREATE
        resources:
        - rayjobs
      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/tpu 的 nominalQuota 字段:
      • 特定配额:将 nominalQuota 字段设置为与现有容量匹配,以便进行公平共享和配额管理。
      • 无限制配额:将 nominalQuota 字段设置为非常高的值(例如 "999999"),以模拟无限制配额。为了专注于 TAS 和动态切片,此配置会绕过 Kueue 的配额管理功能。

定义分区健康状况选择

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

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

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

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

具体行为如下:

  • 如果存在定位到 cloud.google.com/gke-tpu-partition-[shape]-state 标签的 nodeSelector 或 nodeAffinity,则该标签保持不变。
  • 如果不存在此类标签配置,则网络钩子会注入以下默认节点亲和性,以确保仅使用可用分区:

    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 的拓扑,例如 2x2x1、2x2x2、2x2x4 或 2x4x4。这些较小的拓扑需要 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。
    • 该网络钩子会注入默认节点亲和性,以确保使用 HEALTHY 和 DEGRADED 节点。
  2. 应用 big-super-slice.yaml 清单:

    kubectl apply -f big-super-slice.yaml
    

    应用清单后,Kueue 会创建一个名为 big-super-slice 的 JobSet。然后,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 个动态切片,并等待所有切片变为活跃状态,然后再准入工作负载。

通过切片重用优化工作负载调度

默认情况下,Kueue 会指示切片控制器为每次工作负载执行预配一个新的 TPU 切片,并在工作负载完成时将其删除。此行为可能会导致底层基础架构出现流失和开销。

借助切片重复使用功能,新工作负载可以重复使用具有相同拓扑和硬件限制的现有空闲 TPU 切片。启用切片重复使用后,Kueue 会在作业结束时将切片标记为空闲,而不是将其删除。请求同一分区的新作业会立即声明并重复使用该切片,从而绕过硬件预配延迟。

启用切片重复使用

如需充分优化切片重复使用,您必须同时配置 Slice 控制器和 Kueue,使其协同工作。

  1. 配置切片控制器:更新 Kueue 切片控制器部署参数,以包含 --reuse-slices=true 标志。为帮助确保在现有切片上以最佳方式调度工作负载,还请添加 --add-preferred-node-affinity=true 标志。

  2. 配置 Kueue(推荐):如需允许 Kueue 使用控制器的首选节点亲和性建议,您必须在 Kueue 配置中启用 TASRespectNodeAffinityPreferred 特性门控。

    例如,修改 kueue-manager-config ConfigMap 以添加特性门控:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: kueue-manager-config
      namespace: kueue-system
    data:
      controller_manager_config.yaml: |
        apiVersion: config.kueue.x-k8s.io/v1beta1
        kind: Configuration
        featureGates:
          TASRespectNodeAffinityPreferred: true
        # ...
    

    更改 ConfigMap 后,重启 kueue-controller-manager 部署以强制执行更改:

    kubectl rollout restart deploy kueue-controller-manager -n kueue-system
    

强制执行每个工作负载的切片删除

如需让特定工作负载清理其切片并防止切片重复使用,请完成以下步骤:

  1. 将以下标签应用于作业或 JobSet 定义:

    kueue.gke.io/tpu-enforce-slice-deletion: "true"
    

    应用此标签后,工作负载仍可调度到现有的空闲切片上。不过,在工作负载完成后,切片将被永久删除,而不是返回到可重复使用的池中。

  2. 将此标签添加到 Kueue 配置中的 labelKeysToCopy 列表,以配置 Kueue 将此标签从框架作业传递到 Kueue 工作负载对象:

    labelKeysToCopy:
    - "kueue.gke.io/tpu-enforce-slice-deletion"
    

监控切片

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

监控切片的状态

当工作负载创建或主动使用切片时,切片控制器会附加标签,以标识使用该切片的工作负载。由于切片名称是动态生成的(并且在启用重复使用时与工作负载名称分离),因此您应使用这些标签来查找分配给工作负载的切片。

  1. 如需查找分配给工作负载的切片,请运行以下命令:

    kubectl get slice -l kueue.gke.io/tpu-slice-used-by-namespace=NAMESPACE,kueue.gke.io/tpu-slice-used-by-workload=WORKLOAD_NAME
    

    替换以下内容:

    • NAMESPACE:工作负载的命名空间。
    • WORKLOAD_NAME:Kueue 工作负载的名称,通常与作业或 JobSet 的名称相同。
  2. 从上一个命令的输出中复制切片名称。

  3. 使用切片名称查看动态切片的详细状态:

    kubectl describe slice SLICE_NAME
    

    将 SLICE_NAME 替换为切片的名称。

输出类似于以下内容:

Name:         s-4x4x4-74d3fb0b
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>

监控切片的指标

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

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

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

Kueue Slice 控制器指标

您还可以监控 Kueue Slice Controller 公开的以下 Prometheus 指标,以观察切片生命周期、重复使用和准入检查:

切片生命周期指标

Slice 生命周期指标会跟踪切片的创建和删除:

  • tpu_ac_slice_create_time:测量切片创建时长的直方图。
  • tpu_ac_slices_created:跟踪已创建切片的计数器(包含 is_reusable 标签)。
  • tpu_ac_slices_status:按状态跟踪当前切片数量的计量器,包括 is_reusable 和 in_use 标签。
  • tpu_ac_slice_delete_time:测量切片删除操作所用时间的直方图。
  • tpu_ac_slices_deleted:跟踪已删除切片的计数器。
  • tpu_ac_slices_gc:计数器跟踪自动清理了切片。

切片重用指标

Slice 重用指标可跟踪 TPU 切片的成功重用和冲突:

  • tpu_ac_slices_reused:跟踪成功重复使用的切片的计数器。
  • tpu_ac_slices_conflict:跟踪因拓扑或形状不匹配而被删除的切片的计数器。

工作负载和准入指标

工作负载和准入指标可跟踪准入检查的时长和结果:

  • tpu_ac_admission_time:衡量准入检查过程时长的直方图。注意:此指标衡量的是切片控制器的准入检查时长,不包括 Kueue 工作负载的总体准入时间。
  • tpu_ac_workload_processed:准入检查决策计数器,包含 target_state 标签。

常规指标

常规指标用于跟踪运行问题和错误:

  • tpu_ac_problem:跟踪操作问题或错误的计数器。此指标包含一个 problem 标签,用于指示具体的错误类型。

清理

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

  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。不过,您也可以使用自己的自定义调度器来管理动态切片。如果您选择使用其他调度器,请遵循切片自定义资源参考信息。

后续步骤