Panduan Lengkap Canary Deployment di Kubernetes
Pendahuluan
Bayangkan kamu sedang membangun platform e-commerce seperti Tokopedia atau Shopee, dan timmu baru saja selesai mengembangkan fitur pembayaran baru. Risiko meluncurkan langsung ke semua pengguna tentu sangat tinggi — satu bug kecil bisa membuat ribuan transaksi gagal. Di sinilah Canary Deployment hadir sebagai solusi.
Canary Deployment adalah strategi rilis bertahap di mana versi baru aplikasi (canary) diluncurkan hanya kepada sebagian kecil pengguna terlebih dahulu. Jika metrik menunjukkan hasil yang baik, traffic secara bertahap dipindahkan ke versi baru. Jika ada masalah, rollback dilakukan sebelum dampak meluas.
Nama ini berasal dari praktik lama penambang batu bara yang membawa burung kenari ke dalam tambang — jika kenari pingsan karena gas beracun, penambang tahu mereka harus segera keluar. Dalam dunia software, “kenari” kita adalah sekelompok kecil pengguna nyata yang memverifikasi bahwa versi baru aman sebelum diluncurkan ke semua orang.
Jika kamu sudah familiar dengan pipeline CI/CD dasar menggunakan Tutorial GitHub Actions untuk Pemula: Menjalankan Workflow Pertama Anda, artikel ini akan membawa pemahamanmu ke level berikutnya dengan implementasi deployment strategis di Kubernetes.
Prasyarat: Menyiapkan Environment Kubernetes
Sebelum mulai, pastikan environment-mu sudah siap:
- Kubernetes cluster (lokal:
minikubeataukind, atau cloud: GKE, EKS, AKS) - kubectl terinstal dan terkonfigurasi
- Helm v3+ (opsional, untuk chart-based deployment)
- Pengetahuan dasar tentang
DeploymentdanServicedi Kubernetes
Verifikasi koneksi cluster:
kubectl cluster-info
kubectl get nodes
Buat namespace khusus untuk eksperimen ini:
kubectl create namespace canary-demo
kubectl config set-context --current --namespace=canary-demo
Strategi Canary Deployment: Manual vs. Otomatis
Ada dua pendekatan utama dalam canary deployment di Kubernetes:
| Aspek | Manual (Native K8s) | Otomatis (Argo Rollouts / Flagger) |
|---|---|---|
| Kontrol traffic | Berbasis rasio replica | Berbasis persentase presisi |
| Analisis metrik | Manual via Prometheus | Otomatis dengan threshold |
| Rollback | Manual | Otomatis jika metrik gagal |
| Kompleksitas setup | Rendah | Sedang–Tinggi |
| Cocok untuk | Tim kecil, proyek awal | Tim besar, traffic tinggi |
Untuk artikel ini, kita akan membahas keduanya dimulai dari pendekatan native Kubernetes.
Implementasi Canary Deployment dengan Service Manifest
Langkah 1: Deploy Versi Stabil (Stable)
Buat deployment versi v1 sebagai baseline:
# stable-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-stable
labels:
app: myapp
version: stable
spec:
replicas: 9
selector:
matchLabels:
app: myapp
version: stable
template:
metadata:
labels:
app: myapp
version: stable
spec:
containers:
- name: myapp
image: myapp:v1.0.0
ports:
- containerPort: 8080
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
Langkah 2: Deploy Versi Canary
# canary-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-canary
labels:
app: myapp
version: canary
spec:
replicas: 1 # ~10% dari total (1 dari 10 pod)
selector:
matchLabels:
app: myapp
version: canary
template:
metadata:
labels:
app: myapp
version: canary
spec:
containers:
- name: myapp
image: myapp:v2.0.0 # Versi baru
ports:
- containerPort: 8080
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
Langkah 3: Buat Service Tunggal
Service menggunakan label app: myapp tanpa memilah versi, sehingga traffic otomatis terdistribusi proporsional berdasarkan jumlah replica:
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp # Match KEDUA deployment
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
kubectl apply -f stable-deployment.yaml
kubectl apply -f canary-deployment.yaml
kubectl apply -f service.yaml
# Verifikasi distribusi pod
kubectl get pods -l app=myapp --show-labels
Contoh output yang diharapkan:
NAME READY STATUS LABELS
myapp-stable-7d4f8b9c6-abc12 1/1 Running app=myapp,version=stable
myapp-stable-7d4f8b9c6-def34 1/1 Running app=myapp,version=stable
myapp-stable-7d4f8b9c6-ghi56 1/1 Running app=myapp,version=stable
myapp-stable-7d4f8b9c6-jkl78 1/1 Running app=myapp,version=stable
myapp-stable-7d4f8b9c6-mno90 1/1 Running app=myapp,version=stable
myapp-stable-7d4f8b9c6-pqr12 1/1 Running app=myapp,version=stable
myapp-stable-7d4f8b9c6-stu34 1/1 Running app=myapp,version=stable
myapp-stable-7d4f8b9c6-vwx56 1/1 Running app=myapp,version=stable
myapp-stable-7d4f8b9c6-yza78 1/1 Running app=myapp,version=stable
myapp-canary-5b8c9d7e4-bcd90 1/1 Running app=myapp,version=canary
Dengan 9 pod stable dan 1 pod canary, sekitar 10% request akan diarahkan ke versi baru secara otomatis oleh kube-proxy.
Langkah 4: Tingkatkan Traffic ke Canary Secara Bertahap
# Setelah monitoring 30 menit — naikkan canary ke 30%
kubectl scale deployment myapp-canary --replicas=3
kubectl scale deployment myapp-stable --replicas=7
# Setelah 1 jam — naikkan ke 50%
kubectl scale deployment myapp-canary --replicas=5
kubectl scale deployment myapp-stable --replicas=5
# Full rollout — migrasi semua ke v2
kubectl scale deployment myapp-canary --replicas=10
kubectl scale deployment myapp-stable --replicas=0
Monitoring dan Analisis: Mengukur Keberhasilan Canary
Metrik kunci yang harus dipantau selama canary deployment:
# Cek error rate via log
kubectl logs -l version=canary --tail=100 | grep -i "error\|500\|panic"
# Resource usage
kubectl top pods -l app=myapp
# Describe untuk event anomali
kubectl describe deployment myapp-canary
Jika menggunakan Prometheus + Grafana, query berikut berguna untuk membandingkan error rate:
# Error rate per versi
sum(rate(http_requests_total{status=~"5..", version="canary"}[5m]))
/
sum(rate(http_requests_total{version="canary"}[5m]))
Threshold yang umum digunakan:
- Error rate < 1% → aman dilanjutkan
- P99 latency tidak meningkat > 20% → deployment sehat
- CPU/Memory tidak melebihi limit → tidak ada memory leak
Automasi Rollout dan Rollback dengan Progressive Delivery
Untuk otomatisasi penuh, gunakan Argo Rollouts. Install terlebih dahulu:
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f \
https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
Buat Rollout manifest dengan analisis otomatis:
# argo-rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: myapp-rollout
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 10 # 10% traffic ke canary
- pause: {duration: 5m}
- setWeight: 30 # 30% setelah 5 menit
- pause: {duration: 10m}
- setWeight: 60 # 60% setelah 10 menit
- pause: {duration: 10m}
- setWeight: 100 # Full rollout
analysis:
templates:
- templateName: success-rate
startingStep: 1
args:
- name: service-name
value: myapp-service
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:v2.0.0
ports:
- containerPort: 8080
Buat AnalysisTemplate untuk evaluasi otomatis:
# analysis-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
args:
- name: service-name
metrics:
- name: success-rate
interval: 2m
successCondition: result[0] >= 0.99 # 99% success rate
failureLimit: 3
provider:
prometheus:
address: http://prometheus.monitoring.svc.cluster.local:9090
query: |
sum(rate(http_requests_total{
service="{{args.service-name}}",
status!~"5.."
}[2m])) /
sum(rate(http_requests_total{
service="{{args.service-name}}"
}[2m]))
kubectl apply -f argo-rollout.yaml
kubectl apply -f analysis-template.yaml
# Monitor status rollout
kubectl argo rollouts get rollout myapp-rollout --watch
# Manual rollback jika diperlukan
kubectl argo rollouts abort myapp-rollout
kubectl argo rollouts undo myapp-rollout
Mirip dengan bagaimana Membangun Aplikasi Serverless dengan Cloudflare Workers: Tutorial Step-by-Step memungkinkan deployment tanpa downtime di edge, Argo Rollouts memberi kita mekanisme kontrol granular yang sama namun di level Kubernetes cluster.
Contoh Kasus Nyata
Jika kamu ingin membangun layanan ride-hailing seperti Gojek dengan jutaan request per hari, canary deployment bisa diimplementasikan dalam skenario ini:
Skenario: Tim pricing engine merilis algoritma surge pricing baru.
# Deploy canary hanya untuk region Jakarta
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: pricing-canary-jkt
annotations:
deployment.region: "jakarta"
spec:
replicas: 2
selector:
matchLabels:
app: pricing-engine
region: jakarta
version: canary
template:
metadata:
labels:
app: pricing-engine
region: jakarta
version: canary
spec:
containers:
- name: pricing
image: pricing-engine:v2.1.0-surge-algo
env:
- name: FEATURE_FLAG_SURGE_V2
value: "true"
EOF
Dengan pendekatan ini, hanya pengguna di Jakarta yang merasakan algoritma baru, sementara kota lain tetap menggunakan versi stabil.
Troubleshooting: Error yang Sering Muncul
Pod Canary Tidak Mendapat Traffic (Traffic Split Tidak Sesuai)
Penyebab: Label selector pada Service tidak match dengan kedua deployment, atau terjadi mismatch label antara spec.selector di Service dan metadata.labels di pod template.
Solusi:
# Verifikasi label pod yang berjalan
kubectl get pods --show-labels -l app=myapp
# Pastikan endpoint terdaftar di service
kubectl get endpoints myapp-service
# Debug selector service
kubectl describe service myapp-service | grep -A5 "Selector"
# Jika endpoint kosong, perbaiki label di deployment
kubectl patch deployment myapp-canary -p \
'{"spec":{"template":{"metadata":{"labels":{"app":"myapp"}}}}}'
ImagePullBackOff pada Canary Pod
Penyebab: Image versi baru belum tersedia di registry, atau credentials registry tidak dikonfigurasi untuk namespace canary.
Solusi:
# Cek detail error
kubectl describe pod <nama-pod-canary>
# Buat secret registry jika belum ada
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=YOUR_USERNAME \
--docker-password=YOUR_PASSWORD \
--namespace=canary-demo
# Tambahkan imagePullSecrets ke deployment
kubectl patch deployment myapp-canary -p '{
"spec": {
"template": {
"spec": {
"imagePullSecrets": [{"name": "regcred"}]
}
}
}
}'
Argo Rollouts Analysis Selalu Gagal (AnalysisRun Failed)
Penyebab: Query Prometheus mengembalikan nilai NaN atau kosong karena metric belum terkumpul, atau format query tidak sesuai dengan label metric yang ada.
Solusi:
# Cek status AnalysisRun
kubectl get analysisrun
kubectl describe analysisrun <nama-analysisrun>
# Test query Prometheus secara manual
curl -g "http://prometheus:9090/api/v1/query" \
--data-urlencode 'query=sum(rate(http_requests_total[2m]))'
# Tambahkan initialDelay agar metric sempat terkumpul
# Di AnalysisTemplate, tambahkan field berikut:
# initialDelay: 60s
Rollback Tidak Otomatis Setelah Error Threshold Terlampaui
Penyebab: failureLimit di AnalysisTemplate terlalu tinggi, atau progressDeadlineSeconds di Rollout belum dikonfigurasi.
Solusi:
# Perbaiki di AnalysisTemplate
metrics:
- name: success-rate
failureLimit: 1 # Turunkan dari 3 ke 1
consecutiveErrorLimit: 2
interval: 1m
# Di Rollout spec, tambahkan:
spec:
progressDeadlineSeconds: 600 # Timeout 10 menit
strategy:
canary:
analysis:
templates:
- templateName: success-rate
Pertanyaan yang Sering Diajukan (FAQ)
Apa perbedaan Canary Deployment dengan Blue-Green Deployment?
Blue-Green deployment menjalankan dua environment identik (blue = lama, green = baru) dan melakukan switch traffic 0% → 100% secara instan. Canary deployment lebih gradual — traffic dipindahkan bertahap (10% → 30% → 60% → 100%), memungkinkan deteksi masalah lebih awal dengan risiko lebih kecil. Blue-Green membutuhkan dua kali resource, sementara canary lebih hemat karena hanya menambahkan sebagian kecil pod baru.
Bagaimana cara menentukan persentase awal traffic yang aman untuk canary?
Umumnya mulai dari 1–10% tergantung volume traffic dan toleransi risiko. Untuk aplikasi dengan traffic tinggi (jutaan request/jam), bahkan 1% sudah cukup untuk mendapat sampel data yang signifikan secara statistik. Untuk aplikasi dengan traffic rendah, mulai dari 20–30% agar periode monitoring lebih pendek. Faktor utama: jumlah sample yang cukup untuk analisis error rate yang valid.
Apa yang harus dipantau selama periode canary?
Fokus pada empat metrik utama: (1) Error rate — persentase request 5xx, (2) Latency P99 — waktu respons di persentil ke-99, (3) Resource utilization — CPU dan memory pod canary, dan (4) Business metrics — konversi, transaksi sukses, atau metrik bisnis spesifik aplikasimu. Jika salah satu melebihi threshold yang ditentukan, segera lakukan rollback.
Apakah canary deployment bisa digunakan untuk perubahan database schema?
Ini adalah salah satu tantangan terbesar canary deployment. Perubahan schema database harus backward compatible — versi lama dan baru harus bisa berjalan bersamaan dengan schema yang sama. Gunakan teknik expand-and-contract: pertama tambahkan kolom baru (tanpa hapus yang lama), deploy canary dan validasi selama beberapa jam, kemudian hapus kolom lama hanya setelah seluruh traffic bermigrasi penuh ke versi baru. Tools seperti Flyway atau Liquibase sangat membantu mengelola migrasi bertahap ini dengan aman dan terstruktur.
Berapa lama idealnya periode observasi sebelum menaikkan persentase canary?
Tidak ada angka pasti, namun panduan umum adalah minimal 30 menit per tahap untuk aplikasi dengan traffic sedang. Faktor yang memengaruhi: volume request (semakin tinggi, semakin cepat data terkumpul), kompleksitas fitur (fitur pembayaran butuh observasi lebih lama dari fitur tampilan), dan SLA bisnis. Untuk perubahan kritis seperti autentikasi atau transaksi finansial, pertimbangkan observasi 2–4 jam per tahap sebelum menaikkan persentase berikutnya.
Kesimpulan
Canary deployment adalah salah satu strategi paling efektif untuk merilis fitur baru dengan risiko minimal di lingkungan Kubernetes. Mulai dari pendekatan manual berbasis rasio replica hingga otomatisasi penuh dengan Argo Rollouts dan AnalysisTemplate, kamu kini memiliki toolset lengkap untuk mengimplementasikan progressive delivery di produksi. Selamat mencoba dan jangan ragu untuk bereksperimen — setiap deployment yang berhasil adalah bukti bahwa sistem yang kamu bangun semakin matang dan andal!