Resource Management #
Requests dan limits adalah dua angka yang punya dampak besar pada stabilitas dan biaya cluster. Terlalu rendah: Pod di-OOMKilled atau di-throttle. Terlalu tinggi: resource terbuang, biaya meningkat, dan Pod sulit di-schedule. Di production dengan banyak tim dan banyak workload, tanpa resource management yang baik, satu workload yang tidak terkontrol bisa mengambil resource dari semua yang lain.
Requests vs Limits: Konsep Dasar #
Resource Requests:
→ Jumlah resource yang DIJAMIN tersedia untuk Pod
→ Digunakan scheduler untuk memilih node
→ Pod tidak akan di-schedule ke node yang tidak punya request yang tersedia
→ "Berapa minimum yang dibutuhkan untuk berjalan normal?"
Resource Limits:
→ Batas maksimum resource yang boleh digunakan Pod
→ CPU: throttled jika melebihi limit (tidak di-kill)
→ Memory: OOMKilled jika melebihi limit
→ "Berapa maksimum yang boleh dipakai?"
Analogi:
Request = kursi yang dipesan di restoran (slot yang dijamin)
Limit = jumlah makanan maksimal yang boleh dipesan
Dampak Konfigurasi yang Salah #
Scenario 1: Request terlalu kecil, limit terlalu besar
requests: cpu=10m, memory=10Mi
limits: cpu=4000m, memory=4Gi
→ Pod bisa di-schedule ke node yang hampir penuh
→ Saat beban tinggi, semua Pod di node berebut CPU
→ Node bisa OOM karena banyak Pod yang sebenarnya butuh lebih dari request-nya
→ Noisy neighbor problem: satu Pod bisa monopoli resource
Scenario 2: Request dan limit sama tinggi
requests: cpu=2000m, memory=2Gi
limits: cpu=2000m, memory=2Gi
→ Scheduling sangat konservatif, banyak resource terbuang
→ Node yang sebenarnya punya sumber daya tidak bisa menerima Pod baru
→ Utilisasi cluster rendah, biaya tinggi
Scenario 3: Tidak ada requests atau limits sama sekali
→ BestEffort QoS: Pod pertama yang di-evict saat node pressure
→ Tidak ada jaminan resource, bisa di-kill kapan saja
→ Berbahaya untuk production workload
Quality of Service (QoS) Classes #
Kubernetes mengkategorikan Pod ke dalam tiga QoS class yang menentukan prioritas eviction:
Guaranteed (paling aman):
requests == limits untuk SEMUA container (CPU dan memory)
→ Pod terakhir yang di-evict saat node pressure
→ Gunakan untuk workload kritikal
Burstable (menengah):
requests < limits, atau hanya salah satu di-set
→ Di-evict setelah BestEffort tapi sebelum Guaranteed
→ Cocok untuk sebagian besar workload
BestEffort (paling berisiko):
Tidak ada requests dan limits sama sekali
→ Pod pertama yang di-evict saat node pressure
→ Jangan gunakan di production
# Guaranteed QoS: requests == limits
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "500m" # sama dengan requests
memory: "512Mi" # sama dengan requests
# Burstable QoS: requests < limits (paling umum)
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "1000m" # boleh burst 10x saat idle
memory: "512Mi" # memory limit lebih konservatif
Cara Menentukan Nilai yang Tepat #
Jangan menebak — gunakan data dari observasi:
# Lihat resource usage Pod saat ini
kubectl top pods -n production
# Lihat usage dengan detail container
kubectl top pods -n production --containers
# Dari Prometheus: rata-rata CPU usage dalam 24 jam terakhir
# p95 memory usage dalam 24 jam terakhir
# CPU usage rata-rata selama 24 jam (untuk request)
avg_over_time(
rate(container_cpu_usage_seconds_total{
namespace="production", container="api"
}[5m])[24h:]
)
# CPU usage p95 selama 24 jam (untuk limit)
quantile_over_time(0.95,
rate(container_cpu_usage_seconds_total{
namespace="production", container="api"
}[5m])[24h:]
)
# Memory usage p99 (untuk limit — lebih konservatif)
quantile_over_time(0.99,
container_memory_working_set_bytes{
namespace="production", container="api"
}[24h:]
)
Rumus praktis untuk setting awal:
CPU request = rata-rata usage sehari-hari × 1.2 (buffer 20%)
CPU limit = peak usage × 1.5 (atau tidak set untuk CPU)
Memory request = rata-rata usage × 1.3
Memory limit = p99 usage × 1.5 (atau max yang pernah tercatat)
Untuk CPU: pertimbangkan tidak set limit (hanya throttle, tidak kill)
Untuk memory: selalu set limit (OOMKill lebih predictable dari OOM node)
LimitRange: Default Per Namespace #
LimitRange menetapkan nilai default dan batas untuk resource di satu namespace — berguna agar tidak ada Pod tanpa resource spec:
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: production
spec:
limits:
# Default untuk Container
- type: Container
default: # limit default jika tidak di-set
cpu: "500m"
memory: "512Mi"
defaultRequest: # request default jika tidak di-set
cpu: "100m"
memory: "128Mi"
max: # batas maksimum yang bisa di-set
cpu: "4000m"
memory: "4Gi"
min: # batas minimum
cpu: "10m"
memory: "16Mi"
# Batas untuk PersistentVolumeClaim
- type: PersistentVolumeClaim
max:
storage: "100Gi"
min:
storage: "1Gi"
ResourceQuota: Batas Per Namespace #
ResourceQuota membatasi total resource yang bisa dikonsumsi seluruh Pod di satu namespace:
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
# Batas resource
requests.cpu: "20" # total CPU request di namespace ini
requests.memory: "40Gi"
limits.cpu: "40"
limits.memory: "80Gi"
# Batas jumlah objek
pods: "100"
services: "20"
persistentvolumeclaims: "20"
secrets: "50"
configmaps: "50"
# Batas storage
requests.storage: "500Gi"
# Batas berdasarkan StorageClass
ssd.storageclass.storage.k8s.io/requests.storage: "200Gi"
# Lihat quota usage saat ini
kubectl describe resourcequota production-quota -n production
# Output:
# Resource Used Hard
# -------- --- ----
# limits.cpu 3500m 40
# limits.memory 7Gi 80Gi
# pods 28 100
# requests.cpu 1200m 20
# requests.memory 2.5Gi 40Gi
Vertical Pod Autoscaler (VPA) #
VPA secara otomatis menyesuaikan requests dan limits berdasarkan observasi penggunaan aktual:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: api-vpa
namespace: production
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: api
updatePolicy:
updateMode: "Off" # Off: hanya rekomendasi, tidak auto-apply
# Initial: apply saat Pod dibuat
# Auto: evict dan recreate dengan nilai baru
resourcePolicy:
containerPolicies:
- containerName: api
minAllowed:
cpu: "50m"
memory: "64Mi"
maxAllowed:
cpu: "2000m"
memory: "2Gi"
# Lihat rekomendasi VPA
kubectl describe vpa api-vpa -n production
# Output:
# Recommendation:
# Container Recommendations:
# Container Name: api
# Lower Bound:
# Cpu: 50m
# Memory: 131072k
# Target:
# Cpu: 120m ← rekomendasi untuk request
# Memory: 256Mi
# Upper Bound:
# Cpu: 500m
# Memory: 512Mi
Ringkasan #
- Request = garantied, limit = maksimum — scheduler menggunakan request untuk memilih node; limit menentukan batas sebelum throttle (CPU) atau OOMKill (memory).
- Guaranteed QoS untuk workload kritikal — set request == limit; Pod ini paling terakhir di-evict saat node pressure.
- Tentukan nilai dari data, bukan dugaan — gunakan
kubectl topdan Prometheus untuk lihat usage aktual; request = rata-rata + buffer, limit = peak + buffer.- Memory limit selalu di-set, CPU limit opsional — OOMKill lebih predictable dari node OOM; CPU throttle lebih baik dari kill untuk sebagian besar service.
- LimitRange untuk default namespace — Pod tanpa resource spec otomatis mendapat nilai default; mencegah BestEffort QoS yang berbahaya di production.
- ResourceQuota untuk isolasi antar tim — tim A tidak bisa mengambil resource tak terbatas yang berdampak ke tim B; quota memberikan fairness dan predictability.
← Sebelumnya: Anti-Pattern Ecosystem & Tooling Berikutnya: Autoscaling →