Kelas QoS

Kelas QoS Guaranteed, Burstable, dan BestEffort beserta urutan eviksi saat tekanan sumber daya.

Daftar isi

Quality of Service (QoS) adalah kelas yang diberikan Kubernetes kepada setiap Pod secara implisit berdasarkan request dan limit sumber dayanya. Kelas tersebut menentukan urutan Pod yang diusir ketika Node kekurangan memori, yaitu peristiwa yang disebut eviction, dan dalam jalur ini disebut eviksi. Topik ini membahas tiga kelas QoS, aturan penentuannya pada manifest, serta urutan eviksi saat tekanan memori. Logika penentuan kelas disimulasikan dengan Python sehingga urutan eviksi setiap Pod dapat diamati tanpa kluster.

Tiga kelas QoS#

Kubernetes menggolongkan setiap Pod ke salah satu dari tiga kelas QoS, yaitu Guaranteed, Burstable, dan BestEffort. Nama kelas ditulis apa adanya tanpa penerjemahan karena nilainya dibaca langsung dari status Pod. Kelas ditetapkan otomatis oleh API server berdasarkan kombinasi request dan limit seluruh container dalam Pod, sehingga tidak ada kunci manifest untuk memilih kelas secara langsung.

KelasSyarat penentuanUrutan saat eviksi
Guaranteedsetiap container menetapkan request dan limit untuk CPU serta memori dengan nilai yang samapaling akhir
Burstableada request atau limit, tetapi syarat Guaranteed tidak terpenuhidi antara keduanya
BestEfforttidak ada request dan tidak ada limitpaling awal

Ketiga kelas tersebut membentuk skala jaminan yang berbeda. Jaminan kelas QoS bersumber dari request, bukan dari limit. Kubelet mereservasi memori sebesar request Pod, sehingga Pod dengan request yang cukup besar jarang tertekan saat Node sibuk. Limit memberi ruang untuk berkembang, tetapi ruang tersebut tidak dijamin dan dapat ditarik kembali saat Node kekurangan memori.

Penentuan kelas pada manifest#

Aturan penentuan kelas berlaku terhadap semua container dalam Pod, termasuk init container pada kelas Guaranteed. Pod dikategorikan Guaranteed apabila setiap container menetapkan request dan limit untuk CPU dan memori dengan nilai yang sama persis. Pod dikategorikan BestEffort apabila tidak ada satu container pun yang menetapkan request atau limit. Seluruh kombinasi lainnya, misalnya limit tanpa request atau request yang berbeda dari limit, menghasilkan Burstable.

Berkas berikut memuat tiga Pod dengan kelas QoS yang berbeda, yaitu cache-1 yang berkelas Guaranteed, api-1 yang berkelas Burstable karena limitnya lebih besar daripada requestnya, dan demo-1 yang berkelas BestEffort karena tidak menetapkan sumber daya apa pun. Urutan dokumen pada berkas itu mengikuti urutan penjelasan, dari jaminan tertinggi hingga terendah. Ketiga Pod tersebut dapat diterapkan bersamaan pada satu namespace untuk membandingkan perilakunya secara langsung.

yaml pod-qos.yaml
apiVersion: v1
kind: Pod
metadata:
  name: cache-1
spec:
  containers:
    - name: cache
      image: redis:7.2
      resources:
        requests:
          cpu: 500m
          memory: 128Mi
        limits:
          cpu: 500m
          memory: 128Mi
---
apiVersion: v1
kind: Pod
metadata:
  name: api-1
spec:
  containers:
    - name: api
      image: nginx:1.27
      resources:
        requests:
          cpu: 250m
          memory: 128Mi
        limits:
          cpu: 500m
          memory: 256Mi
---
apiVersion: v1
kind: Pod
metadata:
  name: demo-1
spec:
  containers:
    - name: demo
      image: busybox:1.36
      command: ["sleep", "3600"]

Kesalahan yang sering terjadi adalah menetapkan request dan limit CPU yang sama tetapi melupakan memori, sehingga Pod yang dianggap Guaranteed ternyata Burstable. Kelas Pod yang sudah berjalan dapat diverifikasi melalui kolom status Pod, sebagaimana perintah berikut. Pemeriksaan ini menjadi langkah penutup setelah manifest diterapkan, sehingga anggapan tentang kelas Pod selalu berlandaskan nilai yang sebenarnya.

bash
# tidak-dijalankan
# menampilkan nama pod beserta kelas QoS-nya
kubectl get pod -o custom-columns='NAMA:.metadata.name,QOS:.status.qosClass'
text Contoh keluaran
NAMA   QOS
cache-1 Guaranteed
api-1  Burstable
demo-1 BestEffort

Simulasi penentuan kelas#

Logika penentuan kelas cukup pendek sehingga mudah disimulasikan. Fungsi pada skrip berikut menerima daftar container beserta resources-nya, kemudian menerapkan aturan BestEffort, Guaranteed, dan Burstable secara berurutan. Fungsi yang sama kemudian digunakan untuk mengurutkan Pod sesuai kelasnya, meniru urutan eviksi kubelet saat Node kekurangan memori. Penentuan kelas hanya membaca struktur data sumber daya, sehingga tidak ada ketergantungan pada runtime Kubernetes.

python simulasi-qos.py
"""Simulasi penentuan kelas QoS dan urutan eviksi pod."""


def qos_class(containers):
    """Menentukan kelas QoS dari resources seluruh container dalam pod."""
    ada_batasan = False
    semuanya_guaranteed = True
    for c in containers:
        req = c.get("requests", {})
        lim = c.get("limits", {})
        if req or lim:
            ada_batasan = True
        # Guaranteed: setiap container menetapkan request dan limit untuk CPU
        # serta memori, dengan nilai request sama persis dengan limitnya.
        lengkap = {"cpu", "memory"} <= set(req) and req == lim
        if not lengkap:
            semuanya_guaranteed = False
    if not ada_batasan:
        return "BestEffort"
    if semuanya_guaranteed:
        return "Guaranteed"
    return "Burstable"


pods = [
    {"nama": "cache-1", "containers": [
        {"requests": {"cpu": "500m", "memory": "128Mi"},
         "limits": {"cpu": "500m", "memory": "128Mi"}},
    ]},
    {"nama": "api-1", "containers": [
        {"requests": {"cpu": "250m", "memory": "128Mi"},
         "limits": {"cpu": "500m", "memory": "256Mi"}},
    ]},
    {"nama": "batch-1", "containers": [
        {"limits": {"cpu": "1", "memory": "512Mi"}},
    ]},
    {"nama": "demo-1", "containers": [
        {},
    ]},
]

print("Penentuan kelas QoS:")
for pod in pods:
    kelas = qos_class(pod["containers"])
    print(f"  {pod['nama']:<10} {kelas}")

# --- urutan eviksi saat node kekurangan memori ---
# kubelet mengusir pod BestEffort lebih dahulu, diikuti Burstable, sedangkan
# Guaranteed paling akhir. Antara pod berkelas sama, urutannya deterministik.
URUTAN_EVIKSI = {"BestEffort": 0, "Burstable": 1, "Guaranteed": 2}
print()
print("Urutan eviksi saat tekanan memori:")
berurutan = sorted(pods, key=lambda p: (URUTAN_EVIKSI[qos_class(p["containers"])],
                                        p["nama"]))
for i, pod in enumerate(berurutan, start=1):
    kelas = qos_class(pod["containers"])
    print(f"  {i}. {pod['nama']} ({kelas})")
text Keluaran
Penentuan kelas QoS:
  cache-1    Guaranteed
  api-1      Burstable
  batch-1    Burstable
  demo-1     BestEffort

Urutan eviksi saat tekanan memori:
  1. demo-1 (BestEffort)
  2. api-1 (Burstable)
  3. batch-1 (Burstable)
  4. cache-1 (Guaranteed)

Keluaran tersebut menegaskan perbedaan antara keempat Pod. cache-1 memperoleh Guaranteed karena request dan limitnya identik pada CPU maupun memori. api-1 dan batch-1 sama-sama Burstable, yang pertama karena request berbeda dari limit dan yang kedua karena request sama sekali tidak ditetapkan. demo-1 memperoleh BestEffort dan menempati urutan eviksi pertama, sedangkan cache-1 menempati urutan terakhir. Urutan yang sama dapat dijadikan acuan saat kapasitas Node diperkirakan. Pod terlemah digugurkan lebih dahulu sebelum Pod berjaminan tersentuh.

Urutan eviksi saat tekanan memori#

Tekanan memori terdeteksi melalui sinyal eviksi yang diamati kubelet, misalnya ambang memori tersedia di bawah nilai tertentu. Sinyal tersebut diperiksa secara berkala, dan eviksi dimulai apabila sinyal bertahan lebih lama dari masa tenggangnya. Pada kondisi terburuk, kernel juga dapat menjalankan OOM killer di tingkat Node, yaitu mengakhiri proses secara langsung apabila eviksi berjalan lebih lambat daripada pertumbuhan konsumsi memori.

Apabila penggunaan memori Node mendekati batasnya, kubelet menjalankan eviksi untuk mengembalikan tekanan ke tingkat yang aman. Kubelet menilai Pod yang berjalan berdasarkan apakah konsumsinya melebihi requestnya, lalu mengusiri Pod dengan jaminan terendah terlebih dahulu. BestEffort menjadi korban pertama karena tidak membawa jaminan apa pun, diikuti Burstable yang konsumsinya melampaui request, sedangkan Guaranteed paling akhir.

Eviksi dilakukan satu Pod per putaran, diikuti pemeriksaan ulang tekanan memori sebelum keputusan berikutnya. Kubelet mengirim sinyal penghentian dengan masa tenggang sebelum proses dipaksa berhenti, sehingga aplikasi berkesempatan menutup koneksi dan menyimpan keadaannya. Pola ini menjadikan eviksi proses yang teratur, bukan pemberhentian serentak seluruh Pod pada Node.

Burstable yang konsumsinya masih di bawah requestnya diperlakukan lebih baik daripada BestEffort, sebab Pod Burstable tersebut tidak melampaui jaminan yang dibawanya. Karena itu, request yang jujur terhadap kebutuhan aplikasi menjadi benteng pertama Pod saat Node tertekan. Kelas Guaranteed memberikan perlindungan paling kuat bagi komponen yang gangguannya langsung berdampak pada pengguna.

Ringkasan#

  • Kelas QoS ditetapkan secara implisit dari resources setiap container, tanpa kunci manifest untuk memilihnya.
  • Guaranteed menuntut request sama dengan limit untuk CPU dan memori pada setiap container, BestEffort menuntut ketiadaan request dan limit, sedangkan kombinasi lainnya menghasilkan Burstable.
  • Saat Node kekurangan memori, kubelet mengusiri BestEffort terlebih dahulu, diikuti Burstable yang melampaui request, sedangkan Guaranteed terakhir.
  • Kelas QoS dapat diverifikasi melalui kolom status Pod menggunakan kubectl.

Referensi#