DEV Community

Cover image for Kubernetes Probe'larını Bozarak Öğrenmek — Liveness, Readiness ve Startup
Taha Yağız Güler
Taha Yağız Güler

Posted on

Kubernetes Probe'larını Bozarak Öğrenmek — Liveness, Readiness ve Startup

Probe nedir, neden gerekli?

Kubernetes bir pod'un "çalışıyor" olduğunu bilir — container ayaktaysa çalışıyor demek. Ama "çalışıyor" ile "sağlıklı" aynı şey değil. Uygulama deadlock'a girmiş olabilir, DB bağlantısını kaybetmiş olabilir, henüz başlamayı tamamlamamış olabilir.

Probe'lar Kubernetes'e şunu söyler: "Bu container'ın içindeki uygulamayı benim istediğim şekilde kontrol et."

Üç probe türü var, her biri farklı bir soruyu cevaplıyor:

Probe Soru Başarısız olursa
Startup Uygulama başladı mı? Pod restart
Readiness Traffic almaya hazır mı? Traffic kesilir, pod durmaz
Liveness Uygulama sağlıklı mı? Pod restart

En kritik fark readiness ile liveness arasında — birinde pod ölür, diğerinde ölmez.


Lab ortamı

Docker Desktop üzerinde kind cluster, tek node:

kind create cluster --name probe-lab
kubectl create namespace probe-lab
kubectl config set-context --current --namespace=probe-lab
Enter fullscreen mode Exit fullscreen mode

Senaryo 1 — Bozuk Liveness Probe

Nginx 80 portunda çalışıyor ama liveness probe 9999'a bakıyor. Ne olacak?

apiVersion: apps/v1
kind: Deployment
metadata:
  name: liveness-broken
  namespace: probe-lab
spec:
  replicas: 1
  selector:
    matchLabels:
      app: liveness-broken
  template:
    metadata:
      labels:
        app: liveness-broken
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80

        livenessProbe:
          httpGet:
            path: /
            port: 9999        # nginx burada dinlemiyor
          initialDelaySeconds: 5
          periodSeconds: 5
          failureThreshold: 3 # 3 başarısız → restart
Enter fullscreen mode Exit fullscreen mode
kubectl apply -f liveness-broken.yaml
kubectl get pods -w
Enter fullscreen mode Exit fullscreen mode

Çıktı:

NAME                    READY   STATUS             RESTARTS   AGE
liveness-broken-xxx     1/1     Running            0          8s
liveness-broken-xxx     1/1     Running            1          23s
liveness-broken-xxx     1/1     Running            2          38s
liveness-broken-xxx     0/1     CrashLoopBackOff   3          53s
Enter fullscreen mode Exit fullscreen mode

Events'e bakınca:

Warning  Unhealthy  Liveness probe failed: dial tcp: connection refused
Warning  Killing    Container failed liveness probe, will be restarted
Enter fullscreen mode Exit fullscreen mode

Ne öğrendim: Liveness başarısız olunca Kubernetes container'ı öldürüp yeniden başlatıyor. Ama sorun devam ettiği için sonsuz döngüye giriyor — buna CrashLoopBackOff deniyor. Production'da bu alarm tetikler, on-call mühendisi uyandırır.


Senaryo 2 — Bozuk Readiness Probe

Aynı nginx, bu sefer readiness probe var olmayan bir path'e bakıyor: /nonexistent. Liveness doğru. Ne olacak?

livenessProbe:
  httpGet:
    path: /        # doğru — pod ölmeyecek
    port: 80

readinessProbe:
  httpGet:
    path: /nonexistent   # 404 dönecek — probe başarısız
    port: 80
  initialDelaySeconds: 3
  periodSeconds: 5
  failureThreshold: 3
Enter fullscreen mode Exit fullscreen mode
kubectl get pods -w
Enter fullscreen mode Exit fullscreen mode

Çıktı:

NAME                     READY   STATUS    RESTARTS   AGE
readiness-broken-xxx     0/1     Running   0          10s
readiness-broken-xxx     0/1     Running   0          60s
readiness-broken-xxx     0/1     Running   0          2m
Enter fullscreen mode Exit fullscreen mode

RESTARTS hiç artmıyor. Pod ölmüyor. Ama 0/1 — traffic almıyor.

Service endpoint'e bakınca:

kubectl get endpoints readiness-broken
Enter fullscreen mode Exit fullscreen mode
NAME               ENDPOINTS   AGE
readiness-broken   <none>      2m
Enter fullscreen mode Exit fullscreen mode

<none> — Kubernetes bu pod'u endpoint listesinden çıkardı. Hiçbir istek buraya gelmiyor.

Ne öğrendim: Readiness ile liveness'ın farkı tam burada netleşiyor. Liveness başarısız → pod restart. Readiness başarısız → pod Running kalıyor, sadece traffic kesiliyor. Pod'u öldürmek her zaman doğru cevap değil — bazen sadece "biraz bekle, hazır olunca gönder" demek yeterli.


Senaryo 3 — Startup Probe Olmadan Yavaş Uygulama

Uygulama başlamak için 40 saniye bekliyor. Startup probe yok, liveness 20 saniyede restart ediyor.

lifecycle:
  postStart:
    exec:
      command: ["/bin/sh", "-c", "sleep 40"]  # 40 saniye beklet

livenessProbe:
  httpGet:
    path: /
    port: 80
  initialDelaySeconds: 5
  periodSeconds: 5
  failureThreshold: 3   # 5 + (3*5) = 20 saniyede restart
  # uygulama 40 saniyede hazır — hiç hazır olamaz
Enter fullscreen mode Exit fullscreen mode

Sonuç: CrashLoopBackOff. Uygulama hiç ayağa kalkamıyor çünkü liveness onu hazır olmadan öldürüyor.

Şimdi startup probe ekle:

startupProbe:
  httpGet:
    path: /
    port: 80
  periodSeconds: 5
  failureThreshold: 12  # 12 * 5 = 60 saniye bekler
  # startup geçene kadar liveness çalışmaz

livenessProbe:
  httpGet:
    path: /
    port: 80
  initialDelaySeconds: 5
  periodSeconds: 10
  failureThreshold: 3
Enter fullscreen mode Exit fullscreen mode

Sonuç:

NAME                  READY   STATUS    RESTARTS
slow-app-fixed-xxx    1/1     Running   0        ← restart yok
Enter fullscreen mode Exit fullscreen mode

Ne öğrendim: Startup probe, liveness için bir "koruma kalkanı" görevi görüyor. "Ben hazır olana kadar dokunma" diyor. Spring Boot, JVM tabanlı uygulamalar, büyük model yükleyen ML servisleri — bunların hepsinde startup probe zorunlu.


Senaryo 4 — HPA ile Readiness Entegrasyonu

Bu senaryoda yük testi yaparak HPA'yı tetikledim ve yeni açılan pod'ların readiness geçene kadar traffic almadığını gözlemledim.

Önce metrics-server'ı kur:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

kubectl patch deployment metrics-server \
  -n kube-system \
  --type='json' \
  -p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'
Enter fullscreen mode Exit fullscreen mode

HPA tanımı:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-demo
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: hpa-demo
  minReplicas: 1
  maxReplicas: 4
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 20
Enter fullscreen mode Exit fullscreen mode

Yük testi:

kubectl run load-generator \
  --image=busybox:1.28 \
  --restart=Never \
  -n probe-lab \
  -- /bin/sh -c "while true; do wget -q -O- http://hpa-demo; done"
Enter fullscreen mode Exit fullscreen mode

HPA çıktısı:

NAME       TARGETS        REPLICAS
hpa-demo   2%/20%         1
hpa-demo   198%/20%       2        ← scale-out başladı
hpa-demo   156%/20%       4
hpa-demo   2%/20%         4
hpa-demo   2%/20%         1        ← scale-in, yük durdu
Enter fullscreen mode Exit fullscreen mode

Yeni pod açılırken endpoint listesi:

NAME       ENDPOINTS                    
hpa-demo   10.x.x.x:80                 ← sadece hazır pod
hpa-demo   10.x.x.x:80,10.x.x.x:80    ← ikinci pod readiness geçince eklendi
Enter fullscreen mode Exit fullscreen mode

Ne öğrendim: HPA pod açtığında o pod hemen traffic almıyor. Readiness probe geçene kadar endpoint listesine girmiyor. Bu çok kritik — yük altında açılan pod hazır olmadan traffic alırsa hata oranı artar. Readiness probe bu geçiş sürecini güvenli hale getiriyor.


Production'da Dikkat Ettiğim Şeyler

Liveness probe'a bağımlı servis kontrolü koyma:

# YANLIŞ — DB geçici kapanırsa tüm pod'lar cascade restart yapar
livenessProbe:
  httpGet:
    path: /health/db
    port: 8080

# DOĞRU — liveness sadece "ben ayaktayım" sorusunu sormalı
livenessProbe:
  httpGet:
    path: /health/live
    port: 8080

readinessProbe:
  httpGet:
    path: /health/ready   # DB bağlantısı burada kontrol edilir
    port: 8080
Enter fullscreen mode Exit fullscreen mode

Threshold değerlerini varsayılan bırakma:

livenessProbe:
  failureThreshold: 5    # 3 değil — geçici ağ sorunlarına tolerans
  periodSeconds: 10
  timeoutSeconds: 5      # 1 saniye çok kısa
Enter fullscreen mode Exit fullscreen mode

Startup probe'u atlama: Eğer uygulamanın başlangıç süresi değişkense — farklı ortamlarda farklı sürebiliyorsa — startup probe yaz. initialDelaySeconds ile tahmin yürütmek yerine gerçek hazırlık durumunu kontrol et.


Özet

Bu lab'dan önce probe'ları biliyordum ama gözlemlememştim. Şimdi şunu rahatlıkla söyleyebiliyorum:

  • Liveness → "uygulama dondu mu?" — başarısız olursa restart
  • Readiness → "traffic almaya hazır mı?" — başarısız olursa sadece traffic kesilir
  • Startup → "uygulama başlamayı tamamladı mı?" — liveness için koruma kalkanı

Ve en önemli şey: readiness ile liveness'ı aynı endpoint'e bağlamak işe yarıyor ama doğru değil. İkisi farklı soruları soruyor, farklı endpoint'ler hak ediyorlar.


Bu yazı, bir mülakatta aldığım geri bildirimi uygulamalı olarak çalışma serim. Serinin ilk yazısı: Terraform + Terragrunt + Ansible: A Hands-On Learning Journey

Top comments (0)