Menjadwalkan workload GKE dengan TAS

Workload AI dan ML memerlukan komunikasi Pod-ke-Pod yang signifikan. Karena persyaratan ini, bandwidth jaringan antar-Pod berdampak langsung pada waktu dan biaya eksekusi workload. Bandwidth ini bergantung pada penempatan instance virtual machine (VM) di cluster.

Dokumen ini menjelaskan cara mengoptimalkan penjadwalan workload AI atau ML berskala besar di cluster Google Kubernetes Engine (GKE) untuk performa dan keandalan. Secara khusus, Anda akan mengonfigurasi cluster untuk menggunakan Topology Aware Scheduling (TAS) untuk komunikasi latensi rendah. Pendekatan ini meminimalkan overhead komunikasi dan membantu memaksimalkan performa untuk workload Anda.

Apa itu Topology Aware Scheduling (TAS)?

TAS dapat meningkatkan efisiensi pelatihan model bahasa besar (LLM) secara signifikan. TAS menempatkan worker secara strategis di topologi jaringan untuk meminimalkan beban komunikasi selama agregasi gradien, yang mengharuskan worker berkomunikasi dalam urutan peringkat tertentu. Dengan meminimalkan hop jaringan antara worker yang berkomunikasi secara berurutan, TAS mengurangi pertentangan jaringan dan mengoptimalkan pemanfaatan bandwidth, sehingga menghasilkan konvergensi yang lebih cepat dan waktu pelatihan yang lebih singkat. Dengan model LLM yang makin besar, TAS sangat penting untuk memaksimalkan performa dan skalabilitas pelatihan terdistribusi.

TAS berfungsi optimal dengan kapasitas yang ditempatkan secara padat, yang dapat diperoleh melalui kapasitas terikat pemesanan. Dengan Spot VM dan opsi konsumsi lainnya, kapasitas Anda cenderung tidak dialokasikan berdekatan, sehingga TAS mungkin tidak berfungsi dengan baik dalam skenario ini.

Sebelum memulai

Sebelum memulai, pastikan Anda telah melakukan tugas berikut:

  • Aktifkan Google Kubernetes Engine API.
  • Aktifkan Google Kubernetes Engine API
  • Untuk menggunakan Google Cloud CLI untuk tugas ini, instal lalu lakukan inisialisasi gcloud CLI. Jika sebelumnya Anda telah menginstal gcloud CLI, dapatkan versi terbaru dengan menjalankan perintah gcloud components update. Versi gcloud CLI yang lebih lama mungkin tidak mendukung menjalankan perintah dalam dokumen ini.
  • Untuk terhubung ke cluster, jalankan perintah berikut:

    gcloud container clusters get-credentials CLUSTER_NAME
    

    Ganti CLUSTER_NAME dengan nama cluster Anda.

Menyiapkan cluster GKE

Untuk menyiapkan cluster GKE agar dapat menjalankan workload dengan TAS, selesaikan langkah-langkah berikut:

  1. Menginstal Kueue dengan TAS diaktifkan
  2. Melihat topologi cluster GKE Anda

  3. Mengonfigurasi Kueue

Menginstal Kueue dengan TAS diaktifkan

Sebaiknya gunakan TAS dengan Kueue, sistem berbasis Kubernetes yang mengelola kuota dan cara tugas menggunakannya. TAS memerlukan Kueue versi 0.10.0 atau yang lebih baru, dan Anda harus mengaktifkannya secara eksplisit.

Untuk menginstal Kueue dan mengaktifkan TAS, pilih salah satu opsi berikut:

Manifes Kueue

  1. Instal Kueue:

    kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/v0.10.0/manifests.yaml
    
  2. Aktifkan TAS di Kueue:

    kubectl -n kueue-system patch deployment kueue-controller-manager \
        --type json -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--feature-gates=TopologyAwareScheduling=true"}]'
    

Diagram Helm

Instal Kueue dengan TAS yang diaktifkan menggunakan diagram Helm:

helm install kueue oci://us-central1-docker.pkg.dev/k8s-staging-images/charts/kueue \
    --version="v0.10.0" \
    --create-namespace \
    --namespace=kueue-system \
    --set="controllerManager.featureGates[0].name=TopologyAwareScheduling,controllerManager.featureGates[0].enabled=true"

Setelah menginstal Kueue, Anda harus mengonfigurasinya untuk memahami infrastruktur yang dikelolanya, seperti yang dijelaskan di bagian berikutnya.

Melihat topologi cluster GKE Anda

Sebelum melihat topologi node A4X, A4, A3 Ultra, A3 Mega, dan A3 High (8 GPU) yang disediakan sebagai Spot VM, Anda harus menentukan penempatan rapat pada node GKE untuk mengekspos topologi fisiknya untuk TAS. Jika tidak, akan terjadi error.

Untuk melihat topologi node cluster GKE Anda di node pool tertentu, jalankan perintah berikut:

kubectl get nodes -l cloud.google.com/gke-nodepool=NODE_POOL_NAME \
    -ocustom-columns='NAME:.metadata.name,BLOCK:.metadata.labels.cloud\.google\.com/gce-topology-block,SUBBLOCK:.metadata.labels.cloud\.google\.com/gce-topology-subblock,HOST:.metadata.labels.cloud\.google\.com/gce-topology-host' | sort -k2,4

Ganti NODE_POOL_NAME dengan nama node pool.

Untuk memahami topologi fisik node GKE pada VM Anda dalam output, lihat label node berikut:

  • cloud.google.com/gce-topology-block: ID khusus organisasi dari blok yang dipesan tempat VM berada.

  • cloud.google.com/gce-topology-subblock: ID khusus organisasi dari sub-blok tempat VM berada.

  • cloud.google.com/gce-topology-host: ID host tempat VM berada.

  • kubernetes.io/hostname: nama host node Kubernetes. Nama host ini biasanya juga merupakan nama node GKE.

Makin banyak nilai label yang sama pada dua VM, makin dekat lokasi fisik kedua VM tersebut. Untuk mengetahui informasi selengkapnya tentang istilah ini, lihat Terminologi.

Mengonfigurasi Kueue

Setelah menginstal Kueue, Anda harus mengonfigurasi Kueue untuk menentukan infrastruktur yang dikelolanya. Biasanya, Kueue memerlukan definisi kuota resource ClusterQueue dari infrastruktur statis, atau infrastruktur dinamis dengan penskalaan otomatis cluster yang diaktifkan. ClusterQueue hanya menerima Workload jika resource yang diminta workload kurang dari atau sama dengan kumpulan resource yang ditentukan dalam ClusterQueue. Setelah Anda mengonfigurasi Kueue seperti yang dijelaskan di bagian ini, Kueue akan menerima workload menggunakan TAS sebagai berikut:

  • Workload TAS: Kueue memeriksa topologi infrastruktur fisik dan penggunaan saat ini.

  • Workload non-TAS: Kueue tidak memeriksa topologi infrastruktur fisik. Kueue mengelola seluruh kuota yang ditentukan dalam konfigurasi dan menyerahkan penetapan node ke kube-scheduler.

Untuk memahami cara memberikan definisi kuota resource ClusterQueue ke Kueue, tinjau contoh berikut:

  • Kuota sangat tinggi: Kueue praktis tidak pernah menghentikan penerimaan workload berdasarkan resource yang diminta. Berdasarkan definisi TAS, Kueue mungkin atau mungkin tidak menerima workload berdasarkan topologi infrastruktur. Untuk mengetahui informasi selengkapnya, lihat Kuota resource yang sangat tinggi.

  • Kuota realistis: Kueue hanya menerima Workload jika resource yang diminta Workload berada dalam batas kuota resource ini. Berdasarkan definisi TAS, Kueue kemudian memeriksa topologi infrastruktur sebelum menerima Workload. Untuk mengetahui informasi selengkapnya, lihat Kuota resource yang realistis.

Semua referensi ke kuota resource di bagian berikut mengacu pada kuota resource ClusterQueue.

Kuota resource sangat tinggi

Contoh berikut menggunakan kuota resource yang sangat tinggi, sehingga Kueue tidak pernah menghentikan workload berdasarkan kuota resource yang tersedia. Sebagai gantinya, Kueue menggunakan informasi topologi node yang tersedia untuk mencoba dan mencocokkan topologi dengan persyaratan workload.

Untuk menggunakan definisi kuota resource berikut, selesaikan langkah-langkah berikut:

  1. Buka editor file pilihan Anda. Kemudian, sertakan definisi kuota berikut dalam file YAML bernama kueue-tas-config-very-high-quota.yaml:

      apiVersion: kueue.x-k8s.io/v1alpha1
      kind: Topology
      metadata:
        name: "gke-default"
      spec:
        levels:
        - nodeLabel: "cloud.google.com/gce-topology-block"
        - nodeLabel: "cloud.google.com/gce-topology-subblock"
        - nodeLabel: "cloud.google.com/gce-topology-host"
        - nodeLabel: "kubernetes.io/hostname"
    ---
      kind: ResourceFlavor
      apiVersion: kueue.x-k8s.io/v1beta1
      metadata:
        name: "tas-flavor"
      spec:
        nodeLabels:
          cloud.google.com/gke-nodepool: "NODE_POOL_NAME"
        topologyName: "gke-default"
        tolerations:
        - key: "nvidia.com/gpu"
          operator: "Exists"
          effect: NoSchedule
    ---
      apiVersion: kueue.x-k8s.io/v1beta1
      kind: ClusterQueue
      metadata:
        name: "tas-cluster-queue"
      spec:
        namespaceSelector: {}
        resourceGroups:
        - coveredResources: ["nvidia.com/gpu"]
          flavors:
          - name: "tas-flavor"
            resources:
            - name: "nvidia.com/gpu"
              nominalQuota: 10000000
    ---
      apiVersion: kueue.x-k8s.io/v1beta1
      kind: LocalQueue
      metadata:
        namespace: "default"
        name: "tas-user-queue"
      spec:
        clusterQueue: "tas-cluster-queue"
    

    Ganti NODE_POOL_NAME dengan nama node pool.

  2. Buat dan terapkan konfigurasi kuota resource untuk sistem antrean tugas Kueue:

    kubectl create -f kueue-tas-config-very-high-quota.yaml
    

Kuota resource yang realistis

Contoh sebelumnya hanya mengonfigurasi resource GPU. Namun, Kueue dapat mengelola semua resource yang kompatibel dengan Kubernetes.

Contoh berikut menentukan kuota resource yang lebih realistis, termasuk CPU, memori, dan GPU. Ini untuk 100 mesin a3-ultragpu-8g. Satu mesin memiliki 224 vCPU, memori 2.944 GB, dan 8 GPU. Prinsip yang sama berlaku untuk jenis mesin GPU Umum (A2, A3 Edge, G2, G4, dan N1), menggunakan spesifikasi CPU dan memori masing-masing.

Untuk menggunakan definisi kuota resource berikut, selesaikan langkah-langkah berikut:

  1. Buka editor file pilihan Anda. Kemudian, sertakan definisi kuota berikut dalam file YAML bernama kueue-tas-config-real-quota.yaml:

      apiVersion: kueue.x-k8s.io/v1alpha1
      kind: Topology
      metadata:
        name: "gke-default"
      spec:
        levels:
        - nodeLabel: "cloud.google.com/gce-topology-block"
        - nodeLabel: "cloud.google.com/gce-topology-subblock"
        - nodeLabel: "cloud.google.com/gce-topology-host"
        - nodeLabel: "kubernetes.io/hostname"
    ---
      kind: ResourceFlavor
      apiVersion: kueue.x-k8s.io/v1beta1
      metadata:
        name: "tas-flavor"
      spec:
        nodeLabels:
          cloud.google.com/gke-nodepool: "NODE_POOL_NAME"
        topologyName: "gke-default"
        tolerations:
        - key: "nvidia.com/gpu"
          operator: "Exists"
          effect: NoSchedule
    ---
      apiVersion: kueue.x-k8s.io/v1beta1
      kind: ClusterQueue
      metadata:
        name: "tas-cluster-queue"
      spec:
        namespaceSelector: {} # match all
        resourceGroups:
        - coveredResources: ["cpu", "memory", "nvidia.com/gpu"]
          flavors:
          - name: "tas-flavor"
            resources:
            # numbers below represent quota of 100 a3-ultragpu-8g machines
            - name: "cpu"
              nominalQuota: 22400
            - name: "memory"
              nominalQuota: 294400Gi
            - name: "nvidia.com/gpu"
              nominalQuota: 800
    ---
      apiVersion: kueue.x-k8s.io/v1beta1
      kind: LocalQueue
      metadata:
        namespace: "default"
        name: "tas-user-queue"
      spec:
        clusterQueue: "tas-cluster-queue"
    

    Ganti NODE_POOL_NAME dengan nama node pool.

  2. Buat dan terapkan konfigurasi kuota resource untuk sistem antrean tugas Kueue:

    kubectl create -f kueue-tas-config-real-quota.yaml
    

    Outputnya mirip dengan hal berikut ini:

    topology.kueue.x-k8s.io/gke-default created
    resourceflavor.kueue.x-k8s.io/tas-flavor created
    clusterqueue.kueue.x-k8s.io/tas-cluster-queue created
    localqueue.kueue.x-k8s.io/tas-user-queue created
    

Menjadwalkan workload dengan TAS menggunakan Kueue

Skenario berikut menunjukkan cara menginstruksikan Kueue dan TAS untuk mengelola kombinasi workload dan infrastruktur umum menggunakan jenis permintaan topologi dan tingkat permintaan topologi:

  • Berikut adalah jenis permintaan topologi yang tersedia (yang diutamakan atau yang wajib):

    • kueue.x-k8s.io/podset-preferred-topology: Kueue memprioritaskan penjadwalan seluruh workload dalam level topologi tertentu, tetapi tetap menerima workload yang tidak sesuai dengan level topologi ini. Untuk workload yang mungkin sesuai dengan satu level topologi, Kueue mungkin menjadwalkan workload tersebut di beberapa instance level topologi tersebut.

    • kueue.x-k8s.io/podset-required-topology: Kueue terus mencoba menerima workload ini hingga seluruh workload dapat ditempatkan dalam level topologi yang dipilih.

  • Berikut adalah level permintaan topologi yang tersedia, sehingga Anda dapat lebih atau kurang spesifik tentang infrastruktur fisik tempat Anda lebih memilih atau memerlukan Tugas untuk dijalankan:

    • cloud.google.com/gce-topology-block

    • cloud.google.com/gce-topology-subblock

    • cloud.google.com/gce-topology-host

    • kubernetes.io/hostname

Untuk menjadwalkan workload menggunakan nilai ini, gunakan file YAML Tugas berikut:

apiVersion: batch/v1
kind: Job
metadata:
  generateName: JOB_NAME
  labels:
    kueue.x-k8s.io/queue-name: tas-user-queue
spec:
  parallelism: NUMBER_OF_REPLICAS
  completions: NUMBER_OF_REPLICAS
  completionMode: Indexed
  template:
    metadata:
      annotations:
        ANNOTATIONS_STRING
    spec:
      containers:
      - name: dummy-job
        image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
        args: ["60s"]
        resources:
          requests:
            nvidia.com/gpu: "1"
          limits:
            nvidia.com/gpu: "1"
      restartPolicy: Never

Ganti variabel berikut:

  • JOB_NAME: nama untuk Tugas.

  • NUMBER_OF_REPLICAS: jumlah Pod yang berjalan secara paralel.

  • ANNOTATIONS_STRING: lihat tabel berikut:

    Jenis dan tingkat topologi yang diminta Deskripsi ANNOTATIONS_STRING
    Lebih disukai untuk dijalankan dalam nama host (direkomendasikan) Konfigurasi ini akan menerima workload Anda selama ada cukup resource yang tersedia untuk memenuhi persyaratan resource workload Anda, meskipun kapasitasnya terfragmentasi. Kueue akan menjadwalkan Pod Anda sepadat mungkin. kueue.x-k8s.io/podset-preferred-topology: "kubernetes.io/hostname"
    Diperlukan untuk dijalankan dalam host

    Konfigurasi ini akan menerima workload Anda jika dan hanya jika ada host yang tersedia dengan resource yang cukup untuk memenuhi persyaratan resource workload Anda.

    Hal ini berguna jika ada beberapa VM per host (misalnya, jenis mesin yang lebih kecil) atau beberapa Pod dapat berjalan di satu node. Dalam kasus tersebut, jika workload diterima, workload akan berjalan di satu host.

    kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-host"
    Lebih disukai untuk dijalankan dalam host Konfigurasi ini akan menerima workload Anda selama ada cukup resource yang tersedia untuk memenuhi persyaratan resource workload Anda, meskipun kapasitasnya terfragmentasi. Kueue akan mencoba menjadwalkan Pod Anda dalam satu host dan akan menggunakan host tambahan jika diperlukan. kueue.x-k8s.io/podset-preferred-topology: "cloud.google.com/gce-topology-host"
    Wajib dijalankan dalam sub-blok Konfigurasi ini akan menerima workload Anda jika dan hanya jika ada sub-blok yang tersedia dengan resource yang cukup untuk memenuhi persyaratan resource workload Anda. kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-subblock"
    Lebih cocok untuk dijalankan dalam sub-blok Konfigurasi ini akan menerima workload Anda selama ada cukup resource yang tersedia untuk memenuhi persyaratan resource workload Anda, meskipun kapasitasnya terfragmentasi. Kueue akan mencoba menjadwalkan Pod Anda dalam sub-blok dan akan menggunakan sub-blok tambahan jika diperlukan. Dalam hal ini, Kueue akan memberi peringkat lebih tinggi pada sub-blok dengan kapasitas yang lebih besar meskipun terfragmentasi dibandingkan dengan sub-blok dengan kapasitas yang cukup untuk memenuhi persyaratan. kueue.x-k8s.io/podset-preferred-topology: "cloud.google.com/gce-topology-subblock"
    Diperlukan untuk dijalankan dalam blok Konfigurasi ini akan mengizinkan workload Anda jika dan hanya jika resource yang tersedia dalam blok memenuhi persyaratan resource workload Anda. Jika diterima, Kueue akan meminimalkan jumlah sub-blok dan host untuk menjadwalkan workload. Hal ini dapat menyebabkan fragmentasi kapasitas yang tersedia. kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
    Lebih disukai untuk dijalankan dalam blok Konfigurasi ini akan menerima workload Anda selama ada cukup resource yang tersedia untuk memenuhi persyaratan resource workload Anda, meskipun kapasitasnya terfragmentasi. Kueue akan mencoba menjadwalkan Pod Anda dalam satu blok dan akan menggunakan blok tambahan jika diperlukan. kueue.x-k8s.io/podset-preferred-topology: "cloud.google.com/gce-topology-block"

Menjadwalkan workload menggunakan PodGroup dengan TAS menggunakan Kueue

Saat menggunakan PodGroup, Anda harus menentukan tiga kolom tambahan untuk setiap Pod dalam PodGroup:

Bergantung pada framework ML yang Anda gunakan, pemimpin PodGroup dapat memerlukan GPU atau tidak. Karena keterbatasan Kueue, kasus ini perlu ditangani secara berbeda. Contoh berikut menunjukkan cara membuat PodGroup yang terdiri dari tiga Pod dengan satu leader dan dua worker.

Kasus 1: Leader juga merupakan worker dan memerlukan GPU

Jika leader adalah salah satu worker dan juga memerlukan GPU, leader dapat memiliki nomor berapa pun dalam PodGroup. Untuk memudahkan, dalam contoh berikut, indeks leader adalah 0:

apiVersion: v1
kind: Pod
metadata:
  generateName: tas-podgroup-leader-
  labels:
    kueue.x-k8s.io/queue-name: tas-user-queue
    kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group"
    kueue.x-k8s.io/pod-group-pod-index: "0"
  annotations:
    kueue.x-k8s.io/pod-group-total-count: "3"
    kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
  containers:
  - name: leader
    image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
    args: ["600s"]
    resources:
      requests:
        nvidia.com/gpu: "1"
      limits:
        nvidia.com/gpu: "1"
  restartPolicy: Never
---
apiVersion: v1
kind: Pod
metadata:
  generateName: tas-podgroup-worker-1-
  labels:
    kueue.x-k8s.io/queue-name: tas-user-queue
    kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group"
    kueue.x-k8s.io/pod-group-pod-index: "1"
  annotations:
    kueue.x-k8s.io/pod-group-total-count: "3"
    kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
  restartPolicy: Never
  containers:
  - name: worker
    image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
    args: ["600s"]
    resources:
      requests:
        nvidia.com/gpu: "1"
      limits:
        nvidia.com/gpu: "1"
---
apiVersion: v1
kind: Pod
metadata:
  generateName: tas-podgroup-worker-2-
  labels:
    kueue.x-k8s.io/queue-name: tas-user-queue
    kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group"
    kueue.x-k8s.io/pod-group-pod-index: "2"
  annotations:
    kueue.x-k8s.io/pod-group-total-count: "3"
    kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
  restartPolicy: Never
  containers:
  - name: worker
    image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
    args: ["600s"]
    resources:
      requests:
        nvidia.com/gpu: "1"
      limits:
        nvidia.com/gpu: "1"

Kasus 2: Leader bukan worker dan tidak memerlukan GPU

Jika leader bukan salah satu worker karena batasan Kueue, leader harus memiliki indeks terakhir di PodGroup, karena cara Kueue membuat PodSet. Jika leader tidak memiliki indeks terakhir dan worker pertama tidak menggunakan indeks pertama, Kueue tidak akan menerapkan penetapan peringkat.

Lihat contoh berikut:

---
apiVersion: v1
kind: Pod
metadata:
  generateName: tas-podgroup-leader-
  labels:
    kueue.x-k8s.io/queue-name: tas-user-queue
    kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group2"
    kueue.x-k8s.io/pod-group-pod-index: "2"
  annotations:
    kueue.x-k8s.io/pod-group-total-count: "3"
    kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
  containers:
  - name: leader
    image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
    args: ["600s"]
    resources:
      requests:
        cpu: "1"
      limits:
        cpu: "1"
  restartPolicy: Never
---
apiVersion: v1
kind: Pod
metadata:
  generateName: tas-podgroup-worker-0-
  labels:
    kueue.x-k8s.io/queue-name: tas-user-queue
    kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group2"
    kueue.x-k8s.io/pod-group-pod-index: "0"
  annotations:
    kueue.x-k8s.io/pod-group-total-count: "3"
    kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
  restartPolicy: Never
  containers:
  - name: worker
    image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
    args: ["600s"]
    resources:
      requests:
        nvidia.com/gpu: "1"
      limits:
        nvidia.com/gpu: "1"
---
apiVersion: v1
kind: Pod
metadata:
  generateName: tas-podgroup-worker-1-
  labels:
    kueue.x-k8s.io/queue-name: tas-user-queue
    kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group2"
    kueue.x-k8s.io/pod-group-pod-index: "1"
  annotations:
    kueue.x-k8s.io/pod-group-total-count: "3"
    kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
  restartPolicy: Never
  containers:
  - name: worker
    image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
    args: ["600s"]
    resources:
      requests:
        nvidia.com/gpu: "1"
      limits:
        nvidia.com/gpu: "1"

Langkah berikutnya