Rollback Strategy #
Kegagalan peluncuran kode baru di lingkungan produksi bukanlah pertanyaan tentang apakah hal itu akan terjadi, melainkan kapan. Di bawah lalu lintas dunia nyata yang kompleks, bug memori bocor (memory leak), degradasi kueri database, atau kegagalan integrasi API eksternal dapat muncul sewaktu-waktu meskipun aplikasi telah lolos uji di lingkungan penjaminan mutu (Quality Assurance). Selisih waktu yang dibutuhkan tim operasional untuk memulihkan layanan dari kondisi rusak kembali ke kondisi stabil—dikenal dengan metrik MTTR (Mean Time To Recovery)—merupakan pembeda utama antara insiden kecil yang berlangsung 5 menit dengan pemadaman sistem (outage) masif selama 2 jam yang merugikan bisnis.
Kubernetes menyediakan infrastruktur bawaan yang sangat tangguh untuk membatalkan rilis yang gagal (rollback). Namun, mengandalkan perintah rollback bawaan secara membabi buta tanpa memahami struktur riwayat ReplicaSet, pengaruh skema database bersama, serta integrasi metrik observabilitas dapat memperburuk situasi kegagalan. Artikel ini membedah arsitektur riwayat revisi Kubernetes, taktik rollback untuk berbagai strategi rilis, otomatisasi pembatalan berbasis metrik, serta mitigasi inkonsistensi database saat rollback dilakukan.
Arsitektur Riwayat Revisi Kubernetes #
Deployment Controller di Kubernetes mengelola pembaruan melalui objek ReplicaSet. Setiap kali kita memperbarui spesifikasi Pod pada manifes Deployment (misalnya mengganti tag image kontainer), Deployment Controller tidak menghapus ReplicaSet lama.
Controller akan membuat ReplicaSet baru, menaikkan replikanya (scale up), dan secara paralel menurunkan replika ReplicaSet lama ke angka nol (scale down).
Deployment (order-service)
├── ReplicaSet v2 (Aktif - replicas: 4) ──► Pod 1 (v2), Pod 2 (v2), Pod 3 (v2), Pod 4 (v2)
└── ReplicaSet v1 (Non-Aktif - replicas: 0) [Riwayat disimpan untuk Rollback]
ReplicaSet lama yang telah dinonaktifkan (memiliki status replicas: 0) tetap dipertahankan di dalam database etcd cluster. Objek ReplicaSet ini bertindak sebagai snapshot cadangan yang memuat seluruh definisi Pod template (termasuk versi image kontainer lama, variabel lingkungan lama, dan konfigurasi volume lama) yang siap digunakan kembali jika kita memicu perintah rollback.
Parameter revisionHistoryLimit
#
Berapa banyak snapshot ReplicaSet lama yang disimpan oleh Kubernetes dikendalikan oleh properti revisionHistoryLimit di level spesifikasi Deployment:
spec:
# Menyimpan 10 revisi ReplicaSet terakhir (default: 10 jika tidak dikonfigurasi)
revisionHistoryLimit: 10
[!WARNING] Risiko Nilai Ekstrim: Jangan pernah menetapkan
revisionHistoryLimit: 0di lingkungan produksi. Nilai nol akan menghapus seluruh ReplicaSet lama seketika setelah deployment selesai, yang meniadakan kemampuan kita untuk melakukan rollback instan via API Kubernetes. Sebaliknya, menetapkan nilai terlalu besar (misalnya100) akan membebani database etcd cluster dengan ratusan objek usang yang menurunkan performa control plane cluster. Rentang nilai5hingga10adalah standar industri yang ideal.
Alur Keputusan Penanganan Insiden (Rollback Decision Loop) #
Ketika tim operasional mendeteksi adanya anomali performa pasca-rilis, langkah penanganan harus mengikuti bagan alur keputusan terstruktur berikut guna meminimalkan durasi pemadaman:
flowchart TD
Start["Deteksi Anomali Pasca-Rilis"] --> Dec1{"Apakah rilis baru melibatkan<br>perubahan skema database<br>'(Database Migration)'?"}
Dec1 -- "Tidak" --> ExecRollback["Jalankan Rollback Instan<br>'(kubectl rollout undo)'"]
Dec1 -- "Ya" --> Dec2{"Apakah skema database baru<br>kompatibel dengan kode lama v1<br>'(Backward Compatible)'?"}
Dec2 -- "Ya" --> ExecRollback
Dec2 -- "Tidak" --> Dec3{"Apakah downtime lebih berisiko<br>daripada memperbaiki kode langsung<br>'(Fix Forward)'?"}
Dec3 -- "Ya (Downtime Sangat Kritis)" --> FixForward["Terapkan Pola Fix-Forward<br>'(Rilis hotfix v2.1 secepatnya)'"]
Dec3 -- "Tidak" --> DBReverse["Jalankan Skrip Database Rollback,<br>lalu rollback aplikasi ke v1"]
ExecRollback --> Monitor["Pantau SLA & Error Rate hingga Stabil"]
FixForward --> Monitor
DBReverse --> Monitor
style ExecRollback stroke:#388e3c,stroke-width:2px
style FixForward stroke:#f57c00,stroke-width:2px
style DBReverse stroke:#d32f2f,stroke-width:2px
Mekanisme Eksekusi Rollback Berdasarkan Strategi Rilis #
Cara kita memicu pembatalan rilis berbeda-beda tergantung pada strategi deployment yang kita pilih saat awal perancangan arsitektur:
1. Rolling Update Rollback (Metode Gradual) #
Pada strategi Rolling Update, proses rollback bekerja secara bertahap terbalik. Kubernetes akan membuat ulang Pod lama (v1) satu per satu dan mematikan Pod baru (v2) secara perlahan.
# 1. Periksa daftar riwayat revisi yang tersedia
kubectl rollout history deployment/order-service -n production
# 2. Periksa spesifikasi detail di revisi tertentu (misalnya revisi 2)
kubectl rollout history deployment/order-service --revision=2 -n production
# 3. Eksekusi rollback ke revisi tepat sebelum revisi saat ini
kubectl rollout undo deployment/order-service -n production
# 4. Atau eksekusi rollback ke revisi spesifik berdasarkan nomor riwayat
kubectl rollout undo deployment/order-service --to-revision=2 -n production
# 5. Pantau jalannya pemulihan Pod
kubectl rollout status deployment/order-service -n production
2. Blue/Green Rollback (Metode Instan) #
Rollback pada strategi Blue/Green adalah yang paling cepat dan aman di produksi. Kita tidak perlu membuat ulang atau merestart kontainer apa pun. Kita hanya perlu menginstruksikan Service produksi utama untuk mengalihkan rujukan label selector kembali ke lingkungan Blue (v1) yang saat ini dalam status siaga (standby).
# Ubah selector Service secara atomik kembali ke warna Blue (hanya butuh waktu milidetik)
kubectl patch service order-service-prod -n production \
-p '{"spec":{"selector":{"app":"order-service","color":"blue"}}}'
3. Canary Rollback (Metode Terkontrol) #
Jika kita menggunakan Canary deployment (misalnya dengan Argo Rollouts), kita dapat menghentikan proses rilis secara instan begitu terdeteksi anomali pada subset kecil pengguna awal. Burung kenari ditarik kembali dari terowongan dengan cara menghapus Pod Canary atau memotong alokasi trafiknya ke angka nol.
# Perintah membatalkan rilis Canary menggunakan CLI Argo Rollouts
kubectl argo rollouts abort order-service -n production
# Kembalikan status internal Rollout ke versi stabil sebelumnya
kubectl argo rollouts undo order-service -n production
Otomatisasi Rollback Berbasis Metrik (Metric-Driven Auto-Rollback) #
Mengandalkan tindakan manusia untuk mendeteksi kegagalan rilis dan mengetik perintah rollback secara manual memiliki kelemahan kritis: lambat dan rawan bias. Di lingkungan skala besar, kita harus membangun sistem otomatisasi yang mendeteksi kegagalan dan melakukan rollback tanpa intervensi manusia.
Tahap 1: Deteksi Kegagalan Infrastruktur Dasar (Native Kubernetes) #
Kubernetes dapat mendeteksi kegagalan inisialisasi kontainer secara otomatis menggunakan parameter progressDeadlineSeconds. Jika Pod baru tidak pernah berhasil melewati readinessProbe dalam batas waktu tersebut, Kubernetes akan menandai status Deployment sebagai Failed.
spec:
# Batas waktu maksimal rollout harus selesai (300 detik)
progressDeadlineSeconds: 300
template:
spec:
containers:
- name: app
readinessProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 3 # 3 kali gagal berturut-turut = Pod tidak sehat
Meskipun Kubernetes dapat menghentikan (pause) proses rollout yang macet secara otomatis, Kubernetes tidak melakukan rollback otomatis ke versi lama secara native. Pod lama yang tersisa tetap berjalan, tetapi proses rilis terhenti menggantung.
Tahap 2: Otomatisasi Penuh Berbasis Observabilitas (Argo Rollouts) #
Untuk mencapai otomatisasi rollback yang sesungguhnya berdasarkan performa logika aplikasi (seperti tingkat kesalahan transaksi), kita mengintegrasikan Argo Rollouts dengan kueri metrik dari server Prometheus.
sequenceDiagram
participant Prom as Prometheus Server
participant Controller as Argo Rollouts Controller
participant API as Kubernetes API Server
Loop Cek Metrik Setiap 1 Menit
Controller->>Prom: Query HTTP Success Rate order-service
Prom-->>Controller: Mengembalikan Nilai (e.g., 94.2% Success Rate)
End
Note over Controller: Anomali Terdeteksi!<br>(Success Rate < Threshold 99%)
Controller->>API: Pemicu Abort & Rollback (Exit Code 0)
API->>API: Kembalikan routing Service ke Stable Pods
Note over Controller: Notifikasi Tim: Rollback Sukses Eksekusi
Manifes di bawah ini menguraikan konfigurasi AnalysisTemplate yang secara otomatis membatalkan rilis Canary jika tingkat kesuksesan transaksi HTTP turun di bawah 99%:
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: auto-rollback-rules
namespace: production
spec:
metrics:
- name: http-success-rate
interval: 1m
# Evaluasi metrik selama 10 menit
successCondition: result[0] >= 0.99
# Jika kueri gagal mengembalikan kondisi sukses sebanyak 2 kali, picu rollback
failureLimit: 2
provider:
prometheus:
address: http://prometheus-operated.monitoring.svc.cluster.local:9090
query: |
sum(rate(http_requests_total{app="order-service",status!~"5.."}[2m]))
/
sum(rate(http_requests_total{app="order-service"}[2m]))
Mitigasi Masalah Database Saat Rollback #
Tantangan tersulit dalam proses rollback di produksi bukanlah memulihkan kode aplikasi stateless, melainkan menangani dampak perubahan data pada database (stateful store).
Skenario A: Rollback Pasca Migrasi Additive (Aman) #
Misalkan kita menambahkan kolom baru bernama phone_number pada rilis v2. Ketika bug ditemukan di v2 dan kita memutuskan melakukan rollback aplikasi ke v1:
- Analisis: Kode v1 tidak mengetahui keberadaan kolom
phone_numberdan hanya akan mengabaikannya. Struktur kolom baru tetap ada di database, namun nilainya kosong (null) atau berisi default. - Keputusan: Aman dilakukan. Kita dapat melakukan rollback aplikasi secara instan. Pembersihan kolom yang tidak digunakan di database dapat dilakukan belakangan hari setelah kondisi benar-benar stabil.
Skenario B: Rollback Pasca Migrasi Destructive (Sangat Berbahaya) #
Misalkan kita menghapus kolom lama bernama user_address pada rilis v2 karena menganggap seluruh data telah bermigrasi ke tabel baru. Ketika bug kritis ditemukan di v2 dan kita memaksa rollback aplikasi ke v1:
- Analisis: Pod v1 yang baru saja menyala akan mencoba menjalankan kueri kaku
SELECT user_address FROM users. Karena kolom tersebut telah dihapus secara fisik dari disk database, seluruh kueri v1 akan menghasilkan error database fatal. - Keputusan: Jangan lakukan rollback aplikasi secara langsung.
Taktik Penanganan Skenario Destructive: #
- Pendekatan Reverse Migration (Rollback Database Dulu):
Sebelum memulihkan aplikasi ke v1, jalankan skrip migrasi database pemulihan (down migration) untuk membuat ulang kolom
user_addressdan memulihkan data dari backup terakhir.# 1. Jalankan Job Kubernetes pemulihan database kubectl apply -f database-restore-job.yaml # 2. Setelah database siap, rollback aplikasi ke v1 kubectl rollout undo deployment/order-service -n production - Pendekatan Fix-Forward (Lebih Direkomendasikan): Jika volume transaksi sangat tinggi dan risiko kehilangan data akibat reverse migration terlalu besar, pilihan terbaik adalah tidak melakukan rollback. Tim developer harus segera membuat perbaikan (hotfix) langsung pada kode v2, membuild image baru (v2.1.0-hotfix), dan melakukan push deployment ke depan (fix forward) untuk menimpa versi v2 yang rusak.
Anti-Pattern vs Solusi Terbaik #
Mari kita pelajari beberapa kesalahan fatal terkait strategi rollback di produksi beserta solusi terbaiknya.
Anti-Pattern 1: Melakukan Rollback Tanpa Mencatat Log Alasan Perubahan (Change Cause) #
Melakukan deployment atau rollback secara berulang-ulang tanpa memberikan anotasi atau dokumentasi apa pun pada riwayat revisi. Ketika tim operasional melakukan investigasi pasca-insiden (post-mortem), riwayat revisi Kubernetes hanya menampilkan daftar angka mati yang membingungkan tanpa keterangan kontekstual.
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none> # ← Membingungkan: Mana revisi yang stabil? Apa penyebab perubahan?
Solusi Terbaik #
Gunakan anotasi kubernetes.io/change-cause untuk mencatat riwayat komit Git, versi rilis, atau alasan modifikasi setiap kali melakukan deployment.
# ✓ SOLUSI: Berikan anotasi sebab perubahan saat merilis spesifikasi baru
kubectl annotate deployment/order-service \
kubernetes.io/change-cause="Upgrade to v1.2.0 - commit hash 8f8d2f1" \
-n production
Anti-Pattern 2: Melakukan Rollback via GitOps dengan kubectl rollout undo #
Menggunakan perintah manual kubectl rollout undo langsung pada cluster yang dikelola oleh GitOps engine (seperti ArgoCD).
Konsekuensi #
ArgoCD akan mendeteksi adanya ketidakcocokan (drift) antara keadaan cluster (yang telah diturunkan ke v1 oleh perintah manual kita) dengan keadaan repositori Git (yang masih menunjuk ke versi rusak v2). Dalam hitungan detik, ArgoCD secara otomatis akan menimpa (auto-sync) perubahan manual kita dan mendeploy kembali versi rusak v2 ke cluster, menyebabkan loop pemadaman layanan berulang-ulang.
Solusi Terbaik #
Di lingkungan GitOps, satu-satunya cara melakukan rollback yang aman adalah dengan melakukan git revert pada commit manifes di repositori Git. Biarkan GitOps operator mendeteksi commit revert tersebut dan mengembalikan cluster ke revisi stabil secara teratur.
# ✓ SOLUSI: Alur kerja rollback GitOps yang aman
git revert HEAD # Membuat commit pembalik rilis baru di Git
git push origin main
# ArgoCD mendeteksi commit push baru, menyelaraskan cluster kembali ke v1 secara otomatis
Manifes Lengkap Produksi (Konfigurasi Rollback Aman) #
Berikut adalah contoh manifes Deployment siap produksi yang dikonfigurasi untuk memfasilitasi deteksi kegagalan dan rollback instan secara aman:
apiVersion: apps/v1
kind: Deployment
metadata:
name: auth-processor
namespace: security
annotations:
# Pencatatan awal alasan rilis
kubernetes.io/change-cause: "Inisialisasi rilis stabil v1.0.0"
spec:
replicas: 3
# Jeda waktu tunggu pemantauan stabilitas sebelum rilis dianggap selesai
minReadySeconds: 20
# Batas waktu deteksi kegagalan startup (5 menit)
progressDeadlineSeconds: 300
# Menyimpan riwayat 10 ReplicaSet lama untuk rollback instan
revisionHistoryLimit: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: auth-processor
template:
metadata:
labels:
app: auth-processor
spec:
terminationGracePeriodSeconds: 30
containers:
- name: auth-app
image: company/auth-app:v1.0.0
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
readinessProbe:
httpGet:
path: /healthz/ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 3
Checklist Audit Rencana Rollback Produksi #
Gunakan checklist berikut untuk memvalidasi kesiapan penanganan insiden dan pembatalan rilis di cluster kita:
PERSIAPAN RIWAYAT & METADATA:
□ Nilai 'revisionHistoryLimit' diatur minimal 5 (tidak boleh 0).
□ Anotasi 'change-cause' selalu diperbarui pada setiap pipeline CI/CD rilis baru.
□ Runbook terdokumentasi dengan jelas membedakan alur rollback Kubernetes biasa vs GitOps.
DETEKSI & VALIDASI OTOMATIS:
□ Parameter 'progressDeadlineSeconds' terkonfigurasi untuk mendeteksi deployment stuck.
□ Alerting Prometheus disiapkan untuk mendeteksi anomali pasca-transisi rilis (error HTTP 5xx spike).
□ Skenario auto-rollback dengan Argo Rollouts telah disimulasikan sukses di lingkungan staging.
INTEGRITAS DATA & DATABASE:
□ Tim developer memastikan tidak ada migrasi destructive database yang digabungkan langsung dengan rilis kode baru.
□ Skrip rollback skema database (Down Migration) siap dieksekusi jika terjadi kegagalan kritis.
□ Mekanisme pemulihan data (backup restore) teruji memiliki waktu eksekusi (RTO) di bawah batas toleransi bisnis.
Ringkasan #
- Pertahankan riwayat revisi — Atur
revisionHistoryLimitminimal ke angka 5 untuk memastikan Kubernetes menyimpan snapshot ReplicaSet lama yang dibutuhkan sebagai cadangan rollback.- Gunakan Git Revert pada GitOps — Jangan jalankan
kubectl rollout undolangsung di cluster yang dikelola oleh ArgoCD atau Flux; lakukan pembatalan rilis dengan membalikkan commit di repositori Git.- Terapkan automated rollback berbasis metrik — Integrasikan Argo Rollouts dengan server Prometheus untuk memicu pembatalan rilis secara otomatis saat tingkat kesalahan transaksi HTTP melampaui batas toleransi.
- Pahami risiko rollback database — Rollback aplikasi ke versi lama (v1) pasca migrasi database destructive akan memicu crash loop masif jika kolom yang dibutuhkan v1 telah terhapus secara fisik.
- Gunakan Fix-Forward untuk kasus database kritis — Jika memulihkan database ke skema lama terlalu berisiko terhadap kehilangan data, rilis hotfix perbaikan langsung ke depan (fix forward) adalah pilihan yang lebih aman.
- Patuhi progressDeadlineSeconds — Konfigurasi batas waktu timeout rollout agar Kubernetes dapat menandai status deployment yang macet secara otomatis guna memicu respons cepat tim operator.
← Sebelumnya: Database Migration Strategy Berikutnya: GitOps →