Request vs Limit
| Request | Limit | |
|---|---|---|
| Arti | Jaminan minimum | Batas maksimum |
| Dipakai untuk | Keputusan penjadwalan | Penegakan saat runtime |
| Bila terlampaui (CPU) | Boleh memakai lebih bila node senggang | Di-throttle — proses dipaksa berhenti sesaat |
| Bila terlampaui (memori) | Boleh memakai lebih | OOMKilled — kontainer dibunuh |
resources:
requests:
cpu: 100m # 100 milicore = 0,1 inti
memory: 128Mi
limits:
memory: 512Mi
# CPU limit sengaja tidak disetel — alasannya di bawah
CPU adalah sumber daya yang bisa dikompres. Ketika kontainer menyentuh limit CPU, kernel Linux (CFS) menghentikannya sampai periode kuota berikutnya — meskipun node masih punya CPU yang menganggur. Efeknya terasa langsung pada latensi p99: permintaan yang seharusnya selesai dalam 50 ms tiba-tiba butuh 150 ms karena prosesnya dijeda paksa.
Praktik yang banyak dianut sekarang: selalu setel memory limit (memori tidak bisa dikompres — kehabisan berarti OOM), tetapi hanya setel CPU request tanpa limit. Request sudah cukup menjamin pembagian yang adil saat node sibuk, sekaligus membiarkan aplikasi memanfaatkan kapasitas menganggur.
Tiga Kelas Quality of Service
| Kelas | Syarat | Urutan diusir saat node kehabisan memori |
|---|---|---|
| Guaranteed | request = limit untuk semua sumber daya di semua kontainer | Terakhir — paling terlindungi |
| Burstable | Ada request, tetapi tidak sama dengan limit | Kedua |
| BestEffort | Tidak ada request maupun limit sama sekali | Pertama — paling dulu dikorbankan |
kubectl get pod nama-pod -o jsonpath='{.status.qosClass}'
Pod tanpa request sama sekali masuk kelas BestEffort dan akan menjadi yang pertama dibunuh ketika node kehabisan memori. Lebih buruk lagi, penjadwal tidak punya informasi untuk menempatkannya dengan bijak, sehingga bisa menumpuk beban di node yang sudah padat. Selalu setel setidaknya requests.
OOMKilled: Mendiagnosis dan Memperbaiki
kubectl describe pod nama-pod # Yang perlu dicari: # Last State: Terminated # Reason: OOMKilled # Exit Code: 137 kubectl get events --sort-by=.lastTimestamp | grep OOM kubectl top pods --sort-by=memory
OOMKilled berulang biasanya berarti salah satu dari dua hal: ada kebocoran memori di aplikasi, atau runtime tidak menyadari batas kontainer. Yang kedua sangat umum:
- Java: JVM modern menghormati cgroup, tetapi pastikan memakai
-XX:MaxRAMPercentage=75alih-alih-Xmxtetap. - Node.js: setel
--max-old-space-sizesekitar 75% dari memory limit. - Go: setel
GOMEMLIMITagar garbage collector tahu batasnya.
Tanpa itu, runtime mengira ia punya seluruh memori node dan baru menjalankan pembersihan ketika sudah terlambat.
Menetapkan Batas di Tingkat Namespace
apiVersion: v1
kind: ResourceQuota
metadata:
name: kuota-tim-a
namespace: tim-a
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.memory: 80Gi
persistentvolumeclaims: "10"
count/deployments.apps: "30"
---
apiVersion: v1
kind: LimitRange
metadata:
name: batas-bawaan
namespace: tim-a
spec:
limits:
- type: Container
default: # limit bila tidak disebutkan
memory: 512Mi
defaultRequest: # request bila tidak disebutkan
cpu: 100m
memory: 128Mi
max:
memory: 4Gi
ResourceQuota membatasi total pemakaian sebuah namespace. LimitRange menetapkan nilai bawaan per kontainer sehingga pod tanpa resources tetap mendapat nilai yang wajar. Perhatikan bahwa bila ResourceQuota mengatur requests.cpu, maka setiap pod wajib menyebutkan request CPU atau akan ditolak — LimitRange menyelamatkan Anda dari keharusan menulisnya di setiap manifest.
Menemukan Angka yang Tepat
# Pemakaian nyata saat ini kubectl top pods -n produksi --sort-by=memory kubectl top nodes # Vertical Pod Autoscaler dalam mode rekomendasi saja kubectl get vpa layanan-pesanan -o yaml
Alur yang praktis: mulai dengan perkiraan kasar, jalankan di bawah beban nyata selama beberapa hari, lalu setel requests mendekati pemakaian rata-rata (persentil 50–70) dan memory limit di sekitar puncak ditambah margin 30–50%. Request yang terlalu besar membuang kapasitas kluster; yang terlalu kecil membuat pod dijadwalkan ke node yang sebenarnya sudah penuh.