תזמון פלחים דינמיים באמצעות Kueue ו-TAS

במאמר הזה מוסבר איך להקצות מאגרי צמתים של TPU ולתזמן פרוסות דינמיות ב-Google Kubernetes Engine‏ (GKE) באמצעות Kueue וTopology Aware Scheduling (TAS).

אפשר גם להשתמש בפילוח דינמי באמצעות אינטראקציה ישירה עם פילוח של משאבים בהתאמה אישית. מידע נוסף זמין במאמר בנושא שימוש בחלוקה דינמית עם מתזמן מותאם אישית.

לפני שמבצעים את ההוראות האלה, חשוב להבין את המושגים של חלוקה דינמית.

דרישות

כדי להשתמש בפילוח דינמי ב-GKE, אתם צריכים לעמוד בדרישות הבאות:

  • משתמשים באשכול Standard בערוץ מהיר באחת מהגרסאות הבאות:
    • כדי להגדיר חלוקה דינמית של סופר-סלייס (טופולוגיות ששווה ל-4x4x4 או גדולות ממנו), צריך להשתמש בגרסה 1.35.2-gke.1842000 ואילך.
    • כדי להגדיר חלוקה דינמית למקטעי משנה (טופולוגיות קטנות מ-4x4x4), צריך להשתמש בגרסה 1.36.0-gke.3712000 ואילך.
  • שימוש בגרסת Ironwood‏ (TPU7x).
  • משתמשים בקובץ אימג' של מערכת הפעלה שמותאמת לקונטיינרים עבור הצמתים.
  • כדי להשתמש בהקצאת משאבים מצטברת, צריך להשתמש בהזמנות במצב 'כל הקיבולת'. כל מצב הקיבולת הוא תכונה שמופעלת על ידי TPU Cluster Director.
  • כדי להשתמש בחלוקת משנה דינמית, צריך לוודא שיש בצמתים אירועי תחזוקה בהמתנה. מעקב אחר אירועי תחזוקה בהמתנה במכונות שלכם. אם יש לכם צמתים עם אירוע תחזוקה בהמתנה שזמן הסיום שלו הוא בין 18 בספטמבר 2026 ל-30 בספטמבר 2026, תצטרכו להפעיל ידנית את אירוע התחזוקה של המארח בצמתים האלה כדי שתוכלו להשתמש בחלוקת משנה.

לפני שמתחילים

לפני שמתחילים, חשוב לוודא שביצעתם את הפעולות הבאות:

  • מפעילים את ממשק Google Kubernetes Engine API.
  • הפעלת Google Kubernetes Engine API
  • כדי להשתמש ב-CLI של Google Cloud למשימה הזו, צריך להתקין ואז לאתחל את ה-CLI של gcloud. אם התקנתם בעבר את ה-CLI של gcloud, מריצים את הפקודה gcloud components update כדי לקבל את הגרסה העדכנית. יכול להיות שגרסאות קודמות של ה-CLI של gcloud לא יתמכו בהרצת הפקודות שמופיעות במסמך הזה.

שימוש בפילוח דינמי ב-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
    

    מחליפים את מה שכתוב בשדות הבאים:

  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 בגרסה 0.18.2 ואילך. כדי להשתמש בפריסה דינמית של נתונים, צריך להשתמש ב-Kueue מגרסה 0.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 בגרסה 0.12.0 ואילך. כדי להשתמש ב-dynamic super-slicing, צריך להשתמש ב-JobSet מגרסה 0.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 בגרסה 0.8.0 ואילך.

יצירת מאגרי צמתים עם הקצאת משאבים מצטברת

בקטע הזה מוסבר איך ליצור מאגרי צמתים של TPU עם הקצאת משאבים מצטברת. ‫GKE ממיר את כל קיבולת ה-TPU שלכם למאגרי צמתים שכוללים קבוצות של 16 צמתים של מכונות וירטואליות של Ironwood‏ (TPU7x) או בלוקים משניים. ‫GKE מקצה את מאגרי הצמתים האלה גם אם הוא לא מצליח למצוא את כל המכונות הווירטואליות התקינות, על ידי הצבת צמתים בחלקים תקינים של המכונה המארחת והקצאה מצטברת של מכונות לא תקינות בזמן שהן מתוקנות.

אתם יכולים לטרגט את מאגר הצמתים כך שישתייך לאחת מהקטגוריות הבאות:

  • בלוק ספציפי של יחידות TPU, שמוצג בהזמנות במצב 'כל הקיבולת'. טירגוט בלוקים מאפשר ל-GKE ליצור את מאגר הצמתים בכל תת-בלוק זמין בתוך הבלוק שצוין.
  • תת-בלוק ספציפי או קבוצה ספציפית של 16 צמתים של מכונות וירטואליות של Ironwood (TPU7x) של TPU, כדי לקבל שליטה מפורטת יותר.

יצירת מדיניות של עומס עבודה

כדי ליצור מאגר צמתים של פרוסת TPU עם Ironwood‏ (TPU7x), קודם צריך ליצור מדיניות של עומס עבודה עם השדה 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 .
  • REGION: האזור של מדיניות עומס העבודה.

בפקודה הזו, מבצעים את הפעולות הבאות::

  • תמיד מגדירים את השדה accelerator-topology לערך 4x4x4 כדי להתאים למספר הכולל של הצ'יפים בתוך בלוק משנה יחיד.
  • כדי להפעיל את תהליך ההקצאה המצטבר, צריך תמיד להגדיר את השדה accelerator-topology-mode לערך provision_only. כשמגדירים את השדה provision_only, מאגר הצמתים מספק צמתי TPU בלי ליצור קישורי ICI או OCS.

טירגוט מאגר הצמתים כך שישתייך לבלוק או לתת-בלוק

אתם יכולים לטרגט יחידות משנה ספציפיות או יחידות בתוך ההזמנה במצב 'כל הקיבולת'.

  • טירגוט של בלוק: כל מאגר צמתים משתמש בקיבולת מבלוק ספציפי. ‫GKE ממקם את מאגר הצמתים בתוך תת-בלוק זמין בבלוק הזה. צריך ליצור מאגרי צמתים כמספר תתי הבלוקים בבלוק שרוצים להשתמש בו.
  • טירגוט של בלוק משנה: כל מאגר צמתים ממופה לבלוק משנה ספציפי וזמין. כשמשתמשים בטירגוט של בלוק משנה, GKE יוצר את מאגר הצמתים אם לפחות מכונה וירטואלית אחת תקינה. הקצאת הרשאות מצטברת עוזרת לוודא שכל הצמתים ממוקמים בתוך בלוק המשנה שצוין.

חסימה

  1. כדי לאחזר את השם של הבלוק בהזמנה ואת מספר תתי הבלוקים הזמינים בבלוק, צריך לבצע את השלבים הבאים במסמך View the topology and health status of All Capacity Mode reservations:

    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.

Sub-block

  1. כדי לאחזר את השם של הבלוק ואת המזהים של תתי הבלוקים הזמינים, צריך לבצע את השלבים הבאים במסמך View the topology and health status of All Capacity Mode reservations (הצגת הטופולוגיה וסטטוס התקינות של כל ההזמנות במצב קיבולת):

    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 .
    • CLUSTER_NAME: השם של אשכול GKE.
    • ZONE: האזור של מאגר הצמתים, לדוגמה, us-central2-b.
    • WORKLOAD_POLICY_NAME: השם של מדיניות העומס שיצרתם.

בשלב הזה, הצמתים נוצרים, אבל הקישורים שלהם ל-Inter-Chip Interconnect (ICI) עדיין לא פעילים. לכן, אי אפשר להריץ עומסי עבודה במאגרי הצמתים האלה באופן ישיר.

כדי להפעיל את כל הקישורים הדרושים של ICI כדי ליצור את הפרוסה ולאפשר תזמון של עומסי עבודה, צריך ליצור פרוסה דינמית באחת מהשיטות הבאות:

  • יוצרים משאב מותאם אישית של Slice. במקום Pods, משתמשים במשאב מותאם אישית מסוג Slice כדי להגדיר את הטופולוגיה שצוינה, והבקר של ה-Slice מפעיל אותה.
  • תזמון עומסי עבודה ב-GKE באמצעות Kueue ו-TAS. ‫Kueue מטפל אוטומטית ביצירה ובמחיקה של משאבים מותאמים אישית מסוג Slice. מומלץ להימנע משינוי ידני של משאבים מותאמים אישית של Slice שנוצרו על ידי Kueue.

יצירת פלח דינמי באמצעות Kueue ו-TAS

בקטע הזה נסביר איך לתזמן עומסי עבודה של GKE באמצעות Kueue ו-TAS.

התקנה של בקר פרוסות 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 label: הרמה הזו נדרשת כדי להבין אילו בלוקים משנה שייכים לאילו בלוקים, כי רק בלוקי משנה מאותו בלוק יכולים ליצור פרוסה.
      • תווית cloud.google.com/gke-tpu-partition-4x4x4-id: הרמה הזו מייצגת תת-בלוקים נפרדים של Ironwood‏ (TPU7x) (4x4x4 טופולוגיה).
      • תווית kubernetes.io/hostname: הרמה הזו נדרשת כדי להקצות Pods למכונות וירטואליות ספציפיות וכדי לראות את התוויות וה-taints שלהן.
    • 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 בדיקת ההרשאה. אפשר להגדיר את השדה nominalQuota עבור google.com/tpu בשתי דרכים:
      • מכסת נפח אחסון ספציפית: מגדירים את השדה nominalQuota כך שיתאים לקיבולת הקיימת כדי לנהל את מכסת נפח האחסון ולשתף את הקיבולת באופן הוגן.
      • מכסה ללא הגבלה: מגדירים את השדה nominalQuota לערך גבוה מאוד כמו "999999", כדי לדמות מכסה ללא הגבלה. כדי להתמקד ב-TAS ובחלוקה דינמית, ההגדרה הזו עוקפת את הפונקציונליות של ניהול המכסות ב-Kueue.

הגדרת הבחירה של תקינות המחיצה

בנוסף לבדיקות הרגילות של תקינות ומוכנות הצומת, GKE חושף את המצב הספציפי של כל צורה של מחיצה באמצעות התווית cloud.google.com/gke-tpu-partition-[shape]-state (כאשר [shape] תואם לצורה של מזהה המחיצה, כמו 2x2x1,‏ 2x2x2,‏ 2x2x4,‏ 2x4x4 או 4x4x4). התווית הזו מאפשרת ל-GKE להתחשב בגורמים שמשפיעים על יצירת פרוסות, כמו המצב של קישורי TPU. הגדרה של חלוקת משנה דינמית (טופולוגיות קטנות מ-4x4x4) דורשת GKE בגרסה ‎1.36.0-gke.3712000 ואילך.

אפשר להגדיר את הערך של תווית מצב המחיצה באופן הבא:

  • HEALTHY: המחיצה תקינה ופועלת באופן מלא.
  • DEGRADED: התשתית של המחיצה במצב ירוד, למשל, בגלל ירידה באיכות הקישור של OCS. המחיצה עדיין יכולה ליצור פלח, אבל יכול להיות שהביצועים הכוללים יהיו נמוכים יותר בהשוואה למחיצות תקינות. הסטטוס הזה רלוונטי רק לטופולוגיה 4x4x4 ברמה העליונה. בטופולוגיות קטנות יותר אין מצב של ירידה ברמת השירות.
  • UNHEALTHY: המחיצה לא תקינה ואי אפשר ליצור ממנה פרוסה.
  • UNSET: המצב לא מוגדר בגלל אתחול לא מוצלח של בקר הפרוסות של GKE.
  • INCOMPLETE: לא כל הצמתים במחיצה הוקצו.

ה-webhook של Kueue Slice Controller מאמת אם עומס עבודה כולל דרישה ספציפית לבדיקת תקינות של מחיצה. אם לא מצוינת העדפה, ה-webhook מוסיף זיקה של צומת ברירת מחדל.

ההתנהגות היא כזו:

  • אם יש nodeSelector או nodeAffinity שמטרגטים את התווית cloud.google.com/gke-tpu-partition-[shape]-state, הם לא ישתנו.
  • אם לא קיימת הגדרת תווית כזו, ה-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. הוא כולל דוגמאות שמראות איך ליצור עומס עבודה של פלח דינמי ועומס עבודה שמורכב מכמה פלחים. עומסי העבודה נשלחים כ-JobSets.

דוגמה 1: עומס עבודה יחיד משתמש בפרוסת נפח דינמית אחת

בדוגמה הבאה מתואר איך ליצור עומס עבודה באמצעות פרוסה עם טופולוגיה של 4x12x16, שמורכבת מ-12 בלוקים משניים. מספר ה-Pods חושב כך: (‎4 * 12 * 16) / 4 שבבים לכל צומת = 192 Pods.

  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 או גדולות ממנו. כדי להגדיר חיתוך-על דינמי, כל מאפיין בטופולוגיה המבוקשת צריך להיות כפולה של ארבע, לדוגמה 4A x 4B x 4C.
      • הטופולוגיה צריכה להיות מחרוזת תלת-ממדית בפורמט AxBxC, למשל 4x8x8.
      • המידות צריכות להיות ממוינות בסדר לא יורד: A <= B <= C. לדוגמה, הערך 4x8x4 לא תקין, והוא צריך להיות 4x4x8.
      • מכפלת המידות (אורךרוחבגובה) לא יכולה להיות גדולה מ-9,216.
      • טופולוגיות הפרוסות הגדולות ביותר שנתמכות יכולות לכלול עד 32 תת-בלוקים. לדוגמה, 8x16x16 עם 32 תת-בלוקים,8x12x20 עם 30 תת-בלוקים או 12x12x12 עם 27 תת-בלוקים הם במסגרת המגבלות המותרות.
    • cloud.google.com/gke-tpu-accelerator: tpu7x: מתזמן את ה-Pods במכונות וירטואליות שמריצות Ironwood ‏ (TPU7x).
    • kueue.x-k8s.io/queue-name: מקצה את JobSet ל-LocalQueue של Kueue.
    • ה-webhook מוסיף את זיקת הצומת שמוגדרת כברירת מחדל כדי לוודא שנעשה שימוש בצמתים HEALTHY ו-DEGRADED.
  2. החלת המניפסט big-super-slice.yaml:

    kubectl apply -f big-super-slice.yaml
    

    אחרי שמחילים את המניפסט, Kueue יוצר JobSet בשם big-super-slice. לאחר מכן, Kueue מנסה ליצור פרוסת משאבים דינמית אחת עם טופולוגיה של 4x12x16. אחרי שהפרוסה פעילה, Kueue מאשר את עומס העבודה, ו-192 הפודים מתוזמנים בצמתים כדי ליצור את הפרוסה הדינמית שמריצה את עומסי העבודה.

דוגמה 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
    

במניפסט הזה, מגדירים את השדה replicas לערך 2 בקטע replicatedJobs. אחרי שמחילים את המניפסט, 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.

המאמרים הבאים