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 top dan 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 →

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