Canary Deployment #
Meluncurkan fitur baru ke lingkungan produksi selalu menyimpan ketidakpastian. Meskipun kita telah melakukan pengujian menyeluruh di lingkungan Staging, perilaku sistem di bawah lalu lintas pengguna nyata yang heterogen dan masif sering kali memicu anomali yang tidak terduga. Jika kita menggunakan strategi Blue/Green, kita langsung mengekspos 100% pengguna ke versi baru setelah tombol cutover ditekan. Jika terjadi bug kritis yang lolos dari pengujian awal, seluruh pengguna aktif akan merasakan dampaknya sebelum kita sempat melakukan rollback.
Strategi Canary Deployment dirancang untuk mengatasi masalah ini dengan menerapkan prinsip pengiriman progresif (progressive delivery). Terinspirasi dari praktik penambang batu bara zaman dahulu yang membawa burung kenari (canary) ke dalam terowongan tambang untuk mendeteksi gas beracun secara dini, kita merilis versi aplikasi baru (v2) ke sebagian kecil Pod kontainer terlebih dahulu. Kita kemudian mengalihkan sebagian kecil lalu lintas pengguna asli (misalnya 2% atau 5%) ke Pod tersebut selagi memantau metrik performa aplikasi secara intensif. Jika versi Canary terbukti aman dan stabil, kita meningkatkan porsi lalu lintas secara bertahap hingga mencapai 100%.
Spektrum Implementasi Canary di Kubernetes #
Kita dapat menerapkan Canary Deployment di Kubernetes melalui beberapa tingkatan pendekatan, mulai dari metode manual sederhana berbasis manipulasi jumlah replika Pod hingga otomatisasi tingkat lanjut menggunakan controller khusus.
+-----------------------------------------------------------------------------+
| TINGKATAN IMPLEMENTASI CANARY: |
| |
| 1. Sederhana (L3/L4 Service Pod Ratio) |
| - Pembagian trafik kasar berdasarkan rasio jumlah Pod. |
| - Contoh: 9 Pod v1 + 1 Pod v2 = ~10% Trafik. |
| |
| 2. Menengah (L7 Ingress Controller Weighting) |
| - Pembagian trafik presisi di tingkat HTTP Proxy (Ingress). |
| - Contoh: NGINX Ingress annotations canary-weight: "5". |
| |
| 3. Canggih (Automated Progressive Delivery - Argo Rollouts) |
| - Otomatisasi penuh berbasis metrik Prometheus + auto-rollback. |
| - Evaluasi performa p99 latency & HTTP error rate per menit. |
+-----------------------------------------------------------------------------+
Pendekatan 1: Pembagian Trafik Berbasis Rasio Replika Pod (Layer 4) #
Pendekatan ini adalah metode paling dasar yang tidak memerlukan alat tambahan (tools) di luar Kubernetes bawaan. Kita membuat dua objek Deployment terpisah yang berbagi label identitas yang sama, sehingga sebuah Service global akan mendistribusikan trafik secara round-robin ke seluruh Pod dari kedua versi tersebut.
1. Manifes Deployment Stable (v1) — Menguasai 90% Trafik #
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-service-stable
namespace: production
spec:
replicas: 9 # ← 9 Pod aktif
selector:
matchLabels:
app: api-service
template:
metadata:
labels:
app: api-service
track: stable
spec:
containers:
- name: api
image: company/api-service:v1.0.0
ports:
- containerPort: 8080
2. Manifes Deployment Canary (v2) — Menguasai 10% Trafik #
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-service-canary
namespace: production
spec:
replicas: 1 # ← 1 Pod aktif
selector:
matchLabels:
app: api-service
template:
metadata:
labels:
app: api-service
track: canary
spec:
containers:
- name: api
image: company/api-service:v1.1.0 # Versi Baru
ports:
- containerPort: 8080
3. Manifes Service Pemersatu Trafik #
apiVersion: v1
kind: Service
metadata:
name: api-service-global
namespace: production
spec:
ports:
- port: 80
targetPort: 8080
selector:
app: api-service # ← Mencocokkan label 'app: api-service' dari kedua Deployment
Keterbatasan Utama Pendekatan ini: #
- Granularitas Kasar: Jika kita ingin mengalihkan hanya 1% trafik ke Canary, kita terpaksa harus menjalankan minimal 99 Pod Stable dan 1 Pod Canary. Hal ini memicu pemborosan resource infrastruktur yang sangat masif.
- Ketidakakuratan Distribusi: Karena perutean Service Kubernetes bekerja secara round-robin acak (kube-proxy), persentase trafik yang mengalir ke kontainer Canary tidak dijamin tepat berada di angka 10%.
Pendekatan 2: Perutean Presisi Menggunakan NGINX Ingress Weighting (Layer 7) #
Untuk mengatasi keterbatasan metode pembagian Pod di atas, kita dapat memanfaatkan kemampuan Layer 7 routing pada NGINX Ingress Controller. Dengan pendekatan ini, kita membuat dua objek Service mandiri (satu untuk Stable, satu untuk Canary) dan mendefinisikan Ingress tambahan yang memiliki anotasi kontrol berat (canary-weight).
flowchart LR
Traffic["Traffic Pengguna (api.company.com)"] --> Ingress["Ingress Controller"]
Ingress -->|"95% Trafik"| ServiceStable["Service Stable"] --> PodV1["Pod v1"]
Ingress -->|"5% Trafik"| ServiceCanary["Service Canary"] --> PodV2["Pod v2"]
1. Manifes Ingress Utama (Stable) #
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress-stable
namespace: production
spec:
ingressClassName: nginx
rules:
- host: api.company.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service-stable
port:
number: 80
2. Manifes Ingress Khusus Canary (Mengatur Pembagian Trafik) #
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress-canary
namespace: production
annotations:
# Menginstruksikan NGINX untuk memperlakukan Ingress ini sebagai rute Canary
nginx.ingress.kubernetes.io/canary: "true"
# Mengalihkan tepat 5% lalu lintas HTTP ke Service Canary
nginx.ingress.kubernetes.io/canary-weight: "5"
spec:
ingressClassName: nginx
rules:
- host: api.company.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service-canary
port:
number: 80
Kita dapat memperbarui nilai anotasi nginx.ingress.kubernetes.io/canary-weight secara dinamis (misalnya menaikkan ke "10", "25", atau "50") melalui skrip pipeline CI/CD tanpa perlu mengubah kapasitas replika Pod aplikasi.
Pendekatan 3: Otomatisasi Progressive Delivery dengan Argo Rollouts #
Di lingkungan produksi berskala industri, mengelola transisi persentase trafik dan memantau metrik secara manual adalah tindakan yang rawan kesalahan (error-prone). Argo Rollouts adalah Custom Controller Kubernetes yang menggantikan objek Deployment bawaan dengan objek baru bernama Rollout.
Argo Rollouts mengotomatiskan seluruh siklus Canary: menaikkan trafik secara bertahap, memantau server Prometheus untuk memeriksa tingkat keberhasilan kueri (HTTP success rate), dan secara otomatis memicu pembatalan rilis (rollback) instan jika performa Canary memburuk.
flowchart TD
Start["Deployment Baru via GitOps (v2)"] --> Step1["Argo Rollouts set weight ke 5%"]
Step1 --> Step2["Tunggu 10 menit (Observasi Metrik)"]
Step2 --> Dec1{"Apakah query Prometheus<br>menunjukkan error rate < 1%?"}
Dec1 -- "Tidak (Anomali)" --> RollbackAuto["ROLLBACK OTOMATIS INSTAN<br/>'(Set weight ke 0%, hapus v2)'"]
Dec1 -- "Ya (Normal)" --> Step3["Scale Up weight ke 25%"]
Step3 --> Step4["Tunggu 10 menit (Observasi Metrik)"]
Step4 --> Dec2{"Apakah query Prometheus<br>menunjukkan error rate < 1%?"}
Dec2 -- "Tidak" --> RollbackAuto
Dec2 -- "Ya" --> Step5["Scale Up weight ke 100% (Rilis Selesai)"]
style RollbackAuto stroke:#d32f2f,stroke-width:2px
style Step5 stroke:#388e3c,stroke-width:2px
1. Manifes Rollout (Menggantikan Deployment) #
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: order-api
namespace: production
spec:
replicas: 10
selector:
matchLabels:
app: order-api
template:
metadata:
labels:
app: order-api
spec:
containers:
- name: order-api
image: company/order-api:v2.0.0 # Versi baru kandidat Canary
ports:
- containerPort: 8080
strategy:
canary:
canaryService: order-api-canary-svc # Service rujukan Canary
stableService: order-api-stable-svc # Service rujukan Stable
trafficRouting:
nginx:
stableIngress: order-api-ingress # Ingress utama yang akan dimanipulasi
steps:
- setWeight: 5
# Menunggu selama 5 menit untuk observasi metrik awal
- pause: {duration: 5m}
- analysis:
# Menjalankan evaluasi metrik otomatis berdasarkan AnalysisTemplate
templates:
- templateName: http-error-analysis
- setWeight: 20
- pause: {duration: 10m}
- analysis:
templates:
- templateName: http-error-analysis
- setWeight: 50
- pause: {} # Pause tanpa durasi = Menunggu persetujuan manual (manual approval gate)
- setWeight: 100
2. Manifes AnalysisTemplate (Kriteria Sukses Rilis) #
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: http-error-analysis
namespace: production
spec:
metrics:
- name: success-rate
interval: 1m # Cek metrik setiap 1 menit
successCondition: result[0] >= 0.995 # Sukses rate HTTP wajib >= 99.5%
failureLimit: 3 # Toleransi maksimal 3 kali kegagalan beruntun sebelum rollback
provider:
prometheus:
address: http://prometheus-k8s.monitoring:9090
query: |
sum(rate(http_requests_total{app="order-api", status!~"5.."}[2m]))
/
sum(rate(http_requests_total{app="order-api"}[2m]))
Metrik Kritis Pemantauan Canary Release #
Menjalankan Canary tanpa metrik observabilitas yang memadai adalah tindakan berbahaya. Kita harus mengidentifikasi metrik kunci (Golden Signals) yang benar-benar membedakan kegagalan versi Canary dari kebisingan (noise) trafik kluster biasa.
1. HTTP Error Rate (Persentase 5xx Response) #
Metrik ini paling krusial untuk langsung menangkap kegagalan logika internal server atau kerusakan integrasi database. Bandingkan persentase status HTTP 5xx pada kontainer Canary terhadap kontainer Stable.
- Query PromQL:
sum(rate(nginx_ingress_controller_requests{status=~"5.."}[5m]))
2. Latency p95 / p99 (Ekor Latensi) #
Jangan gunakan metrik rata-rata (average latency) karena degradasi performa yang dialami sebagian kecil pengguna sering kali tertutupi oleh nilai rata-rata global. Gunakan persentil ke-95 atau ke-99 untuk mendeteksi latensi ekstrim.
- Query PromQL:
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
3. Resource Saturation (Saturasi CPU/Memory) #
Versi baru mungkin memiliki bug kebocoran memori (memory leak) lambat yang tidak terdeteksi saat inisialisasi awal. Amati peningkatan konsumsi RAM dan frekuensi terjadinya pematian kontainer akibat kehabisan memori (OOMKilled events).
Pentingnya Signifikansi Statistik dan Volume Trafik #
Berapa lama waktu observasi yang ideal untuk masing-masing fase Canary? Jawabannya sangat bergantung pada volume trafik transaksi (throughput) aplikasi kita.
- Trafik Tinggi (e.g., > 1000 request per detik): Kita mendapatkan ukuran sampel data yang cukup secara statistik hanya dalam waktu 5 hingga 10 menit pemantauan.
- Trafik Rendah (e.g., < 5 request per detik): Data metrik tidak memiliki nilai signifikansi statistik yang memadai dalam 10 menit. Bug mungkin saja tidak terdeteksi karena tidak ada pengguna yang memicu endpoint bermasalah selama masa observasi. Pada skenario ini, kita harus memperpanjang durasi Canary (misalnya hingga 12 atau 24 jam) atau menggunakan teknik pengalihan trafik berdasarkan rute spesifik (header routing) untuk menguji fungsi secara terarah.
Anti-Pattern vs Solusi Terbaik #
Mari kita pelajari kesalahan umum saat merancang Canary Deployment di kluster Kubernetes beserta perbaikan terbaiknya.
Anti-Pattern 1: Canary Tanpa Sticky Sessions (Trafik Flapping) #
Meluncurkan Canary pada aplikasi web e-commerce tanpa mengonfigurasi persistensi sesi (session affinity) di level Ingress. Pengguna yang sedang melakukan checkout akan dialihkan secara acak antara Pod v1 (Stable) dan Pod v2 (Canary) pada setiap klik halaman. Jika v2 memiliki struktur session schema yang berbeda, pengguna akan mendadak ter-logout atau mengalami kegagalan keranjang belanja (cart loss).
Solusi Terbaik #
Gunakan fitur Canary Affinity pada Ingress Controller. Hal ini memaksa Ingress untuk mengirimkan cookie khusus ke peramban (browser) pengguna setelah mereka pertama kali dialihkan ke rute Canary, menjamin bahwa transaksi berikutnya dari pengguna tersebut akan selalu mendarat di versi Canary yang sama.
# ✓ SOLUSI: Menggunakan Canary Cookie untuk persistensi sesi
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress-canary
namespace: production
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
# Memaksa persistensi sesi berbasis cookie
nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"
nginx.ingress.kubernetes.io/canary-by-cookie: "always"
spec:
# ... spec Backend Service ...
Anti-Pattern 2: Mengabaikan Pengujian Downstream Dependencies (Blast Radius Kebocoran Database) #
Menjalankan Canary untuk microservice A yang secara dinamis menulis data baru ke database bersama (shared database). Kode v2 ternyata menulis data dalam format biner yang salah. Meskipun microservice A versi Canary tampak berjalan normal tanpa error HTTP 5xx, database kita terlanjur tercemar data rusak. Hal ini mengakibatkan microservice B (Downstream Service) mengalami crash massal di sisi lain.
Solusi Terbaik #
Aktifkan monitoring tingkat sistem secara holistik. Analisis metrik kueri database (seperti locked rows, active transactions) dan amati log error downstream service selama proses promosi Canary berlangsung. Gunakan skema arsitektur data backward-compatible secara disiplin.
Manifes Lengkap Produksi Canary (NGINX Ingress Annotations) #
Berikut adalah contoh manifes produksi utuh yang menerapkan Canary deployment berbasis NGINX Ingress Controller untuk mengalihkan tepat 10% trafik pengguna ke versi baru:
# 1. Service untuk Aplikasi Stabil (Stable)
apiVersion: v1
kind: Service
metadata:
name: catalog-service-stable
namespace: product-catalog
spec:
ports:
- port: 80
targetPort: 8080
selector:
app: catalog-app
version: stable
---
# 2. Service untuk Aplikasi Canary (Versi Baru)
apiVersion: v1
kind: Service
metadata:
name: catalog-service-canary
namespace: product-catalog
spec:
ports:
- port: 80
targetPort: 8080
selector:
app: catalog-app
version: canary
---
# 3. Ingress Utama (Mengarahkan 90% Trafik Normal)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: catalog-ingress-stable
namespace: product-catalog
spec:
ingressClassName: nginx
rules:
- host: catalog.company.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: catalog-service-stable
port:
number: 80
---
# 4. Ingress Canary (Mengarahkan 10% Trafik Khusus ke Canary Service)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: catalog-ingress-canary
namespace: product-catalog
annotations:
nginx.ingress.kubernetes.io/canary: "true"
# Membagi trafik tepat 10% secara presisi di level NGINX Proxy
nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
ingressClassName: nginx
rules:
- host: catalog.company.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: catalog-service-canary
port:
number: 80
Checklist Ulasan Kesiapan Canary #
Gunakan checklist audit berikut untuk memastikan pipa rilis Canary kita telah siap sebelum meluncurkan rilis di produksi:
PERSISTENSI SESI & KONEKSI:
□ Cookie atau header persistensi sesi (session affinity) telah dikonfigurasi untuk mencegah trafik flapping.
□ Aplikasi Canary menggunakan namespace dan Service yang terisolasi untuk memudahkan pelacakan.
□ Downstream service telah dipastikan tidak terpengaruh oleh tipe payload baru dari versi Canary.
MONITORING & PROMETHEUS METRICS:
□ Kueri PromQL untuk menghitung HTTP error rate dan latensi p99 telah divalidasi keakuratannya.
□ Threshold deteksi anomali telah ditentukan (e.g., error rate maksimal 0.5% selama rilis).
□ Interval kueri metrik diatur seimbang (tidak terlalu sering untuk menghindari beban berlebih pada server Prometheus).
PROSEDUR ROLLBACK & PROMOTE:
□ Skrip pipeline CI/CD siap menaikkan persentase berat (canary-weight) secara bertahap.
□ Batas waktu timeout kegagalan promosi (failure limit) telah ditetapkan di Argo Rollouts.
□ Prosedur pembersihan (cleanup) Ingress Canary di akhir rilis sukses telah dikonfigurasi secara otomatis.
Ringkasan #
- Minimalkan blast radius rilis — Canary deployment melindungi cluster produksi dengan membatasi paparan bug versi baru hanya pada subset kecil pengguna awal (misalnya 2-5% trafik).
- Gunakan Ingress weighting untuk akurasi — Hindari pembagian trafik manual menggunakan rasio replika Pod; manfaatkan anotasi
canary-weightpada Ingress Controller untuk pembagian persentase trafik yang presisi.- Automasi dengan Argo Rollouts — Gunakan CRD
Rolloutuntuk progressive delivery terotomatisasi penuh yang memantau Prometheus metrics dan melakukan auto-rollback jika terjadi anomali.- Amati metrik persentil p99 — Jangan tertipu oleh nilai latensi rata-rata (average latency); amati latensi p99 untuk menangkap kelambatan ekstrim pada request pengguna.
- Terapkan Canary Session Affinity — Konfigurasikan cookie-based routing untuk menjaga konsistensi sesi pengguna aktif agar tidak dialihkan antar-Pod secara acak.
- Sesuaikan durasi berdasarkan throughput — Aplikasi bertrafik rendah membutuhkan masa observasi Canary yang lebih panjang demi mendapatkan signifikansi statistik yang valid.
← Sebelumnya: Blue/Green Deployment Berikutnya: Recreate Deployment →