Scheduler Workflow #

Artikel Architecture sebelumnya membahas Scheduler dari sudut pandang komponen — apa yang ia lakukan dan mekanismenya. Artikel ini membahas dari sudut pandang operasional: apa yang sebenarnya terjadi dari saat Pod dibuat hingga ia berjalan di node, apa yang bisa salah di setiap tahap, dan bagaimana mendiagnosis masalah scheduling di lingkungan nyata.

Alur Lengkap dari Manifest ke Pod Berjalan #

Memahami setiap langkah dalam pipeline ini membantu menjawab pertanyaan “kenapa Pod ini belum Running?”:

kubectl apply -f deployment.yaml
        │
        ▼ (1)
API Server menerima request
  → Autentikasi, otorisasi, admission control
  → Simpan Deployment ke Etcd
        │
        ▼ (2)
Deployment Controller mendeteksi Deployment baru
  → Hitung: butuh 3 Pod, ada 0
  → Buat 3 Pod object (tanpa nodeName) → simpan ke Etcd
        │
        ▼ (3)
Scheduler mendeteksi 3 Pod baru (status: Pending, nodeName: "")
  → Masukkan ke scheduling queue
        │
        ▼ (4)
Untuk setiap Pod, Scheduler menjalankan:
  a. Filtering → eliminasi node yang tidak memenuhi syarat
  b. Scoring   → beri skor node yang lolos
  c. Binding   → tulis nodeName ke Pod object → simpan ke Etcd
        │
        ▼ (5)
Kubelet di node terpilih mendeteksi Pod yang assigned ke nodenya
  → Pull container image (jika belum ada)
  → Buat container via container runtime
  → Jalankan init container (jika ada)
  → Jalankan container utama
  → Lapor status Running ke API Server
        │
        ▼ (6)
Pod status: Running
Readiness probe mulai berjalan
Saat probe sukses: Pod ditambahkan ke Endpoints Service
        │
        ▼ (7)
Traffic mulai diterima Pod

Dari kubectl apply hingga Pod siap menerima traffic, ada tujuh tahap — dan masalah bisa terjadi di mana saja.


Scheduling Queue #

Scheduler tidak memproses semua Pod secara bersamaan. Pod yang menunggu dijadwalkan masuk ke dalam antrian yang memiliki prioritas:

Scheduling Queue terdiri dari tiga antrian:

1. activeQ (antrian utama)
   → Pod yang siap dijadwalkan sekarang
   → Diproses berdasarkan priority dan waktu tunggu

2. backoffQ (antrian retry)
   → Pod yang baru saja gagal dijadwalkan
   → Menunggu backoff period sebelum di-retry

3. unschedulableQ (antrian Pod yang tidak bisa dijadwalkan)
   → Pod yang sudah coba dijadwalkan tapi tidak ada node yang cocok
   → Di-move ke activeQ secara periodik atau saat ada perubahan cluster

Saat node baru bergabung atau resource di cluster berubah (Pod dihapus, resource limit diubah), Scheduler memindahkan Pod dari unschedulableQ ke activeQ untuk di-coba lagi.


Filtering Pipeline #

Filtering mengeliminasi node yang tidak bisa menjalankan Pod. Semua filter berjalan secara paralel untuk efisiensi:

Daftar filter yang umum:

NodeUnschedulable
  → Elminasi node dengan spec.unschedulable: true (di-cordon)

PodFitsResources
  → Eliminasi node yang allocatable CPU/memory tidak cukup
    untuk resource request Pod

NodeAffinity
  → Eliminasi node yang tidak cocok dengan nodeAffinity rules

TaintToleration
  → Eliminasi node yang punya taint yang tidak di-tolerate Pod

PodTopologySpread
  → Eliminasi node yang melanggar topology spread constraint

VolumeBinding
  → Eliminasi node yang tidak bisa menyediakan PVC yang dibutuhkan

PodAntiAffinity
  → Eliminasi node yang melanggar required anti-affinity rules

Jika hasil filtering adalah nol node, Pod masuk ke unschedulableQ dengan pesan yang bisa dilihat di events:

kubectl describe pod <pod-name>

# Events:
# Warning  FailedScheduling  0/3 nodes are available:
#   1 Insufficient cpu,
#   2 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }

Scoring Pipeline #

Node yang lolos filtering diberi skor. Skor total adalah weighted sum dari semua scoring function:

Scoring functions yang aktif secara default:

LeastAllocated (bobot: 1)
  → Lebih tinggi untuk node dengan resource lebih banyak tersisa
  → Mendorong penyebaran Pod ke banyak node

BalancedResourceAllocation (bobot: 1)
  → Lebih tinggi untuk node yang rasio CPU:memory-nya lebih seimbang
  → Mencegah fragmentasi resource

ImageLocality (bobot: 1)
  → Lebih tinggi untuk node yang sudah punya container image
  → Menghindari waktu pull image

InterPodAffinityAndAntiAffinity (bobot: 2)
  → Bobot lebih tinggi karena preferensi pengguna lebih penting
  → Memenuhi preferred affinity/anti-affinity rules

NodeAffinity (bobot: 2)
  → Memenuhi preferred nodeAffinity rules

Binding #

Setelah node dipilih, Scheduler membuat Binding object — ini adalah operasi yang menulis spec.nodeName ke Pod:

Scheduler membuat Binding:
  {
    "apiVersion": "v1",
    "kind": "Binding",
    "metadata": { "name": "api-pod-xyz" },
    "target": { "name": "worker-2" }
  }

API Server menerima Binding:
  → Update Pod: spec.nodeName = "worker-2"
  → Simpan ke Etcd

Kubelet di worker-2 mendeteksi Pod-nya melalui watch
  → Mulai proses menjalankan container

Waktu yang Diperlukan #

Dari pengalaman operasional, berikut estimasi waktu di setiap tahap untuk kondisi normal:

kubectl apply → Pod terbuat di Etcd:       < 1 detik
Pod terbuat → Scheduler assign node:       < 1 detik
Scheduler assign → Kubelet mulai:          1-2 detik
Image sudah ada di node → Container up:   2-5 detik
Image belum ada → Container up:           10-60 detik (tergantung ukuran image)
Container up → Readiness probe sukses:    tergantung initialDelaySeconds

Total dari kubectl apply ke Pod Ready:    ~15-90 detik (kondisi normal)

Mendiagnosis Masalah Scheduling #

Pod Stuck di Pending #

# Langkah 1: lihat event Pod
kubectl describe pod <pod-name>
# Perhatikan bagian "Events" — biasanya ada pesan yang jelas

# Langkah 2: cek resource node yang tersedia
kubectl describe nodes | grep -A 5 "Allocated resources"

# Langkah 3: bandingkan request Pod dengan kapasitas node
kubectl get pod <pod-name> -o yaml | grep -A 10 resources

# Langkah 4: cek taint di node
kubectl describe nodes | grep Taints

Pola Pesan Error dan Artinya #

"0/3 nodes are available: 3 Insufficient cpu"
  → Tidak ada node dengan CPU tersisa yang cukup
  → Solusi: tambah node, kurangi resource request, atau scale down Pod lain

"0/3 nodes are available: 3 node(s) had untolerated taint"
  → Semua node punya taint yang Pod tidak toleransi
  → Solusi: tambah toleration ke Pod atau hapus taint dari node

"0/3 nodes are available: 3 node(s) didn't match Pod's node affinity/selector"
  → Tidak ada node dengan label yang sesuai
  → Solusi: periksa label node, tambah label, atau longgarkan affinity rule

"0/3 nodes are available: 3 pod has unbound immediate PersistentVolumeClaims"
  → PVC tidak bisa di-bind ke PV yang tersedia
  → Solusi: periksa StorageClass, kapasitas PV, atau access mode

"0/3 nodes are available: 3 Too many pods"
  → Semua node sudah penuh (default: 110 Pod per node)
  → Solusi: tambah node

Pod Dijadwalkan ke Node yang Salah #

# Lihat di node mana Pod berjalan
kubectl get pod <pod-name> -o wide

# Jika tidak sesuai ekspektasi, periksa:
# 1. Apakah nodeSelector sudah benar?
kubectl get pod <pod-name> -o yaml | grep nodeSelector -A 5

# 2. Apakah label di node sesuai?
kubectl get nodes --show-labels | grep <label-yang-diharapkan>

# 3. Apakah ada affinity rule yang tidak terpenuhi (preferred, bukan required)?
# Scheduler memilih node terbaik yang tersedia — mungkin tidak ideal tapi valid

Pod Priority dan Preemption #

Kubernetes mendukung prioritas Pod — Pod dengan prioritas tinggi bisa “mengusir” Pod dengan prioritas rendah untuk mendapatkan resource:

# Definisikan PriorityClass
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000          # semakin tinggi semakin prioritas
globalDefault: false
description: "Untuk workload kritikal"

---
# Gunakan di Pod
spec:
  priorityClassName: high-priority
Preemption scenario:

Cluster penuh (tidak ada resource tersisa)
Pod baru dengan priority tinggi masuk ke queue

Scheduler cari node yang bisa menjalankan Pod baru
  jika Pod dengan priority rendah di-evict

Jika ditemukan: evict Pod priority rendah, jalankan Pod priority tinggi
Jika tidak: Pod tetap di Pending

Ringkasan #

  • Tujuh tahap dari apply ke Running — API Server → Deployment Controller → Scheduling Queue → Filter → Score → Binding → Kubelet; masalah bisa terjadi di mana saja.
  • Scheduling queue tiga tingkatactiveQ untuk diproses, backoffQ untuk retry, unschedulableQ untuk yang tidak bisa dijadwalkan; Pod di-move antar antrian berdasarkan kondisi cluster.
  • kubectl describe pod adalah alat utama diagnosis — bagian Events selalu menjelaskan mengapa Pod tidak terjadwal dengan pesan yang sangat spesifik.
  • Waktu total 15-90 detik — sebagian besar waktu dihabiskan untuk image pull; gunakan image yang lebih kecil atau pre-pull image di node untuk mempercepat.
  • Pod Priority untuk workload kritikal — PriorityClass memungkinkan Pod penting mengusir Pod dengan prioritas lebih rendah saat resource terbatas.
  • Perubahan cluster memicu retry — Pod di unschedulableQ otomatis di-retry saat ada node baru bergabung atau Pod dihapus; tidak perlu intervensi manual.

← Sebelumnya: Job & CronJob   Berikutnya: Resource Request & Limit →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact