ReplicaSet #
Di dalam kluster Kubernetes yang melayani jutaan request pengguna, kita tidak boleh membiarkan aplikasi kita berjalan tanpa adanya pengawasan. Jika sebuah kontainer mati akibat lonjakan trafik atau server host fisiknya mendadak hang, sistem harus segera mendeteksi kegagalan tersebut dan mendirikan kontainer pengganti dalam hitungan milidetik. Komponen garda depan yang bertugas menjamin ketersediaan jumlah replika aplikasi kita secara konstan adalah ReplicaSet.
ReplicaSet adalah objek pengawas dasar di Kubernetes yang memastikan bahwa sejumlah replika Pod yang kita inginkan selalu berjalan secara sehat di dalam kluster. Meskipun dalam praktik operasional harian kita jarang membuat objek ReplicaSet secara langsung, memahami arsitektur internal, mekanisme seleksi label, dan hubungannya dengan Deployment sangatlah penting untuk mencegah konflik penempatan Pod serta mempermudah proses debugging masalah ketersediaan kluster.
Mengapa ReplicaSet Dibutuhkan? Konsep Dasar Loop Penjaga #
Filosofi ReplicaSet didasarkan pada loop rekonsiliasi yang sangat sederhana namun dijalankan tanpa henti:
[\text{Kondisi Riil (Current)} \stackrel{?}{=} \text{Kondisi Target (Desired)}]
Setiap detiknya, ReplicaSet Controller (yang berjalan di dalam kube-controller-manager) menghitung jumlah Pod aktif di dalam namespace yang memiliki label cocok dengan spesifikasi selector miliknya.
- Jika Current < Desired: ReplicaSet segera memicu pembuatan Pod baru dengan menyalin struktur template yang dideklarasikan di dalam manifes.
- Jika Current > Desired: (Misalnya karena ada node yang pulih dan Pod lamanya hidup kembali), ReplicaSet akan memilah Pod mana saja yang berlebih dan mengirimkan instruksi penghapusan (
delete) untuk menyeimbangkan jumlahnya. - Jika Current == Desired: Tidak ada tindakan yang diambil. Kluster berada dalam status stabil.
Mekanisme pertahanan otomatis (self-healing) ini memangkas waktu pemulihan aplikasi dari menit (jika dilakukan secara manual oleh operator manusia) menjadi hanya hitungan detik saja.
Mekanisme Label Selector dan Adopsi Pod (Ownership) #
Salah satu keunikan arsitektur Kubernetes yang membedakannya dari sistem orkestrasi tradisional adalah bagaimana ReplicaSet melacak Pod yang menjadi tanggung jawabnya. ReplicaSet tidak mencatat daftar nama Pod atau ID unik secara statis di database. Sebaliknya, ia mengandalkan pencocokan label dinamis menggunakan Label Selector.
Ada dua cara mendefinisikan label selector pada ReplicaSet:
matchLabels: Pencocokan pasangan key-value secara presisi dan sederhana.matchExpressions: Pencocokan ekspresi logika tingkat lanjut menggunakan operator khusus.
Contoh manifest penggunaan matchExpressions yang memberikan fleksibilitas seleksi:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: payment-api-rs
namespace: production
spec:
replicas: 3
selector:
matchExpressions:
- {key: app, operator: In, values: [payment-api]}
- {key: environment, operator: NotIn, values: [development, staging]}
- {key: tier, operator: Exists}
template:
metadata:
labels:
app: payment-api
environment: production
tier: backend
spec:
containers:
- name: main-api
image: payment-api:v2.0
Penjelasan Operator matchExpressions:
#
In: Label pada Pod wajib memiliki key dengan salah satu value yang terdaftar di arrayvalues.NotIn: Label pada Pod wajib memiliki key dengan value yang tidak boleh sama dengan nilai di arrayvalues.Exists: Pod wajib memiliki label dengan key tersebut, tidak peduli apa pun nilainya (propertivaluestidak boleh diisi jika menggunakan operator ini).DoesNotExist: Pod wajib tidak memiliki key label tersebut.
Algoritma Pemilihan Pod yang Akan Dihapus (Deletion Priority) #
Ketika jumlah Pod riil melebihi target desired (misal kita menurunkan nilai replika dari 5 menjadi 3), ReplicaSet Controller tidak menghapus Pod secara acak. Ia menjalankan algoritma seleksi khusus untuk meminimalkan gangguan pada trafik kluster:
- Pending Pods: Pod yang masih dalam fase
Pending(belum mulai berjalan karena masih mengunduh image atau mencari node) akan dihapus terlebih dahulu. - Controller Kesiapan: Pod yang statusnya belum siap (NotReady / gagal lolos readiness probe) akan dihapus sebelum Pod yang sehat (Ready).
- Jumlah Restart (Restart Count): Pod yang memiliki riwayat restart terbanyak (menandakan adanya kebocoran memori atau ketidakstabilan aplikasi) akan diprioritaskan untuk dihapus.
- Creation Time (Waktu Pembuatan): Pod yang umurnya paling muda (youngest) akan dihapus sebelum Pod yang berumur tua (oldest) guna menjaga kestabilan Pod yang sudah lama melayani traffic.
- Penyebaran Node: Controller berusaha menjaga agar Pod tetap tersebar merata di seluruh node kluster. Jika Node A memiliki 3 Pod dan Node B memiliki 1 Pod, Controller akan menghapus Pod di Node A terlebih dahulu.
Konsep Kepemilikan Dinamis dan Adopsi Pod (Ownership) #
- Adopsi Pod Yatim Piatu: Jika kita secara manual membuat sebuah Pod baru (tanpa ReplicaSet) menggunakan perintah
kubectl rundan menempelkan label yang cocok dengan selector, ReplicaSet akan langsung mendeteksi keberadaan Pod tersebut. Ia akan mengadopsinya dan memasukkannya ke dalam perhitungan Current State. - OwnerReferences: Ketika sebuah Pod diadopsi atau dibuat oleh ReplicaSet, API Server menuliskan metadata
ownerReferencesdi dalam objek Pod tersebut, menunjuk ke nama ReplicaSet induk. Ini digunakan oleh Garbage Collector untuk menghapus Pod turunan jika ReplicaSet dihapus.
Strategi Penghapusan Cascading (Garbage Collection) #
Saat kita menghapus objek ReplicaSet menggunakan perintah kubectl delete rs <nama-rs>, ada tiga opsi kebijakan pembersihan (Garbage Collection) yang dapat kita pilih:
- Background Cascading (Default): API Server akan segera menghapus objek ReplicaSet, lalu di latar belakang, Garbage Collector akan melacak
ownerReferencespada Pod dan menghapus seluruh Pod turunan secara asinkron. - Foreground Cascading: API Server menandai ReplicaSet dalam status “deleting”, menghapus seluruh Pod turunan terlebih dahulu hingga bersih, barulah menghapus objek ReplicaSet secara permanen.
- Orphan Policy: Menghapus objek ReplicaSet saja, tetapi membiarkan seluruh Pod turunannya tetap hidup sebagai Pod yatim piatu (orphaned Pods) tanpa pengawas. Opsi ini dipicu dengan flag
--cascade=orphan.
Berikut adalah diagram alur bagaimana ReplicaSet memproses adopsi dan penyelarasan jumlah Pod:
flowchart TD
Start["Tik Loop Rekonsiliasi ReplicaSet"] --> GetPods["Cari semua Pod dengan label app=payment-api"]
GetPods --> CountPods["Hitung jumlah Pod aktif (Current)"]
CountPods --> Compare{"Apakah Current == Desired (3)?"}
Compare -- "Ya" --> Sleep["Tidur & Tunggu Tik Berikutnya"]
Compare -- "Current < Desired" --> CreatePod["1. Ambil template spec Pod\n2. Pasang ownerReferences ke ReplicaSet\n3. Kirim POST /api/v1/pods untuk buat Pod baru"]
Compare -- "Current > Desired" --> SelectPod["Pilih Pod yang akan dihapus\n(Memprioritaskan Pod NotReady / Baru)"]
SelectPod --> DeletePod["Kirim DELETE /api/v1/pods untuk hapus Pod"]
CreatePod --> Sleep
DeletePod --> Sleep
Abstraksi Bertingkat: Hubungan Deployment, ReplicaSet, dan Pod #
Di lingkungan produksi modern, kita sangat dilarang keras menulis manifest atau membuat objek ReplicaSet secara langsung. Kita selalu menggunakan objek-objek abstraksi tingkat tinggi seperti Deployment.
Mengapa Harus Deployment? #
ReplicaSet memiliki keterbatasan besar: ia tidak dapat melakukan pembaruan versi aplikasi (update rolling) secara cerdas. Jika kita mengubah tag image dari :v1.0 ke :v2.0 langsung pada manifest ReplicaSet, ia tidak akan melakukan apa-apa terhadap Pod yang sudah berjalan. Kita terpaksa menghapus seluruh Pod secara manual satu per satu agar ReplicaSet membuat Pod baru dengan template image yang baru (menyebabkan downtime).
Deployment memecahkan masalah ini dengan bertindak sebagai manajer di atas ReplicaSet:
- Saat kita mendeploy manifest
Deployment, Deployment Controller akan membuat objekReplicaSetPertama (versi 1) dan mengisinya dengan spesifikasi template versi 1. - ReplicaSet Pertama bertugas membuat Pod-Pod versi 1.
- Ketika kita mengubah image aplikasi di manifest Deployment ke versi 2, Deployment tidak mengedit ReplicaSet Pertama. Sebaliknya, ia membuat objek ReplicaSet Kedua (versi 2) yang terpisah.
- Deployment secara bertahap menaikkan kapasitas (scale up) ReplicaSet Kedua sembari menurunkan kapasitas (scale down) ReplicaSet Pertama ke angka 0.
Struktur Hierarki Abstraksi di Kubernetes:
Deployment: payment-deployment (Mengatur strategi rilis)
│
├── ReplicaSet: payment-deployment-7f4d9 (Versi Aktif - Replicas: 3)
│ ├── Pod: payment-deployment-7f4d9-abcde
│ ├── Pod: payment-deployment-7f4d9-fghij
│ └── Pod: payment-deployment-7f4d9-klmno
│
└── ReplicaSet: payment-deployment-1a2b3 (Versi Lama - Replicas: 0)
(Disimpan di etcd untuk history rollback)
Properti revisionHistoryLimit di Deployment menentukan berapa banyak objek ReplicaSet lama (yang kapasitasnya sudah 0) yang tetap dipertahankan di database kluster. Menyimpan ReplicaSet lama ini sangat krusial karena saat kita melakukan rollback via kubectl rollout undo, Deployment tinggal mengaktifkan kembali ReplicaSet lama tersebut tanpa perlu membuat ulang struktur dari awal, menjamin proses rollback berjalan instan.
Cara Membaca Status dan Mengelola ReplicaSet via CLI #
Meskipun dikelola otomatis oleh Deployment, keterampilan membaca status ReplicaSet sangat berharga saat melakukan investigasi insiden kluster.
# Tampilkan seluruh ReplicaSet yang ada di namespace aktif
kubectl get replicasets
Output perintah di atas akan menampilkan informasi seperti berikut:
NAME DESIRED CURRENT READY AGE
payment-deployment-7f4d9b 3 3 3 4d
payment-deployment-1a2b3c 0 0 0 10d
- DESIRED: Jumlah target replika yang kita minta di dalam manifest.
- CURRENT: Jumlah replika Pod nyata yang saat ini sedang dicoba dijalankan oleh ReplicaSet.
- READY: Jumlah Pod sehat yang sudah lolos uji kesehatan (readiness probe) dan siap menerima traffic jaringan.
Jika kita melihat nilai CURRENT bertambah namun READY tetap bernilai 0, kita dapat mendiagnosis kegagalannya dengan melihat log events di tingkat ReplicaSet:
# Periksa log kejadian internal ReplicaSet
kubectl describe replicaset payment-deployment-7f4d9b
Di bagian bawah output perintah describe, kita dapat mendeteksi jika terjadi kegagalan sistemik, misalnya kegagalan kuota namespace (ResourceQuota Exceeded) atau penolakan otentikasi registry saat menarik image.
Anti-Pattern dalam Manajemen ReplicaSet #
Berikut adalah kesalahan fatal yang sering kali mengacaukan mekanisme pemantauan daur hidup Pod kluster:
Anti-Pattern 1: Bentrokan Label Selector Antar-ReplicaSet (Label Hijacking) #
Menggunakan label yang terlalu generik atau sama persis untuk dua objek pengontrol yang berbeda.
ANTI-PATTERN: Menulis Selector app=payment-api untuk Dua ReplicaSet/Deployment Berbeda
// KITA MELAKUKAN:
- Membuat Deployment A (untuk payment-api-staging) dengan selector label `app: payment-api`.
- Membuat Deployment B (untuk payment-api-production) di namespace yang sama dengan selector label `app: payment-api`.
// KONSEKUENSI DI PRODUKSI:
- Pod Hijacking (Pembajakan Pod): ReplicaSet A dan ReplicaSet B akan saling memperebutkan Pod yang sama.
- ReplicaSet A mendeteksi ada 6 Pod aktif (3 miliknya dan 3 milik B). Karena target desired adalah 3,
ReplicaSet A akan mulai membunuh 3 Pod secara acak (bisa jadi membunuh Pod produksi milik B).
- Sebaliknya, ReplicaSet B mendeteksi Pod berkurang, lalu membuat Pod baru. ReplicaSet A membunuhnya lagi.
- Terjadi siklus pembunuhan dan pembuatan Pod tiada henti (flapping) yang melumpuhkan performa CPU master node kluster.
✓ SOLUSI YANG BENAR:
- Selalu gunakan kombinasi label yang unik dan spesifik untuk membedakan lingkungan deployment (staging vs production).
- Gunakan label bawaan standar industri seperti `app.kubernetes.io/name` digabung dengan label environment.
- Lebih aman lagi, gunakan namespace terpisah (isolasi logis) untuk memisahkan staging dan production.
Anti-Pattern 2: Melakukan Modifikasi Langsung (Hot Patching) pada Pod Template di Tingkat ReplicaSet #
Mencoba memodifikasi spesifikasi Pod secara langsung pada objek ReplicaSet yang dikelola oleh Deployment.
ANTI-PATTERN: Menjalankan kubectl edit replicaset <nama-rs>
// KITA MELAKUKAN:
- Menghubungi biner ReplicaSet langsung menggunakan command line untuk mengubah environment variable.
// KONSEKUENSI DI PRODUKSI:
- Hasil Terbuang: Perubahan kita akan bertahan beberapa detik saja. Begitu Deployment Controller
melakukan rekonsiliasi berkala, ia akan mendeteksi bahwa spesifikasi ReplicaSet tidak cocok dengan manifest Deployment induknya.
- Deployment Controller akan langsung menimpa (*override*) dan mengembalikan spesifikasi ReplicaSet
ke nilai asal, menghapus konfigurasi baru yang baru saja kita masukkan.
✓ SOLUSI YANG BENAR:
- Selalu lakukan perubahan di tingkat paling atas, yaitu manifest `Deployment`.
- Jalankan perintah edit pada deployment: `kubectl edit deployment <nama-deploy>`
atau perbarui berkas manifes YAML lokal Anda dan jalankan `kubectl apply -f deployment.yaml`.
Ringkasan #
- Loop Penjaga Ketersediaan — ReplicaSet bertugas memastikan jumlah Pod yang aktif selalu tepat sama dengan angka desired state di setiap detik operasional kluster.
- Seleksi Berbasis Label — Kepemilikan Pod ditentukan secara dinamis menggunakan selector label, bukan berdasarkan ID statis, mempermudah adopsi Pod secara fleksibel.
- Bahaya Pod Duplikat — Hindari membuat Pod manual dengan label yang cocok dengan selector ReplicaSet aktif guna mencegah adopsi tidak disengaja dan penghapusan paksa Pod.
- Abstraksi Deployment — Jangan mengelola ReplicaSet secara langsung; selalu gunakan Deployment sebagai orkestrator tingkat tinggi untuk memfasilitasi rolling update tanpa downtime.
- Penyimpanan Sejarah Rollback — Objek ReplicaSet lama yang kapasitasnya sudah 0 dipertahankan kluster sebagai catatan riwayat guna mempercepat proses rollback instan.
- Identifikasi Insiden via Events — Gunakan perintah
kubectl describe replicasetuntuk mendeteksi kegagalan alokasi kuota kluster atau error penarikan image kontainer.- Hindari Bentrokan Label — Selalu rancang label selector yang unik dan spesifik untuk setiap aplikasi guna mencegah terjadinya pembajakan Pod (Pod hijacking) antarkontroler.