Rolling Update #
Dalam operasional aplikasi modern, memperbarui kode atau konfigurasi secara berkala adalah rutinitas harian. Tantangan terbesarnya adalah bagaimana kita dapat meluncurkan versi baru tersebut tanpa mengganggu pengguna aktif sama sekali (zero-downtime deployment). Kubernetes memecahkan tantangan ini secara bawaan menggunakan strategi Rolling Update. Dibandingkan dengan metode deployment tradisional yang sering kali membutuhkan jendela pemeliharaan (maintenance window) di tengah malam, Rolling Update di Kubernetes bekerja dengan cara mengganti Pod lama dengan Pod baru secara berangsur-angsur.
Namun, mencapai zero-downtime yang sesungguhnya tidak sesederhana sekadar membiarkan konfigurasi default berjalan. Kita harus mengonfigurasi toleransi kegagalan secara matematis, menyelaraskan siklus hidup pemutusan koneksi (graceful shutdown), serta mendesain probe kesehatan (readiness probes) yang akurat. Artikel ini membedah mekanisme internal Rolling Update, perhitungan parameter transisi, sinkronisasi routing jaringan, serta panduan memecahkan masalah saat proses update mengalami hambatan (stuck).
Cara Kerja Internal Deployment Controller #
Saat kita memperbarui spesifikasi Pod (seperti mengganti versi tag image kontainer) pada objek Deployment, Kubernetes tidak langsung menimpa Pod yang sedang berjalan. Deployment Controller bertindak sebagai manager tingkat tinggi yang mengoordinasikan pembuatan dan penghapusan Pod melalui objek ReplicaSet.
Berikut adalah tahapan transisi state yang dikelola oleh Deployment Controller:
- Pembuatan ReplicaSet Baru: Deployment Controller membuat ReplicaSet kedua (kita sebut v2) di samping ReplicaSet aktif saat ini (v1).
- Pemberian Skala Bertahap (Scaling Up v2): ReplicaSet v2 mulai membuat Pod baru dengan versi kode v2.
- Verifikasi Kesehatan: Pod v2 harus melewati pemeriksaan Readiness Probe. Sebelum probe ini mengembalikan status sukses, Pod v2 dianggap belum siap melayani lalu lintas dan tidak akan dimasukkan ke dalam daftar endpoint jaringan.
- Pengurangan Skala Bertahap (Scaling Down v1): Setelah satu atau beberapa Pod v2 dikonfirmasi sehat, Deployment Controller menginstruksikan ReplicaSet v1 untuk mematikan sebagian Pod v1 secara perlahan.
- Pengulangan Siklus: Proses ini berulang hingga seluruh Pod v1 dihapus (skala nol) dan ReplicaSet v2 memegang seluruh jumlah replika yang diinginkan secara penuh.
sequenceDiagram
participant DC as Deployment Controller
participant RS1 as ReplicaSet v1 (Old)
participant RS2 as ReplicaSet v2 (New)
participant Pod2 as Pod v2 (Candidate)
participant SVC as EndpointSlice / Service
DC->>RS2: Perintahkan Scale Up (+1 Pod v2)
RS2->>Pod2: Buat Pod v2
Note over Pod2: Kontainer Inisialisasi & Jalankan Probe
Pod2-->>DC: Readiness Probe Berhasil (200 OK)
DC->>SVC: Tambahkan IP Pod v2 ke Routing List
DC->>RS1: Perintahkan Scale Down (-1 Pod v1)
Note over RS1: Hapus 1 Pod v1 secara graceful
Note over DC: Ulangi siklus hingga v1 = 0
Perhitungan Parameter: maxSurge dan maxUnavailable #
Kecepatan, penggunaan resource tambahan, dan tingkat toleransi kegagalan selama proses Rolling Update dikendalikan secara ketat oleh dua parameter di bawah properti rollingUpdate:
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 0
Kita dapat menentukan nilai kedua parameter ini menggunakan angka absolut (misalnya 1 atau 2) atau persentase dari total replika yang diinginkan (misalnya 25%).
1. maxSurge
#
Menentukan jumlah maksimum Pod tambahan yang boleh dibuat di atas kapasitas replika yang diinginkan selama proses update berlangsung.
- Rumus: $\text{Jumlah Pod Maksimal} = \text{Desired Replicas} + \text{maxSurge}$
- Implikasi: Nilai
maxSurgeyang tinggi mempercepat proses deployment karena Kubernetes dapat membuat banyak Pod baru secara paralel. Namun, hal ini membutuhkan kapasitas sisa CPU/Memory (headroom) yang cukup pada node cluster.
2. maxUnavailable
#
Menentukan jumlah maksimum Pod yang boleh tidak tersedia (dalam kondisi mati atau belum siap) selama proses update berlangsung.
- Rumus: $\text{Jumlah Pod Minimal Tersedia} = \text{Desired Replicas} - \text{maxUnavailable}$
- Implikasi: Jika kita menetapkan
maxUnavailable: 0, Kubernetes menjamin bahwa kapasitas layanan kita tidak akan pernah berkurang di bawah 100% dari total replika yang kita minta selama masa transisi.
Pola Konfigurasi yang Direkomendasikan di Produksi #
Pola A: Zero-Downtime Ketat (Sangat Direkomendasikan) #
- Konfigurasi:
maxSurge: 1(atau25%),maxUnavailable: 0 - Karakteristik: Menjamin kapasitas penuh layanan 100% terjaga setiap saat. Pod lama tidak akan pernah dimatikan sebelum Pod baru dikonfirmasi sehat oleh readiness probe.
- Trade-off: Deployment berjalan lebih lambat karena harus menunggu Pod baru siap satu per satu sebelum melanjutkan siklus berikutnya.
Pola B: Hemat Resource (Cluster Terbatas) #
- Konfigurasi:
maxSurge: 0,maxUnavailable: 1(atau25%) - Karakteristik: Tidak membutuhkan resource ekstra sama sekali di cluster. Kubernetes langsung mematikan satu Pod lama untuk memberikan ruang slot penjadwalan bagi Pod baru.
- Trade-off: Selama transisi, kapasitas layanan kita berkurang satu replika. Tidak cocok untuk aplikasi yang jalurnya sudah mendekati batas utilisasi 100% di bawah beban puncak.
Pola C: Update Cepat Skala Besar #
- Konfigurasi:
maxSurge: 50%,maxUnavailable: 0 - Karakteristik: Sangat cepat. Setengah dari jumlah Pod baru dibuat secara instan di awal proses.
- Trade-off: Memerlukan headroom kapasitas node yang sangat besar di cluster.
Peran Vital Probes dalam Jaringan Kubernetes #
Mekanisme Rolling Update yang aman sangat bergantung pada keakuratan Readiness Probe. Ketika Pod v2 baru saja dibuat, Kubelet di node worker akan memicu startup kontainer. Jika kontainer sudah masuk status Running, hal ini hanya menandakan bahwa proses utama (seperti node server.js atau java -jar) telah dijalankan. Proses tersebut biasanya membutuhkan waktu beberapa detik untuk memuat pustaka, membuka koneksi ke database, atau memanaskan cache (warm start).
Jika kita tidak mendefinisikan readinessProbe:
- Kubernetes langsung menganggap Pod v2 tersebut sehat (Ready).
- Service Controller segera memasukkan IP Pod v2 ke daftar perutean trafik.
- Kube-proxy dan Ingress Controller mulai mengirimkan trafik pengguna nyata ke Pod v2 yang belum siap sepenuhnya. Pengguna akan menerima error HTTP
502 Bad Gatewayatau503 Service Unavailable. - Bersamaan dengan itu, Kubernetes langsung mematikan Pod v1 karena menganggap tugas transisi telah selesai.
flowchart TD
subgraph NoProbe["TANPA PROBE"]
Run1["Pod v2 Run"] --> Ready1["Langsung Ditandai Ready"] --> Traffic1["Trafik Masuk"] --> Crash1["CRASH/ERROR 502"]
Crash1 --> Kill1["Dimatikan Instan"] --> PodV1_1["Pod v1 Lama"]
end
subgraph WithProbe["DENGAN PROBE"]
Run2["Pod v2 Run"] --> Wait2["Tunggu Probe Sukses / 200 OK"] --> Ready2["Ditandai Ready"] --> Traffic2["Trafik Masuk (Lancar)"]
Traffic2 --> Kill2["Dimatikan Secara Bertahap"] --> PodV1_2["Pod v1 Lama"]
end
Pentingnya minReadySeconds
#
Selain probe, properti minReadySeconds sangat penting untuk ditambahkan. Properti ini memerintahkan Kubernetes untuk menunggu selama N detik setelah Pod baru ditandai Ready sebelum melanjutkan ke langkah berikutnya.
Jika aplikasi kita memiliki bug memori tersembunyi yang menyebabkannya crash 5 detik setelah menerima trafik nyata, minReadySeconds: 30 akan menyelamatkan kita. Kubernetes akan menghentikan proses update karena Pod baru mati sebelum batas waktu stabilisasi terlewati, sehingga Pod v1 yang tersisa tetap aman menjalankan layanan.
Siklus Graceful Shutdown (Pematian yang Rapi) #
Saat Deployment Controller memutuskan untuk mematikan Pod lama (v1), proses pemutusan koneksi harus dikelola secara halus agar request pengguna yang sedang berjalan di dalam kontainer tidak terputus di tengah jalan.
Alur Pematian Pod di Kubernetes: #
- Pod Diubah ke Status Terminating: Kubernetes menghapus IP Pod dari daftar Endpoint Service. Ingress dan kube-proxy mulai memperbarui tabel routing mereka agar tidak mengirimkan koneksi baru ke Pod tersebut.
- Eksekusi
preStopHook: Jika kita mengonfigurasipreStoplifecycle hook pada kontainer, Kubernetes akan menjalankan perintah tersebut terlebih dahulu. - Signal
SIGTERMDikirim: Kubernetes mengirimkan signalSIGTERMke proses utama (PID 1) di dalam kontainer. Aplikasi harus menangkap signal ini, berhenti menerima koneksi baru, menyelesaikan antrean request yang sedang berjalan, dan menutup koneksi database secara rapi. - Batas Waktu Toleransi (Grace Period): Kubernetes menunggu hingga batas waktu
terminationGracePeriodSeconds(default 30 detik) terlewati. - Signal
SIGKILLDikirim: Jika aplikasi belum mati setelah batas waktu terlewati, kernel host akan mengirimkanSIGKILLuntuk mematikan proses secara paksa.
flowchart TD
Start["Deployment Controller memicu Scale Down"] --> Step1["Status Pod diubah ke 'Terminating'"]
Step1 --> Step2["IP Pod dihapus dari Service EndpointSlice"]
subgraph Parallel ["Berjalan secara Paralel"]
Step3["Kube-proxy & Ingress update routing table (1-5 detik)"]
Step4["Kubelet memicu 'preStop' hook pada kontainer"]
end
Step2 --> Step3
Step2 --> Step4
Step3 --> Step5["Kubelet mengirimkan SIGTERM ke PID 1"]
Step4 --> Step5
Step5 --> Step6{"Apakah proses mati<br>sebelum Grace Period berakhir?"}
Step6 -- "Ya" --> EndSafe["Pod Terhapus Bersih"]
Step6 -- "Tidak" --> Step7["Kubelet mengirimkan SIGKILL secara paksa"]
Step7 --> EndForced["Pod Dihapus Paksa"]
style EndSafe stroke:#388e3c,stroke-width:2px
style EndForced stroke:#d32f2f,stroke-width:2px
[!IMPORTANT] Mengapa
preStophook dengansleepsering dibutuhkan? Proses sinkronisasi tabel perutean di seluruh node worker oleh kube-proxy membutuhkan waktu beberapa detik (propagation delay). Jika aplikasi langsung meresponsSIGTERMdengan menutup socket koneksi seketika, koneksi pengguna yang baru dikirimkan selama jeda propagasi tersebut akan gagal. MenerapkanpreStophook dengan perintahsleep 5memberikan waktu bagi tabel routing jaringan untuk terupdate sepenuhnya sebelum aplikasi mulai mematikan layanannya.
Anti-Pattern vs Solusi Terbaik #
Mari kita pelajari beberapa kesalahan konfigurasi Rolling Update di lingkungan produksi beserta perbaikan terbaiknya.
Anti-Pattern 1: Mengatur maxUnavailable Sebesar 100% pada Cluster Produksi
#
Menetapkan parameter maxUnavailable yang terlalu besar (atau sama dengan jumlah replika) untuk mempercepat rilis. Tindakan ini merusak fungsi dasar zero-downtime karena Kubernetes diizinkan untuk mematikan seluruh Pod lama sekaligus sebelum Pod baru siap.
# ✗ ANTI-PATTERN: Mengizinkan seluruh Pod mati bersamaan saat update
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 0
maxUnavailable: 100% # ← KRITIS: Seluruh Pod v1 dimatikan seketika, downtime total terjadi
Solusi Terbaik #
Gunakan batasan ketat dengan nilai maxUnavailable: 0 agar kapasitas minimal layanan tetap terjaga penuh.
# ✓ SOLUSI: Konfigurasi aman menjamin ketersediaan Pod
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 0 # ← Aman, Pod lama hanya dimatikan setelah Pod baru siap menerima trafik
Anti-Pattern 2: Tidak Mengonfigurasi preStop Hook untuk Aplikasi Web HTTP Traffic Tinggi
#
Saat rolling update berjalan, pengguna terkadang menerima error HTTP 502 Bad Gateway secara berkala (flapping). Hal ini terjadi karena kontainer langsung memproses pematian begitu menerima SIGTERM, padahal Ingress Controller masih mengarahkan request sisa ke Pod tersebut akibat keterlambatan sinkronisasi jaringan internal.
Solusi Terbaik #
Tambahkan preStop lifecycle hook yang melakukan penundaan (delay) singkat sebelum Kubelet mengirimkan SIGTERM ke aplikasi.
# ✓ SOLUSI: Menambahkan preStop hook untuk mitigasi propagation delay
spec:
containers:
- name: web-app
image: company/web-app:v2.1.0
lifecycle:
preStop:
exec:
# Memberikan waktu bagi kube-proxy / Ingress untuk menghapus IP Pod dari routing
command: ["/bin/sh", "-c", "sleep 10"]
terminationGracePeriodSeconds: 45 # Berikan waktu yang cukup (lebih lama dari sleep preStop)
Manifes Deployment Produksi Terbaik #
Berikut adalah contoh manifes Deployment siap produksi yang menerapkan strategi Rolling Update yang aman, lengkap dengan kontrol ketersediaan, probe kesehatan, dan shutdown teratur:
apiVersion: apps/v1
kind: Deployment
metadata:
name: billing-service
namespace: finance
labels:
app: billing-service
spec:
replicas: 4
# Menentukan toleransi waktu tunggu stabilitas Pod baru
minReadySeconds: 15
# Batas waktu timeout keseluruhan deployment (300 detik)
progressDeadlineSeconds: 300
# Jumlah riwayat ReplicaSet yang disimpan untuk rollback instan
revisionHistoryLimit: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Maksimal 1 Pod ekstra di atas 4 replika (total 5)
maxUnavailable: 0 # Selalu pastikan minimal ada 4 Pod siap menerima trafik
selector:
matchLabels:
app: billing-service
template:
metadata:
labels:
app: billing-service
spec:
terminationGracePeriodSeconds: 60 # Sesuai dengan durasi cleanup internal aplikasi
containers:
- name: billing-app
image: company/billing-app:v2.1.0
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1000m"
memory: "512Mi"
lifecycle:
preStop:
exec:
# Jeda agar trafik tidak dialihkan ke Pod yang akan mati ini
command: ["/bin/sh", "-c", "sleep 15"]
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 3
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 3
Panduan Perintah CLI untuk Manajemen Rollout #
Kita dapat mengontrol dan memantau jalannya proses Rolling Update secara interaktif menggunakan CLI kubectl:
1. Memantau Progress Deployment #
Untuk melihat status terkini secara real-time dari pembaruan Pod:
kubectl rollout status deployment/billing-service -n finance
# Output sukses: deployment "billing-service" successfully rolled out
2. Memeriksa Riwayat Revisi #
Setiap kali perubahan spec Pod disimpan, Kubernetes mencatatnya sebagai revisi baru:
kubectl rollout history deployment/billing-service -n finance
Untuk melihat detail spesifikasi dari revisi tertentu:
kubectl rollout history deployment/billing-service --revision=2 -n finance
3. Menghentikan Sementara dan Melanjutkan Rilis (Pause/Resume) #
Sangat berguna jika kita ingin melakukan modifikasi bertahap atau melakukan investigasi cepat di tengah-tengah proses rollout:
# Hentikan sementara rollout yang sedang berjalan
kubectl rollout pause deployment/billing-service -n finance
# Lanjutkan kembali rollout setelah investigasi selesai
kubectl rollout resume deployment/billing-service -n finance
4. Membatalkan Rilis (Rollback) #
Jika terdeteksi kegagalan sistem pada versi baru, kita dapat langsung membatalkannya dan kembali ke versi sebelumnya secara instan:
# Rollback ke revisi tepat sebelum revisi saat ini
kubectl rollout undo deployment/billing-service -n finance
# Rollback ke revisi spesifik berdasarkan nomor riwayat
kubectl rollout undo deployment/billing-service --to-revision=2 -n finance
Diagnosis Masalah Umum (Troubleshooting) #
Jika proses Rolling Update kita berhenti di tengah jalan (stuck), jalankan langkah diagnosis sistematis berikut:
-
Periksa Status Deployment:
kubectl describe deployment billing-service -n financePerhatikan bagian
Conditions. Jika terdapat pesanProgressDeadlineExceeded, artinya batas waktuprogressDeadlineSecondstelah terlewati karena ada kontainer yang gagal startup. -
Identifikasi ReplicaSet yang Terlibat:
kubectl get replicaset -n finance -l app=billing-serviceBandingkan kolom
DESIRED,CURRENT, danREADY. Jika ReplicaSet baru memiliki jumlahDESIREDyang tinggi tetapiREADYbernilai nol, masalah utama ada pada Pod versi baru. -
Temukan Pod yang Bermasalah:
kubectl get pods -n finance -l app=billing-serviceCari Pod dengan status selain
Runningatau yang memiliki nilai kolomREADY0/1. -
Investigasi Log dan Detail Pod:
# Periksa logs kontainer untuk mencari error stacktrace aplikasi kubectl logs <pod-name-baru> -n finance # Periksa events sistem untuk mencari kegagalan probe, kekurangan resource, atau pull image kubectl describe pod <pod-name-baru> -n finance
Akar Masalah Paling Sering Terjadi: #
ImagePullBackOff: Tag image salah ditulis, atau node worker tidak memiliki kredensial otorisasi untuk mengakses repositori registry kontainer privat.CrashLoopBackOff: Aplikasi mengalami crash sesaat setelah inisialisasi awal karena hilangnya variabel lingkungan (ConfigMap/Secret) yang dibutuhkan.- Kekurangan Resource Node (Pending status): Cluster tidak memiliki node worker yang memiliki kapasitas kosong CPU/Memory untuk menampung Pod tambahan (
maxSurge) baru.
Ringkasan #
- Pahami maxSurge & maxUnavailable — Gunakan kombinasi
maxSurge: 25%danmaxUnavailable: 0sebagai konfigurasi standar produksi untuk menjamin ketersediaan kapasitas penuh 100% selama rilis.- Readiness Probe wajib dipasang — Tanpa probe, Kubernetes akan mengarahkan trafik pengguna ke kontainer yang belum selesai melakukan inisialisasi awal.
- Gunakan minReadySeconds sebagai buffer — Jeda waktu tunggu tambahan setelah Pod siap membantu mendeteksi kegagalan startup tersembunyi sebelum seluruh Pod lama dimatikan.
- Gunakan preStop hook untuk graceful shutdown — Perintah
sleepsingkat di preStop hook memberikan waktu bagi jaringan kube-proxy untuk menyinkronkan tabel routing sebelum kontainer mati.- Pertahankan batas sejarah revisi — Atur properti
revisionHistoryLimituntuk membatasi jumlah ReplicaSet usang di cluster tetapi tetap menyisakan cadangan untuk rollback cepat.- Pantau status secara berkala — Manfaatkan perintah
kubectl rollout statuspada pipeline CI/CD kita untuk memvalidasi keberhasilan deployment sebelum menandai rilis selesai.
← Sebelumnya: Deployment Strategy Overview Berikutnya: Blue/Green Deployment →