Controller Manager #
Di dalam kluster Kubernetes, kita sering mendengar istilah “declarative configuration”. Kita sebagai pengguna cukup menyatakan keadaan akhir kluster yang diinginkan (desired state) melalui manifes YAML—misalnya, meminta tiga replika kontainer aplikasi berjalan secara stabil. Namun, sistem tidak secara ajaib mencapai keadaan tersebut sendirinya. Di balik layar, terdapat komponen mesin pelaksana yang secara terus-menerus bekerja siang dan malam untuk mencocokkan kondisi riil di lapangan (current state) dengan keinginan kita. Komponen vital tersebut adalah kube-controller-manager (Controller Manager).
Sebagai manajer utama dari berbagai kontroler, Controller Manager mengemas puluhan loop kontrol (control loops) independen ke dalam satu proses biner tunggal. Memahami arsitektur internal Controller Manager membantu kita mendeteksi mengapa perubahan konfigurasi tidak segera diterapkan, merancang sistem dengan toleransi kesalahan yang tinggi, serta memahami fondasi dari pembuatan Custom Controller (Operator Pattern) untuk mengotomatisasi infrastruktur yang rumit.
Konsep Dasar Loop Kontrol dan Siklus Rekonsiliasi #
Jantung dari seluruh otomatisasi Kubernetes terletak pada sebuah pola sederhana namun sangat kuat yang disebut reconciliation loop (loop rekonsiliasi). Pola ini bertindak seperti termostat AC di rumah kita: termostat mengamati suhu ruangan saat ini, membandingkannya dengan suhu target yang kita atur, lalu menyalakan atau mematikan kompresor pendingin untuk mencapai target tersebut secara terus-menerus.
Di Kubernetes, formula loop rekonsiliasi dapat diringkas menjadi tiga langkah berulang:
- Observe (Mengamati): Membaca status terbaru dari objek-objek kluster melalui cache lokal yang terhubung dengan API Server.
- Compare (Membandingkan): Menganalisis perbedaan antara status riil saat ini (current state) dan status yang diinginkan (desired state) yang tercantum di dalam spesifikasi resource (
spec). - Act (Bertindak): Melakukan panggilan API untuk membuat, memperbarui, atau menghapus resource kluster agar status riil mendekati status yang diinginkan.
Berikut adalah alur visual dari loop rekonsiliasi yang berjalan tanpa henti di dalam setiap kontroler:
flowchart TD
Start["Mulai Siklus Rekonsiliasi"] --> Observe["1. Observe (Amati)\nBaca status riil kluster via API Server cache"]
Observe --> Compare["2. Compare (Bandingkan)\nCek apakah Current State == Desired State"]
Compare --> Decision{Apakah ada perbedaan?}
Decision -- "Tidak (Stabil)" --> Wait["Tunggu Event Baru / Tik Timer"]
Decision -- "Ya (Inkonsisten)" --> Act["3. Act (Eksekusi Tindakan)\nKirim instruksi perubahan status ke API Server"]
Act --> UpdateCache["Perbarui Cache Lokal"]
UpdateCache --> Wait
Wait --> Observe
Karakteristik Idempotensi dan Ketahanan Terhadap Kegagalan #
Pola loop rekonsiliasi dirancang dengan sifat idempotent. Artinya, berapa kali pun loop rekonsiliasi dijalankan dengan input data yang sama, hasil akhir status sistem akan tetap konsisten dan tidak memicu efek samping yang merusak. Sifat ini sangat krusial dalam sistem terdistribusi:
- Crash Resilience: Jika proses biner
kube-controller-managertiba-tiba mengalami crash dan mati di tengah jalan, kontroler tidak perlu mengingat langkah terakhirnya secara detail. Saat biner baru dijalankan kembali, ia hanya perlu membandingkan status terkini dari API Server dan mengambil tindakan penyelarasan dari awal. - Event-Driven & Level-Driven: Kontroler tidak hanya bereaksi terhadap sinyal perubahan sesaat (edges), melainkan berpegang teguh pada keadaan level (levels). Hal ini menjamin bahwa meskipun ada notifikasi perubahan jaringan yang hilang atau terlewat akibat gangguan koneksi, rekonsiliasi berikutnya akan mendeteksi perbedaan tersebut secara otomatis saat membaca ulang status kluster.
Menjelajahi Kontroler Inti Kluster #
Meskipun dikemas dalam satu proses biner (kube-controller-manager), komponen ini menjalankan puluhan kontroler internal yang terisolasi secara logis. Setiap kontroler bertanggung jawab atas siklus hidup objek Kubernetes yang spesifik. Berikut adalah penjelajahan mendalam terhadap kontroler-kontroler paling krusial di dalam kluster:
1. Node Lifecycle Controller #
Node Controller bertanggung jawab penuh untuk memantau kesehatan fisik maupun virtual dari Worker Node yang terdaftar di dalam kluster.
- Mekanisme Heartbeat: Kubelet di setiap node secara berkala mengirimkan laporan kesehatan ke API Server. Node Controller memantau waktu masuknya laporan tersebut.
- Grace Period: Jika sebuah node tidak mengirimkan laporan detak jantung (heartbeat) selama lebih dari batas waktu toleransi (secara default
node-monitor-grace-periodbernilai 40 detik), Node Controller akan memperbarui status node tersebut menjadiUnknownatauNotReady. - Eviction (Pengusiran Pod): Jika kondisi node tetap buruk melewati batas waktu pengusiran (default
pod-eviction-timeoutselama 5 menit), Node Controller akan menambahkan taint khusus (node.kubernetes.io/unreachableataunode.kubernetes.io/not-ready) ke objek Node. Hal ini memicu pengusiran otomatis terhadap Pod-Pod yang tidak memiliki toleration yang sesuai, lalu menjadwalkannya ulang ke Worker Node lain yang sehat.
2. ReplicaSet Controller #
ReplicaSet Controller bertugas memastikan bahwa jumlah replika Pod yang berjalan di kluster selalu tepat sama dengan angka yang didefinisikan pada properti .spec.replicas.
- OwnerReferences: Untuk mengidentifikasi Pod mana saja yang berada di bawah pengawasannya, ReplicaSet Controller menggunakan Label Selector. Pod yang dibuat oleh ReplicaSet akan memiliki metadata
ownerReferencesyang menunjuk ke ReplicaSet induk. - Alur Rekonsiliasi: Jika jumlah Pod aktif dengan label yang cocok ternyata kurang dari desired state (misalnya karena ada Pod yang terhapus manual), ReplicaSet Controller akan mengirimkan request
POSTke API Server untuk membuat Pod baru. Sebaliknya, jika jumlah Pod melebihi desired state, kontroler akan menghapus Pod ekstra secara teratur (memprioritaskan Pod yang statusnya belum siap atau yang baru dibuat).
3. Deployment Controller #
Deployment Controller berada di tingkat abstraksi yang lebih tinggi. Ia tidak mengelola Pod secara langsung, melainkan bertugas mengelola objek ReplicaSet guna memfasilitasi pembaruan aplikasi tanpa downtime.
- Rolling Update: Saat kita memperbarui versi image aplikasi di dalam manifes Deployment, Deployment Controller akan membuat objek ReplicaSet baru (versi 2). Ia kemudian menaikkan kapasitas replika di ReplicaSet baru secara bertahap, sembari menurunkan kapasitas replika di ReplicaSet lama (versi 1) secara paralel.
- Kontrol Latensi Transisi: Dua parameter penting yang dikelola oleh kontroler ini adalah
maxSurge(jumlah Pod maksimum yang boleh dibuat di atas target selama proses update) danmaxUnavailable(jumlah Pod maksimum yang boleh tidak aktif selama proses update). - Rollback History: Deployment Controller menjaga riwayat objek ReplicaSet lama (ditentukan oleh
revisionHistoryLimit). Jika kita melakukan perintah rollback, kontroler cukup membalikkan arah sinkronisasi kapasitas replika ke objek ReplicaSet versi sebelumnya.
4. EndpointSlice Controller #
Di masa lalu, Kubernetes menggunakan Endpoint Controller tradisional yang menyimpan seluruh IP Pod ke dalam satu objek Endpoint tunggal untuk setiap Service. Pada kluster skala besar dengan ribuan Pod, memodifikasi satu IP Pod memaksa seluruh daftar IP ditulis ulang ke API Server, memicu beban jaringan dan etcd yang luar biasa tinggi.
- Abstraksi EndpointSlice: Untuk mengatasi masalah skalabilitas tersebut, EndpointSlice Controller memecah daftar IP target Service ke dalam beberapa objek kecil bernama
EndpointSlice(masing-masing memuat maksimal 100 endpoint secara default). - Sinkronisasi Realtime: EndpointSlice Controller memantau perubahan siklus hidup Pod dan kesiapan (readiness probe). Jika sebuah Pod dinyatakan sehat oleh Kubelet, kontroler akan menambahkan IP Pod ke EndpointSlice yang sesuai, sehingga
kube-proxydi setiap node dapat segera mengizinkan lalu lintas jaringan masuk ke kontainer baru tersebut.
5. ServiceAccount Controller & Garbage Collector #
- ServiceAccount Controller: Mengotomatisasi pembuatan token keamanan default untuk setiap namespace. Kontroler ini memantau pembuatan namespace baru dan segera menyiapkan ServiceAccount default beserta Secret token autentikasi yang diperlukan agar kontainer di dalam namespace tersebut dapat berinteraksi dengan API Server jika diizinkan.
- Garbage Collector (Pembersih Sampah): Bertugas menghapus objek-objek yatim piatu (orphaned resources) yang induknya telah dihapus. Mekanisme ini menggunakan metadata
ownerReferencesdengan aturan pembersihanCascade(misalnya, jika sebuah objek Deployment dihapus, Garbage Collector bertugas melacak dan menghapus semua objek ReplicaSet dan Pod turunan yang terkait dengannya secara bersih).
Mekanisme Leader Election pada High Availability (HA) #
Di lingkungan produksi yang menuntut ketersediaan tinggi, kita tidak boleh hanya menjalankan satu instansi Control Plane. Kita wajib menjalankan minimal tiga instansi Control Plane secara paralel. Namun, hal ini menimbulkan tantangan serius bagi Controller Manager: karena kontroler bersifat aktif menulis status ke API Server, jika ada dua instansi Controller Manager aktif menulis instruksi yang sama secara bersamaan, akan terjadi konflik data (split-brain) yang memicu inkonsistensi kluster.
Untuk mencegah masalah ini, Kubernetes mengadopsi pola Leader Election (Pemilihan Pemimpin) berbasis model Active-Passive (satu instansi aktif, instansi lainnya siaga/standby).
sequenceDiagram
participant InstanceA as Controller Manager A (Standby)
participant InstanceB as Controller Manager B (Active Leader)
participant APIServer as API Server (Lease API)
Note over InstanceB: Memperbarui lock Lease setiap 2 detik
InstanceB->>APIServer: UPDATE leases/kube-controller-manager (renewTime = Now)
APIServer-->>InstanceB: 200 OK
Note over InstanceA: Mengamati status Lease secara periodik
InstanceA->>APIServer: GET leases/kube-controller-manager
APIServer-->>InstanceA: Data Lease (Leader: Instance B, duration: 15s)
Note over InstanceB: Instance B mengalami crash total!
Note over InstanceA: Waktu sewa Lease habis (> 15 detik)
InstanceA->>APIServer: GET leases/kube-controller-manager
APIServer-->>InstanceA: Data Lease (Sewa Kedaluwarsa)
InstanceA->>APIServer: UPDATE leases/kube-controller-manager (Leader: Instance A)
APIServer-->>InstanceA: 200 OK (Instance A Menjadi Leader Baru)
Note over InstanceA: Mulai menjalankan loop rekonsiliasi internal
Bagaimana Lease API Bekerja #
Kubernetes memanfaatkan objek Lease di bawah grup API coordination.k8s.io sebagai kunci pengunci (distributed lock). Contoh manifes representasi objek Lease ini di dalam API Server adalah sebagai berikut:
apiVersion: coordination.k8s.io/v1
kind: Lease
metadata:
name: kube-controller-manager
namespace: kube-system
spec:
holderIdentity: controller-manager-node-1 # Identitas instansi yang memegang status Leader
leaseDurationSeconds: 15 # Durasi masa sewa kunci sebelum dinyatakan hangus
acquireTime: "2026-06-16T22:00:00.000000Z" # Waktu awal sewa berhasil diklaim
renewTime: "2026-06-16T22:27:00.000000Z" # Waktu terakhir Leader memperbarui sewa (heartbeat)
leaseTransitions: 3 # Jumlah berapa kali kepemimpinan berpindah tangan
Analisis Skenario Failover dan Dampaknya #
Siklus hidup manajemen kepemimpinan di dalam kluster berjalan dengan aturan berikut:
- Akuisisi Awal: Saat kluster pertama kali menyala, semua instansi Controller Manager mencoba menuliskan nama identitas mereka ke objek
Lease/kube-controller-manager. Instansi pertama yang berhasil menulis ke API Server akan diangkat menjadi Leader. - Heartbeat Pembaruan: Leader wajib memperbarui properti
renewTimedi dalam objek Lease secara rutin (misalnya setiap 2 detik) guna mengonfirmasi kepada kluster bahwa dirinya masih sehat dan bekerja. - Deteksi Kegagalan & Failover: Instansi lain (standby) secara berkala membaca objek Lease tersebut. Jika Leader mengalami kegagalan (misalnya karena sistem operasi hang atau crash biner) dan gagal memperbarui sewa dalam jangka waktu
leaseDurationSeconds(default 15 detik), instansi standby akan mendeteksi bahwa sewa telah kedaluwarsa. Mereka kemudian akan saling bersaing menuliskan identitas mereka ke objek Lease. Instansi yang berhasil melakukan update pertama kali akan mengambil alih kepemimpinan dan segera mengaktifkan seluruh loop kontrol internalnya. - Dampak Toleransi Latensi: Selama transisi perpindahan kepemimpinan berlangsung (sekitar 15-30 detik), tidak ada kontroler yang aktif berjalan di kluster. Ini berarti jika ada Pod yang mati pada rentang waktu ini, Pod baru tidak akan langsung dibuat. Meskipun demikian, transisi ini sama sekali tidak mengganggu jalannya aplikasi yang sudah berjalan aktif di Worker Node. Hal ini membuktikan keandalan arsitektur eventual consistency Kubernetes.
Operator Pattern dan Penulisan Custom Controller #
Kekuatan utama Kubernetes tidak terbatas pada kemampuan mengelola resource bawaan seperti Pod dan Service. Kubernetes didesain agar dapat diperluas tanpa batas oleh pengguna melalui Operator Pattern.
Operator adalah kombinasi dari dua elemen utama:
- Custom Resource Definition (CRD): Menambahkan skema tipe data baru ke dalam database API Server Kubernetes (misalnya tipe data
PostgresClusteratauRedisSentinel). - Custom Controller: Biner aplikasi mandiri yang kita tulis untuk menjalankan loop rekonsiliasi khusus guna mengelola siklus hidup resource kustom tersebut.
Arsitektur Internal Custom Controller #
Menulis kontroler kustom yang efisien membutuhkan pemahaman tentang bagaimana ia berinteraksi dengan API Server tanpa membebani kluster. Berikut adalah arsitektur standar industri yang digunakan oleh framework seperti controller-runtime (Kubebuilder dan Operator SDK):
flowchart LR
subgraph APIServerGroup ["Kubernetes Control Plane"]
APIServer["API Server"] <--> etcd[("etcd DB")]
end
subgraph CustomControllerProcess ["Proses Custom Controller (Operator)"]
direction TB
Reflector["Reflector"] --> FIFO["DeltaFIFO Queue"]
FIFO --> Informer["Informer (Indexer)"]
Informer --> Cache[("Local Cache (Lister)")]
Informer -->|Kirim Event| EventHandlers["Event Handlers (Add/Update/Delete)"]
EventHandlers -->|Masukkan Key| WorkQueue["WorkQueue (Antrean Kerja)"]
WorkQueue -->|Ambil Kerja| Workers["Worker Threads"]
Workers -->|1. Baca Spec| Cache
Workers -->|2. Rekonsiliasi & Act| APIServer
end
APIServer -.->|Watch Stream| Reflector
Komponen Arsitektur Operator: #
- Reflector: Membuka koneksi Watch persistent ke API Server untuk mendengarkan perubahan spesifik pada resource kustom. Setiap kali ada perubahan, Reflector memasukkan data tersebut ke dalam antrean internal
DeltaFIFO. - Informer & Indexer: Membaca data dari
DeltaFIFO, mendekripsinya, lalu menyimpannya ke dalamLocal Cache(sehingga kontroler tidak perlu terus-menerus memanggil API Server untuk membaca data, melainkan cukup membaca dari memori lokal melaluiLister). Informer kemudian memicu fungsi Event Handlers (sepertiOnAdd,OnUpdate,OnDelete). - WorkQueue (Antrean Kerja): Event handler tidak langsung mengeksekusi rekonsiliasi. Ia hanya memasukkan kunci pengenal unik resource (misalnya format
"namespace/nama-resource") ke dalamWorkQueue. Antrean ini memiliki fitur cerdas seperti rate-limiting (membatasi frekuensi pengerjaan ulang jika terjadi error beruntun) dan deduplication (menggabungkan beberapa event perubahan cepat dari objek yang sama menjadi satu tugas rekonsiliasi saja). - Worker Threads: Utas-utas pekerja yang berjalan secara paralel. Mereka mengambil kunci dari
WorkQueue, membaca spesifikasi objek terbaru dariLocal Cache, membandingkannya dengan kondisi riil di lapangan (misal: memeriksa apakah database fisik di cloud sudah terbuat), lalu melakukan panggilan API ke luar (misal ke cloud provider API atau ke API Server) untuk menyelaraskan status.
Anti-Pattern dalam Manajemen Kontroler #
Dalam mendesain sistem produksi atau menulis otomatisasi di Kubernetes, terdapat beberapa kesalahan fatal yang sering kali dilakukan akibat kurangnya pemahaman tentang cara kerja sistem asinkron kontroler.
Anti-Pattern 1: Bypass Kontroler dengan Modifikasi Manual atau Imperatif #
Mencoba memaksa sistem terdistribusi melakukan sesuatu secara instan dengan mengabaikan kontroler bawaan.
ANTI-PATTERN: Menghapus Pod Secara Paksa Tanpa Memperhatikan Replika Induk
// KITA MELAKUKAN:
- Menjalankan aplikasi di bawah kendali Deployment/ReplicaSet.
- Ketika aplikasi bermasalah, kita langsung menghapus Pod secara manual dengan flag paksa:
kubectl delete pod my-app-7f4d9b-abcde --force --grace-period=0
- Atau secara manual memodifikasi IP iptables langsung di host OS Worker Node untuk mengubah rute traffic.
// KONSEKUENSI DI PRODUKSI:
- Kebocoran Resource: Penghapusan paksa memotong siklus pembersihan rapi dari Garbage Collector.
Objek eksternal seperti dynamic persistent volume atau cloud load balancer bisa tertinggal dan tidak terhapus (orphan), memicu pembengkakan biaya.
- Inkonsistensi Jaringan: Modifikasi iptables manual akan segera ditimpa dan dihapus dalam hitungan detik
oleh kube-proxy karena EndpointSlice Controller mendeteksi status riil tidak cocok dengan database etcd.
✓ SOLUSI YANG BENAR:
- Selalu ubah kondisi kluster melalui modifikasi manifes deklaratif (mengubah spec Deployment, Service, dll.).
- Izinkan kontroler yang melakukan penghapusan dan pembuatan resource secara asinkron dan teratur.
- Jika ingin merestart aplikasi secara aman, gunakan perintah resmi yang memicu siklus rolling update terkontrol:
kubectl rollout restart deployment my-app
Anti-Pattern 2: Menulis Custom Controller Tanpa Optimistic Concurrency Control (OCC) #
Kesalahan fatal saat menulis Operator kustom yang mengakibatkan penulisan data konfliktual atau balapan data (race conditions).
// ANTI-PATTERN: Melakukan Update Objek Tanpa Memeriksa ResourceVersion
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
var dbCluster myv1.DatabaseCluster
r.Get(ctx, req.NamespacedName, &dbCluster) // Baca data dari cache lokal
// ✗ Kita memodifikasi status secara langsung tanpa memperhatikan perubahan di etcd
dbCluster.Status.Phase = "Running"
// ✗ Update ini akan gagal jika ada komponen lain yang mengubah objek ini di etcd beberapa milidetik lalu
r.Status().Update(ctx, &dbCluster)
return ctrl.Result{}, nil
}
// ✓ SOLUSI YANG BENAR: Menerapkan Retry Loop saat Terjadi Konflik OCC
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// Gunakan library retry bawaan Kubernetes untuk menangani konflik resourceVersion secara elegan
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
var dbCluster myv1.DatabaseCluster
if err := r.Get(ctx, req.NamespacedName, &dbCluster); err != nil {
return err
}
dbCluster.Status.Phase = "Running"
return r.Status().Update(ctx, &dbCluster)
})
if err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}
Ringkasan #
- Jantung Declarative Kluster — Controller Manager adalah proses tunggal yang mengonsolidasikan puluhan loop kontrol mandiri untuk menjaga status riil kluster tetap sesuai dengan manifes YAML.
- Formula Siklus Rekonsiliasi — Setiap kontroler menerapkan loop tanpa henti: Observe ➔ Compare ➔ Act. Desain ini menjamin sifat idempotent dan toleransi kegagalan kluster yang tinggi.
- Pembagian Tugas Kontroler — Tugas-tugas kluster didelegasikan secara spesifik: Node Controller memantau kesehatan server, ReplicaSet Controller menjaga jumlah Pod, sedangkan Deployment Controller memimpin proses update tanpa downtime.
- Skalabilitas via EndpointSlice — EndpointSlice Controller memecah daftar IP Service menjadi bagian-bagian kecil guna mencegah penurunan performa jaringan pada kluster skala besar.
- Leader Election coordination.k8s.io — Penggunaan objek Lease sebagai distributed lock menjamin hanya ada satu instansi Controller Manager yang aktif dalam skenario High Availability, menghindari risiko split-brain.
- Arsitektur Operator Efisien — Penulisan kontroler kustom wajib menggunakan pola Informer, Lister Cache, dan WorkQueue guna meminimalkan beban request langsung ke API Server.
- Optimistic Concurrency Control (OCC) — Selalu gunakan pola RetryOnConflict saat menulis kode kontroler guna menangani bentrokan penulisan data paralel di database etcd.
← Sebelumnya: Scheduler Berikutnya: Etcd & Cluster Consistency →