Men-deploy sistem batch menggunakan Kueue

Tutorial ini menunjukkan cara mengoptimalkan resource yang tersedia dengan menjadwalkan Job di Google Kubernetes Engine (GKE) dengan Kueue. Dalam tutorial ini, Anda akan mempelajari cara menggunakan Kueue untuk mengelola dan menjadwalkan tugas batch secara efektif, meningkatkan pemanfaatan resource, dan menyederhanakan pengelolaan workload. Anda menyiapkan cluster bersama untuk dua tim tenant di mana setiap tim memiliki namespace-nya sendiri dan setiap tim membuat Job yang berbagi resource global. Anda juga mengonfigurasi Kueue untuk menjadwalkan Tugas berdasarkan kuota resource yang Anda tentukan.

Tutorial ini ditujukan untuk Arsitek cloud dan Engineer platform yang tertarik untuk menerapkan sistem batch menggunakan GKE. Untuk mempelajari lebih lanjut peran umum dan contoh tugas yang dirujuk dalam konten, lihat Peran dan tugas pengguna GKE umum. Google Cloud

Sebelum membaca halaman ini, pastikan Anda memahami hal-hal berikut:

Latar belakang

Job adalah aplikasi yang berjalan hingga selesai, seperti machine learning, rendering, simulasi, analisis, CI/CD, dan workload sejenis.

Kueue adalah scheduler Job berbasis cloud yang dapat digunakan dengan scheduler Kubernetes default, pengontrol Job, dan autoscaler cluster untuk menyediakan sistem batch end-to-end. Kueue menerapkan pengantrean Job, dengan memutuskan kapan Job harus menunggu dan kapan harus dimulai, berdasarkan kuota dan hierarki untuk berbagi resource antar-tim secara adil.

Kueue memiliki karakteristik berikut:

  • Kueue dioptimalkan untuk arsitektur cloud, di mana resource bersifat heterogen, dapat dipertukarkan, dan skalabel.
  • Kueue menyediakan sekumpulan API untuk mengelola kuota yang elastis dan mengelola pengantrean Job.
  • Kueue tidak mengimplementasikan ulang kemampuan yang ada, seperti penskalaan otomatis, penjadwalan pod, atau pengelolaan siklus proses Job.
  • Kueue memiliki dukungan bawaan untuk API batch/v1.Job Kubernetes.
  • Kueue dapat berintegrasi dengan API Job lainnya.

Kueue mengacu pada tugas yang ditentukan dengan sembarang API sebagai Workload, untuk menghindari kerancuan dengan Kubernetes Job API tertentu.

Membuat ResourceFlavor

ResourceFlavor adalah objek yang merepresentasikan variasi node yang tersedia di cluster Anda dengan mengaitkannya ke label dan taint node. Misalnya, Anda dapat menggunakan ResourceFlavors untuk merepresentasikan VM dengan perbedaan jaminan penyediaan (misalnya spot versus on-demand), arsitektur (misalnya CPU x86 versus ARM), merek, dan model (misalnya GPU Nvidia A100 versus T4).

Dalam tutorial ini, cluster kueue-autopilot memiliki resource yang homogen. Akibatnya, buat satu ResourceFlavor untuk CPU, memori, penyimpanan efemeral, dan GPU tanpa label atau taint.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: default-flavor # This ResourceFlavor will be used for all the resources
Deploy ResourceFlavor:

kubectl apply -f flavors.yaml

Membuat ClusterQueue

ClusterQueue adalah objek dengan cakupan cluster yang mengelola sekumpulan resource seperti CPU, memori, dan GPU. Objek ini mengelola ResourceFlavors, dan membatasi penggunaan, serta menentukan urutan penerimaan workload.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
  name: cluster-queue
spec:
  namespaceSelector: {} # Available to all namespaces
  queueingStrategy: BestEffortFIFO # Default queueing strategy
  resourceGroups:
  - coveredResources: ["cpu", "memory", "nvidia.com/gpu", "ephemeral-storage"]
    flavors:
    - name: "default-flavor"
      resources:
      - name: "cpu"
        nominalQuota: 10
      - name: "memory"
        nominalQuota: 10Gi
      - name: "nvidia.com/gpu"
        nominalQuota: 10
      - name: "ephemeral-storage"
        nominalQuota: 10Gi

Deploy ClusterQueue:

kubectl apply -f cluster-queue.yaml

Urutan pemakaian ditentukan oleh .spec.queueingStrategy, yang memiliki dua konfigurasi:

  • BestEffortFIFO

    • Konfigurasi strategi pengantrean default.
    • Penerimaan workload mengikuti aturan masuk pertama keluar pertama (FIFO), tetapi jika tidak ada cukup kuota untuk menerima workload di kepala antrean, workload berikutnya akan dicoba.
  • StrictFIFO

    • Menjamin semantik FIFO.
    • Workload di kepala antrean dapat memblokir pengantrean hingga workload tersebut dapat diterima.

Di cluster-queue.yaml, Anda akan membuat ClusterQueue baru bernama cluster-queue. ClusterQueue ini mengelola empat resource: cpu, memory, nvidia.com/gpu, dan ephemeral-storage dengan ragam yang dibuat di flavors.yaml. Kuota dipakai oleh permintaan dalam spesifikasi Pod workload.

Setiap ragam mencakup batas penggunaan yang dinyatakan sebagai .spec.resourceGroups[].flavors[].resources[].nominalQuota. Dalam hal ini, ClusterQueue menerima workload jika dan hanya jika:

  • Jumlah permintaan CPU kurang dari atau sama dengan 10
  • Jumlah permintaan memori kurang dari atau sama dengan 10Gi
  • Jumlah permintaan GPU kurang dari atau sama dengan 10
  • Jumlah penyimpanan yang digunakan kurang dari atau sama dengan 10Gi

Membuat LocalQueue

LocalQueue adalah objek dengan namespace yang menerima workload dari pengguna di namespace itu. LocalQueue dari namespace berbeda dapat mengarah ke ClusterQueue yang sama di mana mereka dapat berbagi kuota resource. Dalam hal ini, LocalQueue dari namespace team-a dan team-b mengarah ke ClusterQueue cluster-queue yang sama di .spec.clusterQueue.

apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  namespace: team-a # LocalQueue under team-a namespace
  name: lq-team-a
spec:
  clusterQueue: cluster-queue # Point to the ClusterQueue
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  namespace: team-b # LocalQueue under team-b namespace
  name: lq-team-b
spec:
  clusterQueue: cluster-queue # Point to the ClusterQueue

Setiap tim mengirimkan workload ke LocalQueue di namespace masing-masing, yang kemudian diberi alokasi resource oleh ClusterQueue.

Deploy LocalQueues:

kubectl apply -f local-queue.yaml

Membuat Job dan mengamati workload yang diterima

Di bagian ini, Anda akan membuat Job Kubernetes di namespace team-a. Pengontrol Tugas di Kubernetes membuat satu atau beberapa Pod dan memastikan bahwa Pod tersebut berhasil menjalankan tugas tertentu.

Job di namespace team-a memiliki atribut berikut:

  • Antrean ini mengarah ke LocalQueue lq-team-a.
  • Pod ini meminta resource GPU dengan menyetel kolom nodeSelector ke nvidia-tesla-t4.
  • Job ini terdiri atas tiga Pod yang tidur selama 10 detik secara paralel. Job akan dibersihkan setelah 60 detik menurut nilai yang ditentukan di kolom ttlSecondsAfterFinished.
  • Job ini memerlukan 1.500 miliCPU, memori 1.536 Mi, penyimpanan efemeral 1.536 Mi, dan tiga GPU karena terdapat tiga Pod.
apiVersion: batch/v1
kind: Job
metadata:
  namespace: team-a # Job under team-a namespace
  generateName: sample-job-team-a-
  annotations:
    kueue.x-k8s.io/queue-name: lq-team-a # Point to the LocalQueue
spec:
  ttlSecondsAfterFinished: 60 # Job will be deleted after 60 seconds
  parallelism: 3 # This Job will have 3 replicas running at the same time
  completions: 3 # This Job requires 3 completions
  suspend: true # Set to true to allow Kueue to control the Job when it starts
  template:
    spec:
      nodeSelector:
        cloud.google.com/gke-accelerator: "nvidia-tesla-t4" # Specify the GPU hardware
      containers:
      - name: dummy-job
        image: gcr.io/k8s-staging-perf-tests/sleep:latest
        args: ["10s"] # Sleep for 10 seconds
        resources:
          requests:
            cpu: "500m"
            memory: "512Mi"
            ephemeral-storage: "512Mi"
            nvidia.com/gpu: "1"
          limits:
            cpu: "500m"
            memory: "512Mi"
            ephemeral-storage: "512Mi"
            nvidia.com/gpu: "1"
      restartPolicy: Never

Job juga dibuat di file job-team-b.yaml di mana namespace-nya berada di team-b, dengan permintaan untuk merepresentasikan berbagai tim dengan kebutuhan berbeda-beda.

Untuk mempelajari lebih lanjut, lihat men-deploy workload GPU di Autopilot.

  1. Di terminal baru, amati status ClusterQueue yang diperbarui setiap dua detik:

    watch -n 2 kubectl get clusterqueue cluster-queue -o wide
    
  2. Di terminal baru, amati status node:

    watch -n 2 kubectl get nodes -o wide
    
  3. Di terminal baru, buat Job ke LocalQueue dari namespace team-a dan team-b setiap 10 detik:

    ./create_jobs.sh job-team-a.yaml job-team-b.yaml 10
    
  4. Amati Job yang diantrekan, diterima di ClusterQueue, dan node yang dimunculkan dengan GKE Autopilot.

  5. Dapatkan Job dari namespace team-a:

    kubectl -n team-a get jobs
    

    Output-nya mirip dengan berikut ini:

    NAME                      COMPLETIONS   DURATION   AGE
    sample-job-team-b-t6jnr   3/3           21s        3m27s
    sample-job-team-a-tm7kc   0/3                      2m27s
    sample-job-team-a-vjtnw   3/3           30s        3m50s
    sample-job-team-b-vn6rp   0/3                      40s
    sample-job-team-a-z86h2   0/3                      2m15s
    sample-job-team-b-zfwj8   0/3                      28s
    sample-job-team-a-zjkbj   0/3                      4s
    sample-job-team-a-zzvjg   3/3           83s        4m50s
    
  6. Salin nama Job dari langkah sebelumnya, lalu amati status penerimaan dan peristiwa untuk Job melalui Workloads API:

    kubectl -n team-a describe workload JOB_NAME
    
  7. Saat Job yang tertunda mulai meningkat dari ClusterQueue, akhiri skrip dengan menekan CTRL + C pada skrip yang berjalan.

  8. Setelah semua Job selesai, perhatikan node diturunkan skalanya.