Skip to main content
BlogDevOps

Gang Scheduling Kubernetes 1.37 Beta: Yang Siap, Yang Belum

Kubernetes 1.37 menaikkan Workload dan PodGroup ke Beta. Pembacaan dekat atas release post dan docs: gate, contoh Job, perubahan nama yang breaking, dan posisi Kueue serta Volcano.

Matthews Wong

Software Engineer

Oktober 202612 menit baca
Gang Scheduling Kubernetes 1.37 Beta: Yang Siap, Yang Belum

Ringkasan Utama

Kubernetes v1.37 menaikkan API Workload dan PodGroup, beserta gang scheduling bawaan, ke Beta di bawah feature gate GenericWorkload, yang mati secara default di kube-apiserver, kube-controller-manager dan kube-scheduler. Fiturnya menempatkan semua Pod dalam satu grup atau tidak sama sekali. Antrean, kuota dan fair sharing antar tim tetap tugas Kueue atau Volcano.

Bayangkan sebuah Job distributed training yang butuh delapan Pod sekaligus. Scheduler default menempatkan Pod satu per satu, jadi enam bisa di-bind, dua terakhir gagal, dan enam akselerator mahal tertahan oleh job yang tidak bisa mulai. Itulah deadlock yang hendak dicegah gang scheduling, dan selama ini jawaban praktisnya adalah memasang sistem kedua.

Kubernetes v1.37 membawa jawaban in-tree itu ke Beta. Saya membaca release post workload-aware scheduling v1.37, dokumentasi gang scheduling yang baru, post v1.36 sebagai dasarnya, serta halaman overview Kueue dan Volcano. Saya tidak menjalankan cluster v1.37, jadi tidak ada benchmark di sini, hanya apa yang dinyatakan sumber, dengan celahnya saya tandai.

Apa yang naik ke Beta di 1.37, dan apa yang masih Alpha

Release post menyebut API inti Workload dan PodGroup, yang mengaktifkan gang scheduling, bersama workload-aware preemption dan ResourceClaim DRA yang dibagi satu PodGroup, naik ke Beta. Post itu juga menyebut fitur Beta maupun Alpha sama-sama mati secara default dan harus diaktifkan manual. Dokumentasi gang scheduling sepakat: Beta sejak v1.37, mati secara default. Pembagian ini penting karena jalur Beta hanya satu saklar, sedangkan tiap fitur Alpha punya gate sendiri.

FiturStatus di 1.37Gate dan tempat mengaktifkannya
API Workload dan PodGroup, gang scheduling, workload-aware preemptionBeta, scheduling.k8s.io/v1beta1GenericWorkload di kube-apiserver, kube-controller-manager dan kube-scheduler
ResourceClaim DRA yang dibagi satu PodGroupBetaDRAWorkloadResourceClaims di kube-apiserver, kube-controller-manager, kube-scheduler dan kubelet
Topology-aware schedulingAlphaTopologyAwareWorkloadScheduling di kube-apiserver dan kube-scheduler
Hierarki CompositePodGroupAlpha, scheduling.k8s.io/v1alpha3CompositePodGroup di kube-apiserver, kube-controller-manager dan kube-scheduler, ditambah TopologyAwareWorkloadScheduling di controller manager
Integrasi Job controllerAlphaWorkloadWithJob di kube-apiserver dan kube-controller-manager
Field preemptionPolicy pada PodGroupAlphaPodGroupPreemptionPolicy di kube-apiserver dan kube-scheduler

Ada dua detail yang mudah terlewat. Gate WorkloadAwarePreemption yang terpisah di 1.36 digabung ke GenericWorkload, jadi satu gate kini membawa gang scheduling sekaligus workload-aware preemption. Lalu, mengaktifkan CompositePodGroup di kube-controller-manager juga mewajibkan TopologyAwareWorkloadScheduling di sana, sehingga fitur hierarki tidak bisa dinyalakan sendirian.

Model objek: Workload adalah template, PodGroup adalah runtime

Sejak 1.36 objek Workload adalah template statis dan PodGroup menyimpan state runtime. Post 1.36 memberi alasannya: update status bisa di-shard per replica, dan scheduler bisa membaca PodGroup langsung tanpa meng-watch Workload. Controller menulis Workload, membuat PodGroup dari template-nya, lalu mengisi spec.schedulingGroup.podGroupName di setiap Pod. Sketsa di bawah adalah gang datar berisi empat worker, saya susun dari nama field di post 1.37 dengan composite parent dibuang. Anggap ini bahan untuk dicoba, bukan manifest yang disalin dari release notes.

# kind-was.yaml: a throwaway cluster to try the Beta gate.
# Use a node image built for v1.37; the gate does not exist before it.
# I have not run this file. The gate and API group names are from the
# v1.37 release post; the kind keys are kind's standard v1alpha4 config.
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
  GenericWorkload: true
runtimeConfig:
  "scheduling.k8s.io/v1beta1": "true"
---
# The template: a Workload names the group and its gang policy.
apiVersion: scheduling.k8s.io/v1beta1
kind: Workload
metadata:
  name: training-workload
  namespace: some-ns
spec:
  podGroupTemplates:
    - name: workers
      schedulingPolicy:
        gang:
          # Schedulable only if 4 Pods can be placed together.
          minCount: 4
---
# The runtime object. Create it BEFORE the Pods: the scheduler keeps the
# Pods in PreEnqueue until this exists and 4 Pods have been created.
apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: training-workers-pg
  namespace: some-ns
spec:
  workloadRef:
    workloadName: training-workload
    templateName: workers
  schedulingPolicy:
    gang:
      minCount: 4
---
# Each Pod links to the PodGroup, not to the Workload.
apiVersion: v1
kind: Pod
metadata:
  name: worker-0
  namespace: some-ns
  labels:
    app: gang-test
spec:
  schedulingGroup:
    podGroupName: training-workers-pg
  containers:
    - name: worker
      image: busybox:1.36
      command: ["sleep", "3600"]
      resources:
        requests:
          cpu: "2"

Buat PodGroup sebelum Pod-nya. Dokumentasi menyebut scheduler menahan Pod di fase PreEnqueue sampai PodGroup yang dirujuk ada dan minimal minCount Pod sudah dibuat, jadi PodGroup yang hilang membuat seluruh gang tertahan di luar antrean aktif, bukan gagal dengan pesan yang jelas.

Bagaimana scheduler menahan dan menempatkan gang

Setelah kuorum terpenuhi, scheduler menjalankan PodGroup scheduling cycle dan mengambil satu keputusan atomik. Plugin GangScheduling mengimplementasikan extension point PlacementFeasible, dipanggil untuk tiap Pod yang dievaluasi, yang membandingkan jumlah Pod yang berhasil ditempatkan, termasuk yang dijadwalkan di siklus sebelumnya, dengan minCount. Jika placement ditemukan minimal sebanyak minCount, Pod di-bind. Jika tidak, tak satu pun di-bind dan semuanya menunggu di unschedulable queue supaya workload lain bisa memakai kapasitas sementara itu.

1.37 juga mengubah apa yang diantrekan. Dulu setiap Pod anggota diantrekan sendiri-sendiri, bahkan di dalam PodGroup. Sekarang hanya objek PodGroup tingkat atas yang diantrekan, sehingga semua Pod-nya berbagi perilaku antrean yang sama, dan post itu menyebutnya fondasi untuk strategi antrean PodGroup yang lebih canggih nanti.

Dokumentasi memuat catatan yang layak dibaca dua kali. Scheduler tidak pernah mengizinkan Pod kurang dari minCount pada penempatan awal, tetapi jumlah yang berjalan bisa turun di bawahnya kalau Pod dihapus atau di-evict, atau kalau minCount dinaikkan. Setelah itu scheduler hanya menempatkan Pod tambahan bila jumlah yang sudah terjadwal ditambah Pod baru yang feasible mencapai minCount. Gang scheduling adalah jaminan untuk penempatan pertama, bukan invarian sepanjang umur workload.

Job dengan gang policy eksplisit

Bagian yang paling dulu akan disentuh kebanyakan tim adalah Job API. Job v1.37 punya field .spec.scheduling yang tersusun dari empat bagian: schedulingPolicy, schedulingConstraints, disruptionMode, dan resourceClaims. Ini contoh dari release post, dengan container yang bisa dijalankan saya isi di bagian yang dipotong post-nya.

# From the v1.37 release post. gang {} omits minCount, which then
# defaults to parallelism (8). Needs the Alpha WorkloadWithJob gate on
# kube-apiserver and kube-controller-manager.
apiVersion: batch/v1
kind: Job
metadata:
  name: distributed-training-job
spec:
  parallelism: 8
  completions: 8
  scheduling:
    schedulingPolicy:
      gang: {}
    schedulingConstraints:
      topology:
      - key: topology.kubernetes.io/zone
    disruptionMode:
      all: {}
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: trainer
        image: busybox:1.36
        command: ["sleep", "3600"]

Jika minCount pada gang dihilangkan, nilainya default ke parallelism, yaitu 8 di sini. Tanpa .spec.scheduling, atau tanpa schedulingPolicy di dalamnya, yang terpilih adalah policy basic yang berperilaku seperti scheduling Job hari ini. Untuk tiap Job, controller mengompilasi konfigurasi itu menjadi Workload dan PodGroup milik Job dan mengisi schedulingGroup di setiap Pod yang dibuatnya. Setelah dibuat, .spec.scheduling bersifat immutable, kecuali minCount pada gang yang boleh diubah, sehingga gang yang sedang berjalan bisa di-resize.

Integrasi ini Alpha, di balik WorkloadWithJob, dan hanya mencakup Job biasa. Untuk JobSet dan LeaderWorkerSet, post itu menunjuk CompositePodGroup, dan mencantumkan integrasi lebih dalam dengan orchestrator hierarkis seperti JobSet sebagai fokus yang direncanakan, bukan yang sudah dirilis.

Hierarki dan topologi multi-level, masih Alpha

CompositePodGroup memperluas model dari satu grup datar menjadi pohon. Workload mendapat spec.compositePodGroupTemplates, masing-masing membawa gang policy dengan minGroupCount, dan menyarangkan podGroupTemplates atau composite template lain di bawahnya. Scheduler memperlakukan seluruh pohon sebagai satu unit penjadwalan. Contoh multi-level di release post mengunci root ke satu availability zone dan tiap grup anak ke satu rack di dalam zone itu.

# From the v1.37 release post: a two-level hierarchy, zone for the whole
# workload, rack for each child group. Alpha: needs the CompositePodGroup and
# TopologyAwareWorkloadScheduling gates, and scheduling.k8s.io/v1alpha3.
apiVersion: scheduling.k8s.io/v1beta1
kind: Workload
metadata:
  name: multi-level-tas-workload
  namespace: job-ns
spec:
  compositePodGroupTemplates:
  - name: root
    schedulingPolicy:
      gang:
        minGroupCount: 2          # both child groups, or nothing
    schedulingConstraints:
      topology:
      - key: topology.kubernetes.io/zone
    podGroupTemplates:
    - name: workers
      schedulingPolicy:
        gang:
          minCount: 8
      schedulingConstraints:
        topology:
        - key: topology.example.com/rack
    - name: driver
      schedulingPolicy:
        gang:
          minCount: 1
      schedulingConstraints:
        topology:
        - key: topology.example.com/rack

Evaluasinya rekursif dan all-or-nothing: kalau root tidak bisa memenuhi policy-nya, tidak ada Pod dalam hierarki yang di-bind. Constraint topologi diselesaikan dari atas ke bawah, sehingga domain kandidat grup anak berada di dalam placement yang diasumsikan untuk induknya. Preemption ikut diperluas: disruptionMode single membuat grup anak bisa di-preempt sendiri-sendiri, sedangkan all meng-evict semua Pod di seluruh hierarki sekaligus.

Satu kejanggalan di contoh post itu sendiri: CompositePodGroup runtime memakai scheduling.k8s.io/v1alpha3 sementara PodGroup daun memakai v1beta1, dan root menghubungkan anak-anaknya lewat parentCompositePodGroupName. Roadmap post menempatkan topology-aware scheduling dan CompositePodGroup di Beta pada v1.38, yang berupa rencana, bukan komitmen.

Di mana Kueue dan Volcano masih dibutuhkan

Gang scheduling bawaan menjawab satu pertanyaan: bisakah grup Pod yang sudah dibuat ini ditempatkan semuanya? Kueue menjawab pertanyaan yang lebih awal. Overview-nya menyebut Kueue memutuskan kapan sebuah job harus menunggu, kapan di-admit, artinya Pod boleh dibuat, dan kapan di-preempt. Pembacaan saya, keduanya bekerja di momen berbeda: Kueue menjaga pembuatan Pod terhadap kuota, dan gang scheduling menjaga proses bind setelah Pod ada.

AspekBawaan 1.37KueueVolcano
Keputusan yang diambilApakah grup Pod yang sudah dibuat bisa ditempatkan semuanyaKapan job menunggu, di-admit atau di-preemptBatch scheduling lewat sekumpulan policy
Kuota dan keadilan antar tenantBukan bagian dari API di post yang saya bacaKuota, Cohort, Fair Sharing, resource flavor fungibilityKuota queue, peminjaman, reclaim dan preemption antar queue
Perilaku gangminCount per PodGroup di Beta, minGroupCount per CompositePodGroup di AlphaAll-or-nothing with ready Pods, implementasi berbasis timeoutGang scheduling tercantum sebagai policy: semua task job mulai bersamaan
TopologiAlpha, multi-level lewat CompositePodGroupTopology-Aware Scheduling tercantum sebagai fiturNetwork topology-aware dan task-topology scheduling
Jenis jobJob di Alpha; ada library builder untuk controller lainBatch Job, JobSet, LeaderWorkerSet, MPIJob, RayJob dan Pod group tercantum StableVolcanoJob, dengan PyTorch, TensorFlow, Spark dan Ray di antara framework-nya
Sinyal kematanganBeta, mati secara defaultStatus Stable dicantumkan per integrasiProyek CNCF incubating

Post Kubernetes jelas soal arah. Di bagian what is next, post itu mencantumkan upaya membuat Kueue sepenuhnya sadar fitur workload-aware scheduling dalam waktu dekat, dan jangka panjang Kueue memakai API bawaan sebagai mesin untuk gang scheduling dan penempatan topology-aware. Itu terbaca sebagai konvergensi, tetapi itu niat yang dinyatakan untuk v1.38 dan seterusnya, bukan fitur yang sudah rilis, dan saya tidak menemukan pernyataan kompatibilitas untuk Kueue yang ada hari ini.

Aturan keputusan saya dari sumber-sumber ini: kalau Anda butuh kuota antar tim, fair sharing atau admission control, Anda tetap butuh Kueue atau Volcano, dan gang scheduling bawaan tidak menggantikannya. Kalau Anda menjalankan Job training satu tim di cluster yang Anda kendalikan dan hanya deadlock yang menyakitkan, jalur Beta bawaan layak dicoba di cluster uji sekarang.

Kalau Anda sudah menjalankan Kueue atau Volcano untuk perilaku gang, jangan ubah apa pun dulu. Dua mekanisme gang yang menangani Pod yang sama adalah konflik yang tidak ingin saya temukan di production, dan pekerjaan penyelarasan Kueue masih ada di roadmap v1.38.

Di mana ia patah: trade-off yang akan saya catat lebih dulu

Fitur Beta yang mati secara default punya biaya yang tidak disebut di headline. Berikut yang didukung sumber.

  • Tiga komponen control plane harus sepakat. Gate Beta dipasang di kube-apiserver, kube-controller-manager dan kube-scheduler, dan manifest harus memakai scheduling.k8s.io/v1beta1. Saya tidak meneliti apakah layanan Kubernetes terkelola membuka feature gate control plane.
  • Placement tidak dijamin untuk grup yang rumit. Post 1.36 menyatakan bahwa untuk grup heterogen, dan grup dengan dependensi antar-Pod seperti affinity, menemukan placement yang valid tidak dijamin walau ada. Saya tidak menemukan apa pun di post 1.37 yang mencabut batasan ini.
  • Gang scheduling bukan admission control. Gang yang tidak muat pindah ke unschedulable queue dan menunggu. Tidak ada di API ini yang menjatah kapasitas antar tim.
  • Versi Alpha itu patah. v1alpha2 diganti total oleh v1alpha3 dengan perubahan breaking di sekitar disruptionMode, yang nilainya diganti nama: PodGroup menjadi all dan Pod menjadi single.
  • Gate DRA yang mati kini tidak membuat apa-apa. Dengan DRAWorkloadResourceClaims mati, Pod yang claim-nya cocok dengan claim PodGroup-nya tidak mendapat ResourceClaim sama sekali di 1.37, padahal 1.36 membuat satu per Pod. Itu mencegah banjir claim, tetapi saya perkirakan Pod yang bergantung pada claim akan tetap Pending.

Kesalahan termurah adalah menerapkan manifest 1.36 ke cluster 1.37. Versi API lama sudah hilang dan nilai disruptionMode kini berupa objek, jadi saya perkirakan API server menolak manifest itu, bukan mengonversinya. Tulis ulang manifest alpha sebelum upgrade, bukan sesudahnya.

Perubahan nama itu dalam praktik, memakai bentuk field yang tampil di post 1.36 dan 1.37:

# Wrong: a 1.36 alpha manifest applied to a 1.37 cluster.
# v1alpha2 was replaced, and the old disruptionMode value was renamed.
apiVersion: scheduling.k8s.io/v1alpha2
kind: PodGroup
spec:
  disruptionMode: PodGroup

# Right: the 1.37 beta shape. all replaces PodGroup, single replaces Pod.
apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
spec:
  disruptionMode:
    all: {}

Yang dikerjakan hari Senin

Daftar pendek yang biayanya satu cluster uji dan satu sore:

  1. Pisahkan job Anda jadi dua tumpuk: yang tidak berguna kecuali semua Pod berjalan, seperti distributed training, dan yang tahan terhadap progres parsial. Hanya tumpukan pertama yang kandidat.
  2. Bangun cluster uji dengan node image v1.37, GenericWorkload dan API group v1beta1 aktif, lalu minta kapasitas lebih besar dari yang tersedia.
  3. Pastikan perilaku yang dijanjikan docs: setiap Pod tetap Pending tanpa node, dan PodGroup, bukan Pod, yang membawa status.
  4. Periksa status gate di control plane yang benar-benar Anda jalankan sebelum merencanakan apa pun, dan catat cluster mana yang tidak bisa mengaktifkannya.
  5. Biarkan Kueue dan Volcano tetap terpasang. Baca ulang post workload-aware scheduling Kubernetes v1.38 saat terbit, karena GA untuk Workload dan PodGroup serta penyelarasan Kueue sama-sama ada di roadmap yang dinyatakannya.

Me-resize gang yang berjalan cukup satu patch pada Job, karena minCount pada gang adalah satu-satunya field scheduling yang bisa diubah:

# 1. Is the beta API group served at all?
kubectl get --raw /apis/scheduling.k8s.io/v1beta1 | head -c 300
kubectl api-resources --api-group=scheduling.k8s.io

# 2. Gate state: the API server exports each gate as a metric.
kubectl get --raw /metrics | grep 'kubernetes_feature_enabled{name="GenericWorkload"'

# 3. The experiment: request more CPU than the cluster has, then look.
kubectl apply -f gang-test.yaml
kubectl get pods -l app=gang-test -o wide   # expect Pending, NODE <none>
kubectl get podgroups -n some-ns
kubectl describe podgroup training-workers-pg -n some-ns

# 4. Resize a running Job gang. minCount is the one mutable scheduling field.
kubectl patch job distributed-training-job --type merge \
  -p '{"spec":{"scheduling":{"schedulingPolicy":{"gang":{"minCount":6}}}}}'

Gang scheduling bawaan di v1.37 itu nyata tetapi sempit: Beta yang mati secara default dan menjamin penempatan all-or-nothing untuk sekelompok Pod, bukan pengganti sistem yang menentukan siapa dapat kapasitas dan kapan. Uji di tempat deadlock benar-benar menyakitkan, tulis ulang manifest Alpha sebelum upgrade, dan pertahankan lapisan antrean Anda sampai proyek Kubernetes menyatakan sebaliknya.

FAQ

Pertanyaan Umum

Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.

Apakah gang scheduling Kubernetes sudah stabil di 1.37?

Belum. API Workload dan PodGroup, beserta gang scheduling, naik ke Beta di v1.37 dan mati secara default. Anda mengaktifkannya dengan feature gate GenericWorkload di kube-apiserver, kube-controller-manager dan kube-scheduler, lalu memakai API group scheduling.k8s.io/v1beta1. Release post mencantumkan GA untuk API ini sebagai rencana v1.38.

Bagaimana cara mengaktifkan gang scheduling di Kubernetes 1.37?

Aktifkan feature gate GenericWorkload untuk API server, controller manager dan scheduler, dan pastikan scheduling.k8s.io/v1beta1 tersedia. Lalu buat PodGroup dengan gang policy dan minCount, dan arahkan tiap Pod ke sana lewat spec.schedulingGroup.podGroupName. Untuk Job biasa ada juga gate Alpha WorkloadWithJob dan field .spec.scheduling.

Apa fungsi minCount pada PodGroup Kubernetes?

minCount adalah jumlah minimum Pod yang harus bisa ditempatkan bersama. Scheduler menahan grup sampai sedikitnya sebanyak itu Pod ada, lalu hanya mem-bind Pod jika menemukan placement untuk minCount di antaranya, selain itu tidak ada yang di-bind. Di 1.37 minCount bisa diubah, jadi controller dapat me-resize gang, tetapi jumlah yang berjalan masih bisa turun di bawahnya setelah eviction.

Apakah gang scheduling bawaan menggantikan Kueue atau Volcano?

Tidak menurut sumber yang saya baca. Gang scheduling bawaan mengambil keputusan penempatan all-or-nothing untuk Pod yang sudah dibuat. Kueue menambah kuota, fair sharing dan admission, sedangkan Volcano menawarkan queue dan kumpulan policy batch yang lebih luas. Post Kubernetes menyatakan ingin Kueue sepenuhnya sadar workload-aware scheduling, dan nanti memakainya sebagai mesin, yang merupakan item roadmap.

Apakah manifest PodGroup Kubernetes 1.36 saya jalan di 1.37?

Tidak, tidak tanpa perubahan. API v1alpha2 diganti, API inti pindah ke v1beta1, dan nilai disruptionMode diganti nama sehingga PodGroup menjadi all dan Pod menjadi single. Tulis ulang manifest dan uji di cluster v1.37 dengan gate aktif sebelum meng-upgrade apa pun yang penting.