Scheduler #
Scheduler melakukan satu pekerjaan: memutuskan Pod mana yang berjalan di node mana. Kedengarannya sederhana, tapi keputusan ini mempengaruhi utilisasi resource, ketersediaan aplikasi, dan performa cluster secara keseluruhan. Di balik sebuah keputusan scheduling ada puluhan faktor yang dievaluasi secara bersamaan — dan memahami cara kerja scheduler membantu kamu merancang deployment yang efisien dan mendiagnosis masalah Pod yang tidak kunjung terjadwal.
Posisi Scheduler dalam Alur Deployment #
Scheduler tidak bekerja sendiri. Ia adalah bagian dari pipeline yang lebih besar:
Pod dibuat (oleh Deployment Controller, misalnya)
Status: Pending, nodeName: "" ← belum punya node assignment
│
▼
Scheduler mendeteksi Pod tanpa nodeName via watch
│
▼
Scheduler mengevaluasi semua node
│
▼
Scheduler menulis nodeName ke Pod spec via API Server
Status: Pending, nodeName: "worker-2"
│
▼
Kubelet di worker-2 mendeteksi Pod yang assigned ke nodenya
│
▼
Kubelet menjalankan container → Status: Running
Scheduler tidak menjalankan container. Ia hanya menulis satu field — spec.nodeName — ke Pod object di API Server. Kubelet yang kemudian mengambil alih.
Fase 1: Filtering #
Filtering adalah tahap eliminasi. Scheduler melewatkan setiap node melalui serangkaian predicate filter, dan hanya node yang lolos semua filter yang dipertimbangkan lebih lanjut.
Filter yang dijalankan Scheduler (sebagian):
NodeUnschedulable
→ Eliminasi node yang di-cordon (SchedulingDisabled)
PodFitsResources
→ Eliminasi node yang tidak punya cukup CPU dan memory
untuk memenuhi resource request Pod
NodeAffinity
→ Eliminasi node yang tidak cocok dengan nodeSelector
atau nodeAffinity rules di Pod spec
TaintToleration
→ Eliminasi node yang punya taint yang tidak di-tolerate Pod
PodTopologySpread
→ Eliminasi node yang melanggar topology spread constraint
(misalnya: Pod tidak boleh semua di zone yang sama)
VolumeBinding
→ Eliminasi node yang tidak bisa menyediakan volume
yang dibutuhkan Pod (PersistentVolumeClaim)
Jika setelah filtering tidak ada node yang lolos, Pod tetap di status Pending. Ini adalah situasi yang perlu didiagnosis:
# Lihat mengapa Pod tidak terjadwal
kubectl describe pod <pod-name>
# Perhatikan bagian Events, biasanya ada pesan seperti:
# "0/3 nodes are available: 3 Insufficient memory."
# "0/3 nodes are available: 3 node(s) had untolerated taint"
Fase 2: Scoring #
Setelah filtering, biasanya masih ada beberapa node yang lolos. Scoring memilih yang terbaik di antara mereka.
Setiap node diberi skor dari 0–100 berdasarkan beberapa kriteria. Node dengan skor tertinggi yang dipilih. Jika ada seri (skor sama), Scheduler memilih secara acak di antara node dengan skor tertinggi.
Beberapa fungsi scoring (berjalan secara paralel):
LeastAllocated
→ Node dengan resource paling banyak tersisa dapat skor lebih tinggi
→ Mendorong penyebaran Pod ke banyak node (tidak menumpuk di satu node)
BalancedResourceAllocation
→ Node yang rasio CPU:memory-nya lebih seimbang dapat skor lebih tinggi
→ Mencegah situasi di mana CPU habis tapi memory masih banyak (atau sebaliknya)
ImageLocality
→ Node yang sudah punya container image yang dibutuhkan dapat skor lebih tinggi
→ Menghindari delay image pull
InterPodAffinity
→ Node yang sudah menjalankan Pod dengan label yang cocok dengan affinity rule
dapat skor lebih tinggi (atau lebih rendah untuk anti-affinity)
Mempengaruhi Keputusan Scheduling #
Kubernetes menyediakan beberapa cara untuk mengarahkan Scheduler dalam membuat keputusan:
Node Selector #
Cara paling sederhana. Pod hanya akan dijadwalkan ke node yang punya label tertentu:
spec:
nodeSelector:
disktype: ssd # hanya node berlabel disktype=ssd
kubernetes.io/arch: amd64
# Tambahkan label ke node
kubectl label node worker-2 disktype=ssd
Node Affinity #
Lebih ekspresif dari nodeSelector. Mendukung operator lebih dari sekadar kesetaraan:
spec:
affinity:
nodeAffinity:
# WAJIB: Pod tidak akan dijadwalkan jika tidak ada node yang cocok
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- ap-southeast-1a
- ap-southeast-1b
# PREFERENSI: dijadwalkan ke sini jika bisa, tapi tidak wajib
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
IgnoredDuringExecution di nama rule berarti: jika node sudah tidak cocok setelah Pod berjalan (misalnya label dihapus), Pod tidak otomatis dipindahkan.
Pod Affinity dan Anti-Affinity #
Berbeda dari node affinity yang berbasis label node, Pod affinity dan anti-affinity menggunakan keberadaan Pod lain sebagai pertimbangan:
spec:
affinity:
# Jadwalkan Pod ini DEKAT dengan Pod berlabel app=cache
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: cache
topologyKey: kubernetes.io/hostname # "dekat" = node yang sama
# Jadwalkan Pod ini JAUH dari Pod berlabel app=api (replica lain)
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: api
topologyKey: kubernetes.io/hostname # tidak boleh di node yang sama
Anti-affinity sangat berguna untuk memastikan replica Pod tersebar ke node yang berbeda, sehingga kegagalan satu node tidak menghapus semua replica sekaligus.
Taint dan Toleration #
Taint adalah “penolakan” di sisi node — node dengan taint tidak akan menerima Pod yang tidak secara eksplisit men-tolerasi taint tersebut.
# Tambahkan taint ke node
kubectl taint nodes worker-3 gpu=true:NoSchedule
# Efek: tidak ada Pod yang dijadwalkan ke worker-3,
# kecuali Pod yang punya toleration untuk taint ini
# Pod yang bisa dijadwalkan ke node bertaint gpu=true:NoSchedule
spec:
tolerations:
- key: "gpu"
operator: "Equal"
value: "true"
effect: "NoSchedule"
Taint mendukung tiga efek berbeda:
NoSchedule → Pod baru tidak dijadwalkan ke node ini
Pod yang sudah berjalan tidak diusir
PreferNoSchedule → Scheduler berusaha menghindari node ini,
tapi masih menjadwalkan ke sini jika tidak ada pilihan lain
NoExecute → Pod baru tidak dijadwalkan,
Pod yang sudah berjalan langsung diusir (evicted)
Topology Spread Constraint #
Mekanisme lebih modern untuk mendistribusikan Pod secara merata:
spec:
topologySpreadConstraints:
- maxSkew: 1 # selisih maksimum antar zone
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule # atau ScheduleAnyway
labelSelector:
matchLabels:
app: api
Konfigurasi di atas memastikan selisih jumlah Pod berlabel app=api antar availability zone tidak lebih dari 1. Ini menggantikan pola anti-affinity yang lebih kompleks untuk kasus distribusi merata.
Mengapa Pod Tidak Terjadwal? #
Ini adalah masalah yang paling sering ditemui. Alur diagnosisnya:
Pod stuck di Pending
│
▼
kubectl describe pod <pod-name>
Lihat bagian "Events" — biasanya ada pesan diagnostik
Kemungkinan penyebab:
"Insufficient cpu" atau "Insufficient memory"
→ Resource request terlalu besar untuk node yang ada
→ Solusi: kurangi request, tambah node, atau perbesar node
"node(s) had untolerated taint"
→ Node punya taint yang Pod tidak toleransi
→ Solusi: tambahkan toleration ke Pod atau hapus taint dari node
"node(s) didn't match Pod's node affinity"
→ Tidak ada node yang cocok dengan affinity rule
→ Solusi: periksa label node dan affinity rule
"0/3 nodes are available: 3 node(s) were unschedulable"
→ Semua node di-cordon
→ Solusi: kubectl uncordon <node-name>
"pod has unbound immediate PersistentVolumeClaims"
→ PVC tidak bisa di-bind ke PV yang tersedia
→ Solusi: periksa StorageClass dan ketersediaan PV
Ringkasan #
- Scheduler hanya menulis nodeName — ia tidak menjalankan container; hanya memilih node dan kubelet yang mengeksekusi.
- Filtering eliminasi, scoring memilih — semua node yang tidak memenuhi syarat dieliminasi di fase filtering; node terbaik dipilih di fase scoring.
- NodeSelector untuk kebutuhan sederhana — filter node berdasarkan label; gunakan nodeAffinity untuk ekspresi yang lebih kompleks.
- Anti-affinity untuk ketersediaan tinggi — pastikan replica Pod tersebar ke node yang berbeda agar kegagalan satu node tidak menghapus semua replica.
- Taint/toleration untuk node khusus — taint “menolak” Pod yang tidak punya toleration; berguna untuk node GPU, node khusus tim, atau node yang sedang maintenance.
kubectl describe poduntuk diagnosis — bagian Events di output describe selalu menjelaskan mengapa Pod tidak terjadwal.