Memahami Node Affinity, Taints, dan Tolerations di OpenShift
Salah satu kebingungan paling umum saat mengelola cluster Kubernetes dan OpenShift adalah memahami mengapa sebuah Pod berstatus Pending padahal worker node terlihat banyak dan kapasitas cluster tampak mencukupi.
Sering kali kita melihat pesan scheduler seperti berikut:
0/32 nodes are available:
1 Insufficient cpu,
16 node(s) didn't match Pod's node affinity/selector,
12 node(s) had untolerated taint {node-role.kubernetes.io/infra: },
3 node(s) had untolerated taint {node-role.kubernetes.io/master: }
Melihat pesan tersebut, reaksi pertama biasanya adalah langsung mengecek grafik utilisasi CPU dan memory. Namun, proses scheduling di OpenShift tidak hanya didasarkan pada ketersediaan resource fisik, melainkan serangkaian aturan eliminasi bertingkat.
Cara Kerja Scheduler: Proses Eliminasi
Kubernetes Scheduler tidak bertanya:
“Node mana yang pemakaian CPU-nya paling rendah saat ini?”
Scheduler bekerja dengan pertanyaan:
“Dari seluruh node yang ada, node mana saja yang lolos seluruh kriteria penempatan Pod ini?”
Pod Spec
|
v
Kubernetes Scheduler
|
+---- [1] Filter: Label & nodeSelector
|
+---- [2] Filter: Node Affinity (required)
|
+---- [3] Filter: Taints & Tolerations
|
+---- [4] Filter: Resource Requests (Allocatable)
|
+---- [5] Score: Affinity (preferred) & Spread
|
v
Pilihan Node Terbaik -> Pod Scheduled!
Jika tidak ada satu pun node yang lolos dari seluruh rantai filter tersebut, Pod tidak akan dijadwalkan dan tertahan di status Pending.
1. nodeSelector: Filter Paling Sederhana
nodeSelector adalah mekanisme paling dasar untuk membatasi Pod hanya boleh berjalan di node dengan label tertentu:
spec:
nodeSelector:
node-role.kubernetes.io/worker: ""
Prinsip nodeSelector bersifat mutlak (hard requirement). Jika sebuah node tidak memiliki label persis seperti yang diminta, node tersebut langsung dicoret dari daftar kandidat.
Pod (nodeSelector: worker)
|
+---> Node 1 [role: worker] --> Lolos (✓)
+---> Node 2 [role: worker] --> Lolos (✓)
+---> Node 3 [role: infra] --> Dieliminasi (✗)
2. Node Affinity: Fleksibilitas Logika Penempatan
Node Affinity memperluas kapabilitas nodeSelector dengan operator ekspresi (In, NotIn, Exists, DoesNotExist, Gt, Lt) dan pemisahan antara kebutuhan wajib vs preferensi.
A. Wajib (Hard Requirement)
requiredDuringSchedulingIgnoredDuringExecution
Kriteria ini wajib dipenuhi saat Pod dijadwalkan. Jika tidak ada node yang cocok, Pod gagal dijadwalkan.
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- ap-southeast-1a
- ap-southeast-1b
B. Preferensi (Soft Requirement)
preferredDuringSchedulingIgnoredDuringExecution
Scheduler berusaha menempatkan Pod di node yang cocok. Namun jika tidak ada node yang memenuhi preferensi tersebut, Pod tetap dijadwalkan di worker node lain yang tersedia.
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
Arti IgnoredDuringExecution: Aturan affinity hanya dievaluasi saat Pod dijadwalkan. Jika label pada node berubah di kemudian hari saat Pod sudah berjalan, Pod tidak akan di-evict secara otomatis.
3. Taints: Pembatasan dari Sisi Node
Jika nodeSelector dan nodeAffinity merupakan permintaan yang diajukan oleh Pod, maka Taint adalah benteng penolakan yang dipasang di sisi Node.
Taint berfungsi menolak Pod agar tidak sembarangan masuk ke node tertentu kecuali Pod tersebut memiliki izin khusus.
Format taint: key=value:effect
# Contoh memberi taint pada infra node
oc adm taint nodes infra-node-01 dedicated=infra:NoSchedule
Tiga efek taint yang umum:
NoSchedule: Pod baru tanpa toleration tidak akan dijadwalkan di node ini. Pod yang sudah terlanjur jalan tidak terpengaruh.PreferNoSchedule: Scheduler berusaha menghindari penempatan di node ini, kecuali tidak ada node lain.NoExecute: Pod yang tidak punya toleration tidak hanya ditolak saat scheduling, tetapi jika sudah berjalan di node tersebut akan langsung di-evict (dikeluarkan).
4. Tolerations: Kunci Masuk, Bukan Titik Tujuan
Toleration dikonfigurasi di dalam spec Pod sebagai deklarasi bahwa Pod tersebut “tahan” atau diizinkan berada di node yang memiliki taint tertentu:
spec:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "infra"
effect: "NoSchedule"
Miskonsepsi Kritis: Toleration ≠ Penempatan Otomatis
Banyak engineer mengira ketika Pod diberi toleration: dedicated=infra, maka Pod tersebut otomatis akan berjalan di node infra. Ini keliru.
Taint + Toleration
└─► HANYA memberi izin masuk (menghilangkan penolakan).
Node Affinity / nodeSelector
└─► MENENTUKAN preferensi atau paksaan tujuan penempatan.
Jika Anda ingin Pod workload monitoring hanya berjalan di infra node dan tidak tercecer di worker biasa, Anda harus menggabungkan keduanya:
spec:
nodeSelector:
node-role.kubernetes.io/infra: ""
tolerations:
- key: "dedicated"
operator: "Equal"
value: "infra"
effect: "NoSchedule"
5. Miskonsepsi “Insufficient CPU”: Request vs Real Usage
Saat scheduler mengeluarkan pesan:
1 Insufficient cpu
Hal ini bukan berarti CPU fisik node sedang terpakai 100% pada saat itu (top atau metrics monitoring mungkin hanya menunjukkan 25% CPU usage).
Scheduler bekerja berdasarkan Allocatable Resources vs Total Pod Requests, bukan utilisasi real-time.
Kapasitas Node:
Total Allocatable CPU : 8 Core (8000m)
Sudah di-request Pods : 7 Core (7000m)
Sisa untuk Scheduling : 1 Core (1000m)
Pod Baru Meminta:
resources.requests.cpu : 2 Core (2000m)
Hasil Scheduler:
1000m < 2000m -> Insufficient cpu! (Node Ditolak)
Walaupun Pod-Pod yang ada saat ini sedang idle dan CPU aktual node hanya terpakai 0.8 Core, scheduler tetap menolak karena menjamin resource request yang telah dijanjikan.
6. Studi Kasus Eliminasi: Mengapa Pod Tertahan di 32 Node?
Mari kita bedah simulasi klaster OpenShift dengan 32 node:
Total Node di Klaster: 32 Node
├── 3 Master Node (Tainted: node-role.kubernetes.io/master:NoSchedule)
├── 3 Infra Node (Tainted: node-role.kubernetes.io/infra:NoSchedule)
└── 26 Worker Node
Sebuah aplikasi database dideploy dengan konfigurasi:
nodeAffinity: Hanya boleh di rackzone-b(tersedia 10 node worker).requests.cpu: 4 Core.
Scheduler menjalankan proses eliminasi:
[32 Total Nodes]
│
├─► Evaluasi Taints (Master & Infra)
│ └── 6 Node tersingkir (tidak ada toleration)
│
[26 Worker Nodes Tersisa]
│
├─► Evaluasi Node Affinity (zone-b)
│ └── 16 Node bukan zone-b tersingkir
│
[10 Worker Nodes di zone-b]
│
├─► Evaluasi Resource Requests (Sisa Allocatable CPU < 4 Core)
│ └── 10 Node tersingkir karena kapasitas request sudah padat
│
[0 Node Tersedia]
│
▼
Pod Status: Pending
Pesan: 0/32 nodes are available: 10 Insufficient cpu, 16 Didn't match affinity, 6 Untolerated taint.
Pesan error yang tampak rumit di atas sebenarnya adalah rangkuman akurat dari proses eliminasi logis tersebut.
7. Langkah Investigasi Praktis Saat Pod Pending
Jika Anda menemukan Pod berstatus Pending, lakukan investigasi secara berurutan:
Langkah 1: Periksa Event Scheduler pada Pod
oc describe pod <pod-name> -n <namespace>
Scroll ke bagian paling bawah di baris Events:. Catat alasan penolakan node (apakah affinity, taint, atau resource).
Langkah 2: Audit Constraint pada Spec Pod
oc get pod <pod-name> -n <namespace> -o yaml
Periksa 4 blok penentu ini:
nodeSelectoraffinitytolerationsresources.requests
Langkah 3: Periksa Label dan Taint pada Node Target
# Cek daftar label node
oc get nodes --show-labels
# Cek taint pada node tertentu
oc get node <node-name> -o jsonpath='{.spec.taints}' | jq .
Langkah 4: Periksa Alokasi Resource Node
oc describe node <node-name>
Lihat tabel Allocated resources di bagian bawah:
Resource Requests Limits
-------- -------- ------
cpu 7100m (91%) 12000m (150%)
memory 14Gi (45%) 28Gi (90%)
Jika nilai persentase request sudah mendekati 100%, node tersebut tidak akan menerima Pod baru yang meminta request lebih besar dari sisa kapasitas.
Ringkasan Perbandingan & Logika Kerja Scheduler
| Fitur | Didefinisikan Di | Fungsi Utama | Karakteristik |
|---|---|---|---|
| nodeSelector | Pod Spec | Menyaring node berdasarkan kecocokan label persis | Kaku, wajib (hard) |
| Node Affinity | Pod Spec | Menyaring atau memprioritaskan node dengan logika ekspresi | Mendukung required & preferred |
| Taint | Node Spec | Menolak Pod agar tidak dijadwalkan di node tersebut | Proteksi dari sisi node |
| Toleration | Pod Spec | Memberikan izin Pod untuk masuk ke node ber-taint | Pasif (izin masuk, bukan paksaan rute) |
| Resource Requests | Pod Spec | Menjamin ketersediaan kapasitas komputasi minimal | Berbasis reservasi, bukan pemakaian aktual |
Dengan memahami bahwa penempatan Pod adalah proses eliminasi berlapis, Anda dapat dengan cepat mengisolasi akar penyebab Pod Pending dan merancang arsitektur penempatan workload yang stabil di OpenShift.