Exploring Infinite Possibilities on FrontEnd 🚀
Burak Sağlık
Search...

Sat Oct 03 2026

Kubernetes Rollout Hata Ayıklama: ImagePullBackOff, CrashLoopBackOff ve Readiness Probe Çözümleri

Kubernetes Rollout Hata Ayıklama: ImagePullBackOff, CrashLoopBackOff ve Readiness Probe Çözümleri

🎯 Giriş: Kubernetes Rollout Donmaları Neden Bu Kadar Kritikal?

Selam! ☕ Hazırsan başlayalım.

Biliyorsun, her geliştirici hayatında en az bir kez yaşar: dağıtım yapıyorsun, her şey yolunda gidiyor gibi, aniden rollout donuyor. Pod'lar Pendingde kalıyor, CrashLoopBackOff veriyor ya da daha kötüsü — ImagePullBackOff ile sana gülüyor. 😅

Ne oluyor ekip içinde?

  • Moral dibe vurur ⛔ — "Yine mi?" diye bakışlar arası uçar
  • Prodüktivite sıfırlanır 📉 — Kimse yeni feature yazmıyor, herkes loglara dalıyor
  • Stres çarpıcı seviyelere çıkıyor 😰 — "Müşteri şikayet etmeden halledelim" paniği
  • Bilgi kaybı yaşanır 🧠 — Çözüm bulundu ama kimse doküman etmemiş, bir ay sonra deja vu

Bu yazı neden var? 🎯

Amacımız basit: sistematik bir hata ayıklama metodolojisi kazandırmak. "Hadi deneyelim, belki olur" yerine, laboratuvar yaklaşımıyla (evet, bilim adamı gibi 🧪) adım adım, kanıta dayalı gidelim.

Neden laboratuvar yaklaşımı? 🔬

  • Tekrarlanabilir — Aynı hata gelirse panik yapmazsın, prosedürü çalıştırırsın
  • Paylaşılabilir — Yeni ekip arkadaşı gelince "şu checklisti takip et" dersin
  • Ölçeklenebilir — 5 servisin olsun 500'ü, mantık değişmez
  • Öğrenme kalıcı olur — Neden çalıştığını anlarsın, sadece nasıl düzeltildiğini değil

Kendini tanıdın mı? Eğer "evet, bana da oldu" diyorsan doğru yerdesin. Hadi kolları sıvalım, laboratuvara girelim! 🛠


🔁 Laboratuvar Ortamını Kurma: Minikube / Kind ile Hızlı Başlangıç

Hadi kendi makinenizde tek komutla bir Kubernetes cluster'ı ayağa kaldıralım 🚀 Ben Minikube'yi tercih ediyorum çünkü:

  • Docker driver ile saniyeler içinde hazır olur ⚡
  • Tek bir VM/container içinde tüm control-plane + worker barındırır — temiz, izole
  • kubectl zaten sizin için yapılandırılır, ekstra kubeconfig uğraşı yok ✅

Not: Kind de harika bir alternatif (özellikle CI/CD pipelines için), ama lokal geliştirme için Minikube biraz daha "batteries included" geliyor bana.


🛠 Adım adım kurulum

  1. Docker çalışıyor mu kontrol edin (docker ps yeterli)
  2. Minikube yüklü değilse: brew install minikube (macOS) / choco install minikube (Windows) / resmi docs
  3. Aşağıdaki tek satırı terminalinize yapıştırın ve Enter'a basın:
minikube start --driver=docker && kubectl version --short && kubectl get nodes

🔍 Ne oluyor burada?

Komut Ne işe yarar?
minikube start --driver=docker Docker container içinde single-node cluster kurar
kubectl version --short Client + server sürümünü kısa formatta gösterir (doğrulama)
kubectl get nodes Cluster'daki node'ları listeler — Ready gorünmeli!

✅ Beklenen çıktı örneği

😄  minikube v1.32.0 on Darwin 14.5 (arm64)
✨  Using the docker driver based on user configuration
🚜  Pulling base image v0.0.47 ...
💾  Downloading Kubernetes v1.28.3 preload ...
    > preloaded-images-k8s-v18-v1.28.3-docker-overlay2-amd64.tar.lz4:  456.78 MiB / 456.78 MiB  100.00% 12.3 MiB
🔥  Creating docker container (CPUs=2, Memory=2200MB) ...
🐳  Preparing Kubernetes v1.28.3 on Docker 24.0.7 ...
    ▪ kubelet.housekeeping-interval=5m0s
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔎  Verifying Kubernetes components...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
Client Version: v1.28.3
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.28.3
NAME       STATUS   ROLES           AGE   VERSION
minikube   Ready    control-plane   45s   v1.28.3

STATUS Ready gördüyseniz — cluster çalışıyor! 🎉


🎯 Sonraki adım

Artık kubectl apply -f ... ile manifestlarınızı deploy edebilir, kubectl port-forward ile servislerinize erişebilirsiniz. Bir sonraki bölümde ilk Deployment'ımızı yazacağız — hazırmısınız? 😊


❗️ Yaygın Rollout Hata Tiplerini Tanıyalım: ImagePullBackOff, CrashLoopBackOff, Readiness Probe

Kubernetes’ta bir rollout sırasında en sık karşılaştığımız üç “kırmızı bayrak” şunlardır. Her birini ne anlama geldiğini, hangisi tetikler ve kubectl get pods çıktısında nasıl göründüğünü özetleyelim. Böylece bir hata gördüğünüzde “Ah bu neydi?” diye düşünmek yerine hemen müdahale edebilirsiniz 🚀


1️⃣ ImagePullBackOff

Özellik Açıklama
Ne anlama gelir? Kubelet, konteyner imajını çekemez (genelde registery erişimi, yanlış tag veya imagePullSecret eksikliği).
Tetikleyen olay docker pull / containerd pull başarısız olduğunda,ponential back‑off ile tekrar deneme başlar.
kubectl get pods çıktısı STATUS sütununda ImagePullBackOff yazar.

Ne oluyor burada?

  • Pod Pending durumunda kalır, konteyner hiç başlatılmaz.
  • kubectl describe pod <pod> çıktısında Failed to pull image ... hatasını görürsünüz.

Hızlı kontrol listesi ✅

  • Imaj adı/tag doğru mu?
  • Registery’ye erişim var mı (VPN, firewall, imagePullSecret)?
  • imagePullPolicy: Always mı, yoksa IfNotPresent mı?

2️⃣ CrashLoopBackOff

Özellik Açıklama
Ne anlama gelir? Konteyner başarıyla başladı ama kendi içinde çöküyor (exit code ≠ 0) ve Kubelet sürekli yeniden başlatıyor.
Tetikleyen olay Uygulama hatası (exception, OOM, config hatası) → konteyner kapanır → Kubelet exponential back‑off ile tekrar dener.
kubectl get pods çıktısı STATUS sütununda CrashLoopBackOff yazar. RESTARTS sayısı artar.

Ne oluyor burada?

  • Pod Running görünür ama aslında sürekli yeniden başlıyor.
  • kubectl logs <pod> --previous ile çökme öncesi logları inceleyin.

Hızlı kontrol listesi ✅

  • Uygulama loglarında hata var mı? (stack trace, config dosyası eksikliği)
  • resources.limits.memory yeterli mi? (OOMKilled)
  • livenessProbe / startupProbe yanlış ayarlı mı?

3️⃣ Readiness Probe Hatası (Pod “Not Ready”)

Özellik Açıklama
Ne anlama gelir? Konteyner ayakta ama trafiği karşılayacak durumda değil (probe başarısız).
Tetikleyen olay HTTP endpoint, TCP port veya exec komutu belirlenen süre içinde başarısız döner.
kubectl get pods çıktısı STATUS sütununda Running yazar, ancak READY sütunu 0/1 (veya 0/2…) gösterir.

Ne oluyor burada?

  • Pod Running ama Service’in endpoint listesine eklenmez → trafik gitmez.
  • kubectl describe pod <pod> altında Readiness probe failed: mesajı görürsünüz.

Hızlı kontrol listesi ✅

  • Probe path/port doğru mu? (/healthz, 8080 vb.)
  • Uygulama gerçekten hazır mı (migration, cache warm‑up)?
  • initialDelaySeconds / periodSeconds değerleri uygulama başlatma süresine uygun mu?

📋 Hızlı Karşılaştırma Tablosu

Hata Türü Pod Durumu (STATUS) READY Ana Sebep İlk Bakılacak Yer
ImagePullBackOff ImagePullBackOff 0/1 Imaj çekilemedi kubectl describe pod → Events
CrashLoopBackOff CrashLoopBackOff 0/1 (veya 1/1 ama RESTARTS artar) Konteyner çöküyor kubectl logs <pod> --previous
Readiness Probe Fail Running 0/1 Probe başarısız kubectl describe pod → Readiness probe failed

🎯 Pratik İpucu

# Tüm hatalı podları bir kerede görmek için
kubectl get pods --field-selector=status.phase!=Running -A

Bu komut Running olmayan (ImagePullBackOff, CrashLoopBackOff, Pending vb.) podları listeler. Readiness hatası için READY sütununu da kontrol etmeyi unutmayın.


Özetle:

  • ImagePullBackOff → imaj yok/erişilemiyor → pod hiç başlamaz.
  • CrashLoopBackOff → konteyner çöküyor → sürekli restart.
  • Readiness Probe Fail → pod ayakta ama trafiğe kapalı.

Hangi hatayı görürseniz görünün, yukarıdaki tabloyu aklınızda tutun ve ilgili log/event’e odaklanın. Kolay gelsin! 🛠✨


🛠 Hata 1: ImagePullBackOff - Yanlış İsim, Tag veya Private Registry

Bu hatayı her Kubernetes geliştiricisi en az bir kez yaşamıştır 😅. Pod Pending kalıyor, kubectl get pods çıktısında ImagePullBackOff yazıyor ve sen "Neden çekmiyor bu image'ı?" diye hayıflanıyorsun.

Genelde üç sebep var:

  • Yanlış image adı/typo (en sık görülen)
  • Yanlış veya yok olan tag
  • Private registry ama imagePullSecrets eksik

Hadi pratik bir örnekle canlandıralım 👇


❌ Hatalı Deployment — nginx:latestt (typo var!)

# deployment-imagepullbackoff.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  labels:
    app: web-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: nginx
        image: nginx:latestt   # ❌ Burada typo var: "latestt"
        ports:
        - containerPort: 80

Ne yaptık? image: nginx:latestt yazdık — Docker Hub'da böyle bir tag yok. Kubernetes image'ı çekmeye çalışır, 404 alır, retry eder, backoff'a girer.


🔍 Hatayı nasıl teşhis edersin?

Terminalde şu adımları izle:

# 1. Deployment'ı uygula
kubectl apply -f deployment-imagepullbackoff.yaml

# 2. Rollout durumunu izle (biraz bekler, sonra timeout'a düşer)
kubectl rollout status deployment/web-app

# 3. Pod'lardan birinin detayına bak — HATA BURADA GÖZÜKECEK
kubectl describe pod -l app=web-app

kubectl describe çıktısında şu satırı arayacaksın:

Events:
  Type     Reason          Age   From               Message
  ----     ------          ----  ----               -------
  Warning  Failed          10s   kubelet            Failed to pull image "nginx:latestt": rpc error: code = Unknown desc = Error response from daemon: pull access denied for nginx:latestt, repository does not exist or may require 'docker login'
  Warning  Failed          10s   kubelet            Error: ErrImagePull
  Normal   BackOff         5s    kubelet            Back-off pulling image "nginx:latestt"

🎯 İpucu: ErrImagePull → ImagePullBackOff sırasıyla gelir. BackOff, Kubernetes "az önce denedim, olmadı, biraz bekleyip tekrar deneyeyim" diyorsa oluşur.


✅ Düzeltilmiş Deployment — nginx:latest + imagePullSecrets örneği

# deployment-fixed.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  labels:
    app: web-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: nginx
        image: nginx:latest   # ✅ Doğru tag
        ports:
        - containerPort: 80
      # 🔐 Eğer private registry kullanıyorsan:
      imagePullSecrets:
      - name: my-registry-secret   # Önce: kubectl create secret docker-registry my-registry-secret ...

Ne değişti?

Alan Hatalı Düzeltilmiş
image nginx:latestt ❌ nginx:latest ✅
imagePullSecrets Yok Eklendi (private registry için)

🛠 Çözüm kontrol listesi

  • Image adını yazım hatası yok mu? (nginx vs ngnix, latest vs latestt)
  • Tag var mı? (:latest varsayılan ama explicit yazmak iyi pratik)
  • Private registry mi? → imagePullSecrets eklendi mi?
  • Secret namespace doğru mu? (Secret ile Pod aynı namespace'de olmalı)
  • Node'lar image'ı çekebiliyor mu? (Air-gapped ortamda pre-pull gerekebilir)

💡 Özetle

ImagePullBackOff = "Image'ı çekemedim, vazgeçtim" demek.
Çözüm: Yazımı kontrol et, tag doğrula, private registry için secret ekle.

Bir sonraki hatada görüşürüz — CrashLoopBackOff seninle olsun! 😉


🛠 Hata 2: CrashLoopBackOff - Uygulama Kodu Çöküyor

Arkadaşlar, CrashLoopBackOff gördüğümüzde aslında Kubernetes bize "Bu container sürekli çöküyor, ben de restart atıyorum, ama yine çöküyor, bu döngüden çıkamıyorum" diyor 🎯. Genelde uygulama kodunda bir hata var, eksik bir environment variable, ya da başlangıçta crash eden bir şeyler oluyor.

Hadi pratik bir örnek üzerinden anlayalım. Basit bir Python Flask uygulaması yazıyoruz, ama kasten bir ENV değişkeni okuyup o yoksa çökmesini sağlıyoruz. Sonra deploy edip nasıl debug edeceğimizi görelim 🛠.


1️⃣ Basit Python Uygulaması (app.py)

from flask import Flask
import os

app = Flask(__name__)

@app.route("/")
def hello():
    # KASTEN: Eksik env variable varsa crash etsin
    secret = os.environ["MY_SECRET"]
    return f"Merhaba! Secret: {secret}"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

Not: os.environ["MY_SECRET"] → eğer MY_SECRET yoksa KeyError fırlatır ve uygulama çöker ❗️


2️⃣ Dockerfile

FROM python:3.11-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY app.py .

EXPOSE 5000
CMD ["python", "app.py"]

3️⃣ requirements.txt

flask==3.0.2

4️⃣ Hatalı Deployment — deployment-crashloop.yaml (Eksik ENV)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: crashloop-demo
  labels:
    app: crashloop-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: crashloop-demo
  template:
    metadata:
      labels:
        app: crashloop-demo
    spec:
      containers:
      - name: app
        image: crashloop-demo:latest
        imagePullPolicy: Never
        ports:
        - containerPort: 5000
        # ❗️ MY_SECRET env variable EKLİ DEĞİL → CrashLoopBackOff olacak

Bu deployment'ı apply edince pod CrashLoopBackOff durumuna girecek 🔁.


5️⃣ Debug Süreci — Ne Yapmalıyız?

Pod çöküyor, ama neden? Hadi adım adım bakalım ✅.

🔍 Adım 1: Pod durumunu kontrol et

kubectl get pods -l app=crashloop-demo

Çıktı şuna benzer:

NAME                           READY   STATUS             RESTARTS   AGE
crashloop-demo-xxxxx-xxxxx     0/1     CrashLoopBackOff   3          2m

🔍 Adım 2: Önceki container'ın loglarına bak — kubectl logs --previous

Container crash olunca Kubernetes yenisini başlatır. Eski (çöken) container'ın logları --previous ile görünür 👇.

kubectl logs -l app=crashloop-demo --previous

Beklenen çıktı:

Traceback (most recent call last):
  File "/app/app.py", line 8, in hello
    secret = os.environ["MY_SECRET"]
KeyError: 'MY_SECRET'

Aha! MY_SECRET eksik. Bu yüzden çöküyor 🎯.

🔍 Adım 3: Container içine girip canlı debug — kubectl exec

Eğer loglar yetmezse (ör. uygulama başlayıp hemen çöküyorsa), container'ın filesystem'ine bakmak için içine girebiliriz. Ama CrashLoopBackOff'da container sürekli kapanıyor. Trick: sleep infinity ile container'ı canlı tutup sonra exec atarız 🛠.

Geçici bir debug pod'u çalıştıralım (aynı image ile):

kubectl run debug-pod --image=crashloop-demo:latest --restart=Never --command -- sleep infinity

Sonra içine girelim:

kubectl exec -it debug-pod -- sh

İçerideyken:

# Environment variable'ları kontrol et
env | grep MY_SECRET
# boş döner → eksik bestätigt

# Uygulamayı manuel çalıştırıp hata mesajını net gör
python app.py

İpucu: kubectl exec -it <pod> -- sh yerine bash da yazabilirsiniz (image'da bash varsa). sh her yerde olur 🐚.


6️⃣ Çözüm — Düzeltme: ENV Variable Ekle

Deployment'a env bloğu ekleyip tekrar apply ediyoruz ✅.

✅ Düzeltilmiş Deployment — deployment-fixed.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: crashloop-demo
  labels:
    app: crashloop-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: crashloop-demo
  template:
    metadata:
      labels:
        app: crashloop-demo
    spec:
      containers:
      - name: app
        image: crashloop-demo:latest
        imagePullPolicy: Never
        ports:
        - containerPort: 5000
        env:
        - name: MY_SECRET
          value: "super-gizli-deger-123"   # ✅ ARTIK VAR

Alternatif: valueFrom ile Secret/ConfigMap'den de çekebilirsiniz (prod için önerilir 🔐).


7️⃣ Apply ve Doğrula

kubectl apply -f deployment-fixed.yaml
kubectl rollout status deployment/crashloop-demo
kubectl get pods -l app=crashloop-demo

Beklenen çıktı:

NAME                           READY   STATUS    RESTARTS   AGE
crashloop-demo-xxxxx-xxxxx     1/1     Running   0          30s

Artık Running ve 0 restart 🎉.


📋 Özet — CrashLoopBackOff Debug Checklist

Adım Komut / Aksiyon Ne İşe Yarar?
1️⃣ kubectl get pods Pod durumunu ve restart sayısını gör
2️⃣ kubectl logs --previous Çöken container'ın loglarını al (en önemli!)
3️⃣ kubectl describe pod <pod> Events kısmında BackOff, Exit Code vb. ipuçları var
4️⃣ kubectl exec -it <debug-pod> -- sh Container FS/ENV içinde gez, manuel test et
5️⃣ Kod / YAML düzelt → kubectl apply Hatasız deploy ettir

💡 Pro İpuçları

  • --previous unutma! Yeni container başladığında eski loglar kaybolur. CrashLoopBackOff'da mutlaka --previous kullan 🔑.
  • imagePullPolicy: Never local testlerde (kind, minikube, Docker Desktop) işinizi kolaylaştırır. Prod'da IfNotPresent veya Always kullanın.
  • Liveness/Readiness probe ekleyin. Uygulamanız sağlıksa restart atmasın, sağlıksa trafik almasın 🛡.
  • Secret'ları plain YAML'e yazmayın! valueFrom: secretKeyRef ile Kubernetes Secret'ten çekin 🔐.

Hazırsan sıradaki hataya geçelim — ImagePullBackOff / ErrImagePull 🐳. Görüşmek üzere! 👋


🛠 Hata 3: Readiness Probe Başarısızlığı - Trafik Gelmiyor Ama Pod Running

Selam! 👋 Bugün Readiness Probe ile Liveness Probe arasındaki ince ama kritik farkı, yanlış bir path/port tanımının nasıl "Pod Running ama trafik yok" kabusuna yol açtığını ve bunu nasıl düzelteceğimizi anlatacağım. Hazırsan başlayalım 🚀

🎯 Readiness vs Liveness — Neden Farklı?

Probe Ne Zaman Tetiklenir? Ne Olur?
Liveness Container çöktüğünde veya döngüye girdiğinde Pod yeniden başlatılır (restart)
Readiness Container trafiğe hazır değilse (ör. başlangıç, migration, cache warm‑up) Pod Service’den çıkarılır, trafik gitmez ama restart edilmez

Özet: Liveness = "Yaşıyorum mu?" 🤔, Readiness = "İşe hazır mıyım?" ✅


❗️ Hata Senaryosu: Yanlış /healthz Path’i

Deployment dosyamızda readiness probe’un path: /healthz olarak tanımlandığını varsayalım. Uygulamanın aslında /ready endpoint’i var. Sonuç? Pod Running gözükür ama Service trafiği hiç iletmez.

deployment-readiness-fail.yaml (yanlış tanım)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: myorg/my-app:1.0
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /healthz          # ❌ Yanlış path
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10

🔍 kubectl describe pod Çıktısı — "Readiness probe failed"

$ kubectl describe pod my-app-xyz123
...
Events:
  Type     Reason                 Age   From               Message
  ----     ------                 ----  ----               -------
  Warning  Unhealthy              10s   kubelet            Readiness probe failed: HTTP probe failed with statuscode: 404
  Normal   Pulling                30s   kubelet            Pulling image "myorg/my-app:1.0"
  Normal   Pulled                 28s   kubelet            Successfully pulled image "myorg/my-app:1.0"
  Normal   Created                28s   kubelet            Created container my-app
  Normal   Started                27s   kubelet            Started container my-app

Ne oluyor burada?

  • Pod Running durumunda ✔️
  • Ama Readiness probe 404 dönüyor ❌ → Service endpoint listesinden pod çıkarılır → Hiç trafik gelmez 🚫

🛠 Container İçinden Elle Test — kubectl exec + curl

Pod içine girip doğru endpoint’in çalışıp çalışmadığını kontrol edelim:

# Pod adını al
POD=$(kubectl get pods -l app=my-app -o jsonpath='{.items[0].metadata.name}')

# Container içinde curl
kubectl exec -it $POD -- curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/ready
# Beklenen çıktı: 200

kubectl exec -it $POD -- curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/healthz
# Çıktı: 404 (yanlış path)

İpucu: initialDelaySeconds çok kısaysa uygulama henüz /ready endpoint’ini açmamış olabilir. Probe hemen 404 alır → pod “Not Ready” kalır.


✅ Çözüm: Doğru Path/Port + initialDelaySeconds Ayarı

Doğru endpoint /ready ve uygulamanın başlangıçta 10‑15 sn içine hazırlanacağını varsayarsak:

deployment-readiness-fixed.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: myorg/my-app:1.0
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /ready               # ✅ Doğru path
            port: 8080
          initialDelaySeconds: 15      # ⏱ Uygulama başlasın diye biraz bekle
          periodSeconds: 10
          timeoutSeconds: 3
          failureThreshold: 3

Ne değişti?

  • path: /ready → artık 200 OK dönüyor ✅
  • initialDelaySeconds: 15 → probe, container tam ayağa kalkmadan test etmiyor ⏳
  • failureThreshold: 3 → geçici bir hata pod’u hemen “Not Ready” yapmıyor 🛡

Uygulama bu deployment ile yeniden rollout edilince:

kubectl rollout restart deployment/my-app

Pod’lar Ready olur, Service endpoint listesine girer ve trafik akmaya başlar 🎉


📌 Küçük Hatırlatma Listesi

  • Readiness ≠ Liveness — karıştırma!
  • Probe path/port uygulamanın gerçek endpoint’leriyle birebir eşleşmeli
  • initialDelaySeconds ve periodSeconds uygulama başlangıç süresine göre ayarla
  • kubectl exec + curl ile container içinde doğrula — en hızlı debug yolu 🚀

Bir sonraki bölümde Liveness Probe yanlış yapılandırmasının pod’u sürekli restart etmesine neden olan senaryoyu inceleyeceğiz. Görüşmek üzere! 👋


🔁 Sistematik Hata Ayıklama Metodolojisi: 4 Adımda Rollout Sorunu Çözme

Rollout hatalarıyla uğraşırken adım adım, tekrarlanabilir bir şablon kullanmak size hem zaman kazandırır hem de kök nedeni kaçıramazsınız. Aşağıdaki 4 aşama, herhangi bir Kubernetes dağıtımında (Deployment, StatefulSet, DaemonSet…) işinizi kolaylaştıracak bir debug checklist gibidir 🎯

1️⃣ kubectl rollout status — Dağıtımın neresinde?

  • Ne arıyorsunuz?
    • Progressing → henüz tamamlanmadı, bekleyin veya ilerlemeyi izleyin.
    • ReplicaFailure / Failed → en az bir pod hedefe ulaşamadı.
    • Timeout → progressDeadlineSeconds doldu, rollout durdu.
  • İpucu: --watch ile canlı takip edin, kubectl rollout pause/resume ile kontrol elinizde tutun.

2️⃣ kubectl describe pod <pod‑adı> — Event’ler ne diyor?

  • Odaklanılacak alanlar:
    • Events bölümünde FailedCreate, FailedScheduling, ImagePullBackOff, CrashLoopBackOff gibi hatalar.
    • Conditions → Ready, ContainersReady, PodScheduled.
    • Init Containers varsa onların durumu da kontrol edin.
  • İpucu: kubectl get events --sort-by=.metadata.creationTimestamp ile son olayları sıralayın.

3️⃣ kubectl logs <pod‑adı> [-c <container>] [--previous] — Uygulama ne söylüyor?

  • Kontrol listesi:
    • Startup logları → config hatası, migration eksikliği, port çakışması.
    • Stack trace / exception → kod seviyesindeki hata.
    • --previous → çökmüş container’ın son loglarını görmek için hayati.
  • İpucu: kubectl logs -f ile canlı takip, --tail=200 ile son satırları hızlıca inceleyin.

4️⃣ kubectl exec -it <pod‑adı> -c <container> -- /bin/sh — Canlı debug 🎮

  • Ne yapabilirsiniz?
    • Dosya sistemi, env değişkenleri, config dosyalarını doğrulayın.
    • curl localhost:port/healthz veya nc -zv ile network erişimini test edin.
    • Gerekli araçları (curl, netcat, jq, ps, top) container içinde kuruluysa kullanın; yoksa kubectl debug ile efemer bir sidecar ekleyin.
  • İpucu: kubectl cp ile log/dosya çekip lokalde inceleyin.

📋 Tek komut bloğu — Sıralı çalıştırıp çıktıyı toplayın

# 1️⃣ Rollout durumu
kubectl rollout status deployment/<deployment‑adı> --watch

# 2️⃣ Sorunlu pod’u bul ve event’leri oku
kubectl get pods -l app=<uygulama‑etiketi> --field-selector=status.phase!=Running
kubectl describe pod <sorunlu‑pod‑adı>

# 3️⃣ Logları incele (mevcut ve önceki container)
kubectl logs <sorunlu‑pod‑adı> -c <container‑adı> --tail=200
kubectl logs <sorunlu‑pod‑adı> -c <container‑adı> --previous --tail=200

# 4️⃣ Container içine girip canlı debug
kubectl exec -it <sorunlu‑pod‑adı> -c <container‑adı> -- /bin/sh

Bu şablonu her rollout sorununda aynen uyguladığınızda:

  • ✅ Hangi adımda takıldığınız netleşir.
  • ✅ Log/event/CLI çıktıları biriktirilerek post‑mortem raporu kolaylaşır.
  • ⛔ Aynı hata tekrarlanmaz, çünkü kök neden sistematik bulunur.

Hazırsanız bir sonraki bölümde bu adımları bir gerçek senaryo üzerinde birlikte uygulayalım 🚀


🛠 İleri Seviye İpuçları: Rollout Stratejileri, PodDisruptionBudget ve ArgoCD/Flux Entegrasyonu

Temel debugging'i bitirdik, şimdi prodüksiyona güvenle deploy etmek için elimize alabileceğimiz ileri seviye stratejilere bakalım 🚀

🔁 RollingUpdate: maxSurge ve maxUnavailable Ayarlamaları

Deployment'ın strategy.rollingUpdate kısmında bu iki parametre nasıl ölçekleneceğini belirler:

  • maxSurge → Kaç ekstra pod başlatılabilir (varsayılan %25). Yüksek tutarsanız rollout hızlanır ama kaynak ister.
  • maxUnavailable → Kaç pod aynı anda down olabilir (varsayılan %25). Sıfır yaparsanız sıfır downtime ama rollout yavaşlar.

Kısaca: maxSurge: 25%, maxUnavailable: 0 → "Yeni podlar hazır olana kadar eskileri dokunma" derseniz kesintisiz güncelleme elde edersiniz ✅

🛡 PodDisruptionBudget (PDB): Kesintisiz Güncellemenin Sigortası

PDB, kluster yöneticisinin (veya otomatik eviction'ların) bir anda çok pod'u kill etmesini engeller.
Özetle: "En az X pod her zaman ayakta olmalı" diyorsunuz.

Ne işe yarar? Voluntary disruptions (node drain, upgrade, PDB-aware tooling) sırasında minAvailable sayısını garanti altına alır ❗️

Hadi basit bir PDB YAML'i yazalım:

# poddisruptionbudget-example.yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: backend-pdb
  namespace: production
spec:
  minAvailable: 3
  selector:
    matchLabels:
      app: backend

Ne oluyor burada?

  • minAvailable: 3 → Herhangi bir disruption anında en az 3 backend podu Ready kalmak zorunda
  • selector → Hangi pod'ları koruyacağınızı label ile seçersiniz

Bu sayede kubectl drain node-x komutu PDB'yi kırmadan bekler veya iptal eder 🛠

🔄 GitOps ile Otomatik Rollback: ArgoCD ve Flux

Araç Ne İşe Yarar?
ArgoCD Git'teki desired state ile cluster'daki actual state'i sürekli karşılaştırır, drift olursa auto-sync veya manual approve ile düzeltir. Rollout başarısız olursa argocd app rollback tek komutla geri alırsınız 🎯
Flux HelmRelease / Kustomization resource'ları watch eder, sağlık kontrolleri (health checks) başarısız olursa otomotik rollback tetikler. flux suspend / flux resume ile kontrol elinizde ✅

Özet: Her ikisi de "Git tek doğru kaynaktır" prensibiyle çalışır. Rollout bozulursa Git'e geri dönüş = Cluster'a geri dönüş olur 🔁


İpucu: PDB + maxUnavailable: 0 + GitOps auto-rollback üçlüsü ile "gece yarısı deploy, sabah kahvesi molası" senaryosu artık korkulacak bir şey değil ☕️


🎯 Bonus Tavsiye: Günlük Hayatını Kurtaran Kubectl Alias ve Plugin'ler

Kubernetes ile her gün boğuşuyorsanız, tekrarlayan komutları kısaltmak ve görselleştirme araçları eklemek size saatler kazandırır 🚀. Ben de .bashrc / .zshrc dosyama şu alias’ları ekledim, hayatım o kadar kolaylaştı ki siz de deneyin.

🔧 Sık Kullandığım Alias’lar

  • kdp → kubectl describe pod
  • klp → kubectl logs --previous
  • kgp → kubectl get pods -o wide
  • kgs → kubectl get svc
  • kctx → kubectl config use-context
  • kns → kubectl config set-context --current --namespace

İpucu: Alias’ları kendi iş akışınıza göre genişletin; kgd='kubectl get deploy' gibi.

# ~/.bashrc veya ~/.zshrc içine ekleyin
alias kdp='kubectl describe pod'
alias klp='kubectl logs --previous'
alias kgp='kubectl get pods -o wide'
alias kgs='kubectl get svc'
alias kctx='kubectl config use-context'
alias kns='kubectl config set-context --current --namespace'

Kaydedip source ~/.bashrc (veya source ~/.zshrc) çalıştırın, hemen test edin ✅.

🛠 Krew ile Kurulu Olması Gereken Plugin’ler

Plugin Ne İşe Yarar? Kurulum (tek satır)
kubectl-neat Çıktıları temizler, gereksiz alanları gizler 🎯 kubectl krew install neat
kubectl-tree Kaynakları hiyerarşik ağaç görünümünde gösterir 🌳 kubectl krew install tree
stern Birden fazla pod’un loglarını tek terminalde takip eder 🔁 kubectl krew install stern
# Hepsini tek seferde kurmak isterseniz:
kubectl krew install neat tree stern

🎁 Neden Bu Kutuyu Eklemelisiniz?

  • Az yaz, çok yap: Alias’larla parmaklarınız yorulmaz.
  • Görsel hız: kubectl tree ile bağımlılıkları bir bakışta görürsünüz.
  • Log takibi: stern sayesinde birden fazla pod logunu tek pencerede, renkli ve gerçek zamanlı izlersiniz.

Bu araçları kutunuza ekleyin, günlük işlerinizde zaman kazanın ve hata ayıklama sürecinizi keyifli hale getirin 😎.


🎯 Son Söz: Rollout Artık Korkulu Rüya Değil, Kontrollü Bir Süreç

Harika bir yolculuktu, anladığım kadarıyla 🎉

Bu yazıda sistematik yaklaşım, doğru araçlar ve laboratuvar pratiği üçgeninin nasıl bir rollout sürecini "korkulu rüyadan" kontrollü, gözlemlenebilir ve hatayı öpücükleyen bir süreçe dönüştürdüğünü gördük.

Özetle ne öğrendik?

  • Planlama önce, deploy sonra — Strateji (canary, blue-green, rolling) işin zekasıdır 🧠
  • Gözlem olmadan ilerleme yok — Metrik, log, trace üçlüsü sizin "altın gözlerinizdir" 👁️
  • Otomatik geri alma hayat kurtarır — kubectl rollout undo ya da Argo Rollouts abort butonu paniğinizi alır ✅
  • Laboratuvar = Güvenli hata yapma alanı — Production'a gelmeden önce cluster'ınızda deneyin, bozun, onarın 🛠️

💪 Siz de deneyin, hata yapın, öğrenin

Hiçbir okuma, kendi cluster'ınızda kubectl apply yapıp pod'ların nasıl ayağa kalktığını, canary trafiğin nasıl kaydığını, bir hata olduğunda metric'lerin nasıl alarm çaldığını izlemekle Konkurmaz.

  • Küçük bir test namespace'i açın 🧪
  • Basit bir Deployment + Service kurun
  • Canary stratejisiyle yeni bir image rollout edin
  • kubectl rollout status ve kubectl rollout history ile izleyin
  • Kasıtlı bozuk bir image push edin → otomatik rollback'i seyreedin 😎

Hata yapmaktan çekinmeyin. Her hata, bir sonraki production incident'ını önleyen bir ders.


Hadi, cluster'ını aç ve rollout yap! 🚀

Sorun yaşarsan, loglara bak, metric'lere bak, geri al — sonra tekrar dene. Bu döngü sizi her seferinde biraz daha senior yapar.

Görüşmek üzere, sağlıklı deploylar dilerim! 👋


Bu içerik tamamen yapay zeka destekli otomasyon sistemi ile üretilmiştir.

Burak Sağlık

Burak Saglik

©2024 Desing and Developed by @Burak Sağlık

All rights reserved