← Blog'a Geri Dön

Kubernetes'te Progressive Delivery: Argo Rollouts ile Canary Deployment

Junior DevOps perspektifinden — gerçek lab ortamında, adım adım


Giriş: "Her Deploy Bir Kumar mı Olmalı?"

Bir düşün: üretim ortamına yeni bir versiyon deploy ediyorsun. **kubectl set image** komutunu çalıştırıyorsun ve Kubernetes tüm pod'ları bir anda değiştiriyor. 10 saniye sonra telefon çalıyor — kullanıcılar uygulamaya erişemiyor.

Bu senaryo gerçek. Ve bunun için klasik **Deployment** kaynağı yetersiz kalıyor.

Bu yazıda Argo Rollouts ile canary deployment yapacağız: yeni versiyonu önce trafiğin %20'sine gönder, sağlıklıysa kademeli artır, sorun çıkarsa tek komutla geri dön. Gerçek bir Kubernetes lab ortamında, tüm adımlarıyla.

Ortam

Bileşen Detay
Kubernetes v1.29.15 (kubeadm)
Nodes 1 master (px-master) + 1 worker (px-worker)
Helm v3.19.5
Argo Rollouts v1.9.0

Neden Canary? Neden Argo Rollouts?

Klasik Deployment'ın Sorunu

Standart bir Deployment ile image güncellediğinde Kubernetes RollingUpdate stratejisi kullanır. Varsayılan ayarlarla pod'ların %25'i aynı anda değişir. Hızlıdır ama kontrolsüzdür.

Klasik RollingUpdate:

v1 v1 v1 v1 v1
      ↓
v2 v2 v2 v2 v2   ← hepsi bir anda değişiyor

Bir şeyler patlarsa? Tüm kullanıcılar etkileniyor.

Argo Rollouts ile Canary

Argo Rollouts, Deployment kaynağının üzerine inşa edilmiş bir controller. Kendi CRD'siyle (Rollout) gelir ve trafik split'i, manuel onay kapıları, metrik bazlı otomatik rollback gibi özellikler sunar.

Canary Deployment:

Adım 1: %20 canary
  v1 v1 v1 v1 | v2   ← sadece 1 pod yeni versiyon

Adım 2: %40 canary
  v1 v1 v1 | v2 v2

Adım 3: %60 canary
  v1 v1 | v2 v2 v2

Adım 4: %80 canary
  v1 | v2 v2 v2 v2

Adım 5: %100 — Tamamlandı
  v2 v2 v2 v2 v2

Her adımda dur, izle, onay ver veya geri dön.


Kurulum

1. Argo Rollouts Controller

Helm reposunu ekle ve controller'ı kur:

helm repo add argo https://argoproj.github.io/argo-helm
helm repo update

helm install argo-rollouts argo/argo-rollouts \
  --namespace argo-rollouts \
  --create-namespace \
  --set dashboard.enabled=true

Controller'ın ayağa kalkmasını bekle:

kubectl rollout status deployment/argo-rollouts -n argo-rollouts
# deployment "argo-rollouts" successfully rolled out

2. kubectl Plugin

Rollout'ları yönetmek için Argo'nun kubectl plugin'ini kur. Bu plugin sayesinde kubectl argo rollouts komutunu kullanabilirsin:

curl -LO https://github.com/argoproj/argo-rollouts/releases/latest/download/kubectl-argo-rollouts-linux-amd64
chmod +x kubectl-argo-rollouts-linux-amd64
sudo mv kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts

kubectl argo rollouts version
# kubectl-argo-rollouts: v1.9.0+838d4e7

Adım 1: Standart Deployment ile Başla

Önce klasik yöntemi kuralım — farkı görmek için:

kubectl create namespace rollouts-demo

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rollouts-demo
  namespace: rollouts-demo
spec:
  replicas: 5
  selector:
    matchLabels:
      app: rollouts-demo
  template:
    metadata:
      labels:
        app: rollouts-demo
    spec:
      containers:
      - name: rollouts-demo
        image: argoproj/rollouts-demo:blue
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: rollouts-demo-svc
  namespace: rollouts-demo
spec:
  selector:
    app: rollouts-demo
  ports:
  - port: 80
    targetPort: 8080
EOF

5 pod çalışıyor:

NAME                            READY   STATUS    RESTARTS   AGE
rollouts-demo-84b7c468f-h65kc   1/1     Running   0          38s
rollouts-demo-84b7c468f-hvfdg   1/1     Running   0          38s
rollouts-demo-84b7c468f-nsx86   1/1     Running   0          38s
rollouts-demo-84b7c468f-vbxgg   1/1     Running   0          38s
rollouts-demo-84b7c468f-xxzl4   1/1     Running   0          38s

Adım 2: Deployment → Rollout'a Geçiş

Şimdi aynı uygulamayı Rollout kaynağıyla yeniden tanımlıyoruz. Yapı neredeyse aynı — tek fark spec.strategy bloğu:

kubectl delete deployment rollouts-demo -n rollouts-demo

cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1   # ← artık argoproj CRD'si
kind: Rollout                      # ← Deployment değil
metadata:
  name: rollouts-demo
  namespace: rollouts-demo
spec:
  replicas: 5
  selector:
    matchLabels:
      app: rollouts-demo
  template:
    metadata:
      labels:
        app: rollouts-demo
    spec:
      containers:
      - name: rollouts-demo
        image: argoproj/rollouts-demo:blue
        ports:
        - containerPort: 8080
  strategy:
    canary:
      steps:
      - setWeight: 20          # trafiğin %20'si canary'e
      - pause: {}              # elle onay bekle
      - setWeight: 40
      - pause: {duration: 30}  # 30sn otomatik bekle
      - setWeight: 60
      - pause: {duration: 30}
      - setWeight: 80
      - pause: {duration: 30}
EOF

Strategy'yi anlamak:

steps:
  setWeight: 20  →  1 pod yeni versiyon (5 pod × %20 = 1)
  pause: {}      →  DUR, elle onay bekle
  setWeight: 40  →  2 pod yeni versiyon
  pause: 30s     →  30 saniye bekle, sonra devam et
  ...

pause: {} ile pause: {duration: 30} arasındaki fark kritik:

  • pause: {}manuel onay kapısı, promote komutu gelene kadar bekler
  • pause: {duration: 30}otomatik timer, 30 saniye sonra kendi geçer

Rollout durumunu kontrol et:

kubectl argo rollouts get rollout rollouts-demo -n rollouts-demo
Name:            rollouts-demo
Status:          ✔ Healthy
Strategy:        Canary
  Step:          8/8
  SetWeight:     100
  ActualWeight:  100
Images:          argoproj/rollouts-demo:blue (stable)

NAME                                       KIND        STATUS     AGE
⟳ rollouts-demo                            Rollout     ✔ Healthy  48s
└──# revision:1
   └──⧉ rollouts-demo-84dc9dcb7d           ReplicaSet  ✔ Healthy  48s  stable
      ├──□ rollouts-demo-84dc9dcb7d-crw7l  Pod         ✔ Running  48s
      ├──□ rollouts-demo-84dc9dcb7d-fc94q  Pod         ✔ Running  48s
      ├──□ rollouts-demo-84dc9dcb7d-g224w  Pod         ✔ Running  48s
      ├──□ rollouts-demo-84dc9dcb7d-kl6kr  Pod         ✔ Running  48s
      └──□ rollouts-demo-84dc9dcb7d-zhvgs  Pod         ✔ Running  48s

revision:1 — ilk deploy. 5 pod stable etiketli, sistem sağlıklı.


Adım 3: Canary Deploy — blue → yellow

Yeni versiyon geliyor. Image'ı yellow ile güncelle:

kubectl argo rollouts set image rollouts-demo \
  rollouts-demo=argoproj/rollouts-demo:yellow \
  -n rollouts-demo

Hemen sonrasında:

⟳ rollouts-demo                            Rollout     ॥ Paused   110s
├──# revision:2
│  └──⧉ rollouts-demo-78857fdfbb           ReplicaSet  ✔ Healthy  20s   canary
│     └──□ rollouts-demo-78857fdfbb-99gf2  Pod         ✔ Running  20s   ready:1/1
└──# revision:1
   └──⧉ rollouts-demo-84dc9dcb7d           ReplicaSet  ✔ Healthy  110s  stable
      ├──□ rollouts-demo-84dc9dcb7d-crw7l  Pod         ✔ Running  110s  ready:1/1
      ├──□ rollouts-demo-84dc9dcb7d-g224w  Pod         ✔ Running  110s  ready:1/1
      ├──□ rollouts-demo-84dc9dcb7d-kl6kr  Pod         ✔ Running  110s  ready:1/1
      └──□ rollouts-demo-84dc9dcb7d-zhvgs  Pod         ✔ Running  110s  ready:1/1

Ne oluyor?

┌─────────────────────────────────────────────┐
│  Trafik Dağılımı                            │
│                                             │
│  revision:1 (blue)    ████████████  %80     │
│  revision:2 (yellow)  ███           %20     │
│                                             │
│  Status: ॥ Paused — elle onay bekleniyor   │
└─────────────────────────────────────────────┘

Rollout ilk pause: {} adımında durdu. Seni bekliyor. Bu an gerçek hayatta "metriklere bak" anıdır — hata oranı arttı mı? Latency bozuldu mu?

Manuel Onay

Metrikler iyiyse onay ver:

kubectl argo rollouts promote rollouts-demo -n rollouts-demo

Rollout kendi kendine ilerlemeye başlar:

# ~20 saniye sonra
revision:2 → 2 pod (canary)  %40
revision:1 → 3 pod (stable)  %60

# ~50 saniye sonra
revision:2 → 3 pod (canary)  %60
revision:1 → 2 pod (stable)  %40

# ~80 saniye sonra
revision:2 → 4 pod (canary)  %80
revision:1 → 1 pod (stable)  %20

Tamamlandı

⟳ rollouts-demo                            Rollout     ✔ Healthy
├──# revision:2
│  └──⧉ rollouts-demo-78857fdfbb           ReplicaSet  ✔ Healthy  stable
│     ├──□ rollouts-demo-78857fdfbb-99gf2  Pod         ✔ Running
│     ├──□ rollouts-demo-78857fdfbb-w7df4  Pod         ✔ Running
│     ├──□ rollouts-demo-78857fdfbb-427mg  Pod         ✔ Running
│     ├──□ rollouts-demo-78857fdfbb-fqfqs  Pod         ✔ Running
│     └──□ rollouts-demo-78857fdfbb-gvszz  Pod         ✔ Running
└──# revision:1
   └──⧉ rollouts-demo-84dc9dcb7d           ReplicaSet  • ScaledDown

5 pod tamamen yellow'a geçti. revision:1 (blue) scale down edildi. Sıfır downtime.


Adım 4: Bozuk Versiyon + Rollback

Asıl soru şu: "Ya yeni versiyon bozuksa?" Bunu simüle ediyoruz.

kubectl argo rollouts set image rollouts-demo \
  rollouts-demo=argoproj/rollouts-demo:bad \
  -n rollouts-demo
⟳ rollouts-demo                            Rollout     ◌ Progressing
├──# revision:3
│  └──⧉ rollouts-demo-86f7547f69           ReplicaSet  ◌ Progressing  canary
│     └──□ rollouts-demo-86f7547f69-dcgbn  Pod         ⚠ ErrImagePull
├──# revision:2
│  └──⧉ rollouts-demo-78857fdfbb           ReplicaSet  ✔ Healthy      stable
│     ├──□ rollouts-demo-78857fdfbb-99gf2  Pod         ✔ Running
│     ├──□ rollouts-demo-78857fdfbb-w7df4  Pod         ✔ Running
│     ├──□ rollouts-demo-78857fdfbb-427mg  Pod         ✔ Running
│     ├──□ rollouts-demo-78857fdfbb-fqfqs  Pod         ✔ Running
│     └──□ rollouts-demo-78857fdfbb-9mpnd  Pod         ✔ Running

Canary seni koruyor:

┌──────────────────────────────────────────────────────┐
│  revision:3 (bad)     ⚠ ErrImagePull  →  %20        │
│  revision:2 (yellow)  ✔ Running       →  %80        │
│                                                      │
│  Kullanıcıların %80'i hâlâ sağlıklı versiyonda!     │
└──────────────────────────────────────────────────────┘

Klasik RollingUpdate olsaydı şu an tüm pod'lar bozuk versiyona geçmeye çalışıyor olacaktı.

Rollback

kubectl argo rollouts abort rollouts-demo -n rollouts-demo
⟳ rollouts-demo                            Rollout     ✖ Degraded
├──# revision:3
│  └──⧉ rollouts-demo-86f7547f69           ReplicaSet  • ScaledDown  ← bozuk versiyon kapatıldı
├──# revision:2
│  └──⧉ rollouts-demo-78857fdfbb           ReplicaSet  ✔ Healthy     stable
│     ├──□ ...5 pod Running...

abort canary pod'larını kapattı, tüm trafik revision:2'ye döndü. Degraded durumu "abort edildi" anlamında — sistem çalışıyor.

Son olarak Rollout'u temizle:

kubectl argo rollouts undo rollouts-demo -n rollouts-demo
⟳ rollouts-demo                            Rollout     ✔ Healthy
├──# revision:4
│  └──⧉ rollouts-demo-78857fdfbb           ReplicaSet  ✔ Healthy  stable
│     ├──□ ...5 pod Running...
├──# revision:3
│  └──⧉ rollouts-demo-86f7547f69           ReplicaSet  • ScaledDown
└──# revision:1
   └──⧉ rollouts-demo-84dc9dcb7d           ReplicaSet  • ScaledDown

✔ Healthy — sistem temiz. Bozuk versiyon tarihte kaldı.


Özet: Ne Öğrendik?

Komut Ne Yapar
helm install argo-rollouts Controller'ı cluster'a kurar
kubectl argo rollouts set image Yeni versiyonu canary olarak başlatır
kubectl argo rollouts get rollout Adım adım durumu gösterir
kubectl argo rollouts promote Manuel pause kapısını açar
kubectl argo rollouts abort Canary'i durdurur, trafiği stable'a çeker
kubectl argo rollouts undo Degraded → Healthy'e getirir

Canary deployment'ın verdiği güvence:

Klasik deploy:  Bir şey patlarsa → %100 kullanıcı etkilenir
Canary deploy:  Bir şey patlarsa → %20 kullanıcı etkilenir, abort et → %0

Sırada Ne Var?

Bu yazıda manuel canary yaptık — "metriklere bak, onay ver" adımını elle gerçekleştirdik. Bir sonraki seviye Analysis Templates: Prometheus metriklerine bakarak Rollout otomatik olarak "hata oranı %5'i geçtiyse abort et" kararını kendi verebilir.

← Blog'a Geri Dön