
Kubernetes Liveness ve Readiness Probelarında Zincirleme Çökmelere Yol Açan 5 Konfigürasyon Hatası

Giriş
Gece saat 03:15. PagerDuty alarmı çalıyor. Kümelerinizden birindeki 120 podluk bir deployment, aniden toplu olarak CrashLoopBackOff durumuna geçmiş. Loglara baktığınızda uygulamanızda kritik bir hata (panic veya segfault) olmadığını görüyorsunuz. Gelen trafik normal seviyelerde. Peki ne oldu? Yaklaşık 400ms süren anlık bir network dalgalanması, veritabanı bağlantı havuzunuzda mikro saniyelik bir gecikme yarattı. Bu gecikme, aşırı hassas ayarlanmış Liveness Probe uç noktalarınızın timeouta düşmesine neden oldu. Kubelet, 120 podu aynı anda “ölü” kabul edip yeniden başlattı. Veritabanına aynı anda açılmaya çalışılan 120 yeni bağlantı havuzu veritabanını kilitledi ve sistem saatlerce toparlanamadı.
Kubernetes ortamında production seviyesinde sistemler tasarlarken, livenessProbe ve readinessProbe tanımlarının eksikliği ya da yanlış kurgulanması, sadece ilgili podu değil, tüm mikroservis ekosistemini aşağı çeken zincirleme çökmelerin (cascading failures) bir numaralı tetikleyicisidir. Kubelet, sizin niyetinizi okuyamaz; sadece verdiğiniz konfigürasyona göre hareket eden acımasız bir state-machine’dir. Pod Lifecycle Event Generator (PLEG), her döngüde bu probe’ları kontrol eder ve kurallara uymayanı sistemden siler.
Bu metinde, teorik dökümanların ötesine geçerek bizzat production yangınlarında test edilmiş, K8s 1.16 ve sonrasındaki özelliklerle desteklenen 5 kritik probe yapılandırma hatasını, bunların sistem üzerindeki yıkıcı etkilerini ve kalıcı çözümlerini inceleyeceğiz.
İçindekiler
- Hata 1: Readiness Probe İçerisine Harici Bağımlılıkların (Database, Cache) Eklenmesi
- Hata 2: Liveness ve Readiness Probe’lar İçin Aynı Uç Noktanın (Endpoint) Kullanılması
- Hata 3: CFS Quota Limitleri Altında Agresif Timeout ve Threshold Değerleri
- Hata 4: Yavaş Kalkan Uygulamalarda Startup Probe Yerine InitialDelaySeconds İstismarı
- Hata 5: Probe İsteklerinde Ağır I/O veya CPU Döngüleri Tüketmek
- Pratik Öneriler / Production Notları
- Sık Sorulan Sorular
- Sonuç
Hata 1: Readiness Probe İçerisine Harici Bağımlılıkların (Database, Cache) Eklenmesi
Neden Olur: Yazılım mühendislerinin içgüdüsel bir yaklaşımı vardır: “Eğer uygulamam veritabanına ya da Redis’e bağlanamıyorsa, gelen HTTP isteklerine cevap veremez. O halde readiness probe başarısız olmalı ve pod trafiği kesmelidir.” Bu mantık monolitik sanal makinelerde işe yarayabilir, ancak Kubernetes’in dinamik yük dengeleme (load balancing) mantığında felakete davetiye çıkarır.
Nasıl Tespit Edilir: kubectl describe pod <pod-name> çıktısında readiness probe’un sık sık başarısız olduğunu ve podun Endpoints listesinden çıkarılıp tekrar eklendiğini (flapping) görürsünüz. Eğer Redis kümenizde anlık bir p99 gecikmesi (örneğin 15ms’den 120ms’ye çıkış) yaşanırsa, Kubernetes anında tüm podların trafiğini keser. Müşteriler, uygulamanız ayakta olmasına rağmen Service katmanında 503 Service Unavailable hatası almaya başlar.
Gerçek Olay Örneği: 2021 yılındaki bir e-ticaret sepet servisi olayında, arka plandaki RabbitMQ kümesinde yaşanan 2 saniyelik bir lider seçimi (leader election) kesintisi, sepet servisinin readiness uç noktasının başarısız olmasına yol açtı. 80 podluk deployment, kendini load balancer’dan çekti. RabbitMQ 2 saniye sonra düzelse de, Kubernetes Endpoints controller’ın state’i senkronize etmesi ve trafiği tekrar yönlendirmesi 45 saniye sürdü. 2 saniyelik altyapı kesintisi, 45 saniyelik müşteri kesintisine dönüştü.
Nasıl Çözülür: Readiness probe, sadece ve sadece podun kendisinin HTTP isteklerini kabul etmeye ve ağ bağlantılarını dinlemeye (socket bind) hazır olup olmadığını kontrol etmelidir. Eğer veritabanı ulaşılamaz durumdaysa, bırakın uygulamanız trafiği alsın ve istemciye graceful bir şekilde 500 Internal Server Error veya önbellekten (fallback) 200 OK dönsün. Böylece circuit breaker pattern’lerini (örneğin Istio veya uygulama içi Resilience4j) çalıştırabilirsiniz.
Hata 2: Liveness ve Readiness Probe’lar İçin Aynı Uç Noktanın (Endpoint) Kullanılması
Neden Olur: Geliştiriciler genellikle frameworklerin varsayılan /health endpoint’ini her iki probe türüne de kopyala-yapıştır ile eklerler. Liveness (Canlılık) ve Readiness (Hazır Olma) bambaşka state’leri temsil eder. Liveness başarısız olursa Kubelet podu SIGTERM (ve ardından SIGKILL) ile öldürür. Readiness başarısız olursa Service podu trafik havuzundan çıkarır.
Nasıl Tespit Edilir: Podlarınız ağır yük (spiky traffic) altına girdiğinde, CPU kullanımı artar ve thread havuzu dolduğu için /health endpoint’ine gelen isteklere zamanında cevap veremez. Eğer aynı endpoint’i kullanıyorsanız, Liveness probe fail olur. Sistem, zaten aşırı yük altında ezilen bir podu trafiği keserek rahatlatmak yerine, doğrudan öldürür (kill). Kalan podların üzerine daha fazla yük biner ve saniyeler içinde tüm cluster domino taşı gibi çöker.
Trade-off Analizi: Ortak bir /health kullanmak konfigürasyon kolaylığı sağlar ancak hata izolasyonunu yok eder. Ayrıştırılmış uç noktalar (örneğin /health/liveness ve /health/readiness) ekstra kodlama gerektirir ancak pod ömrü yönetiminde size tam kontrol sunar.
Nasıl Çözülür:
1. Liveness çok “aptal” olmalıdır. Sadece uygulamanın deadlock’a girip girmediğini kontrol etmelidir. Çoğu durumda statik bir return true; döndüren bir HTTP 200 ucu yeterlidir.
2. Readiness ise uygulamanın internal state’ine bakabilir (thread havuzu doluluk oranı gibi).
# KÖTÜ KULLANIM
livenessProbe:
httpGet:
path: /health
readinessProbe:
httpGet:
path: /health
# İYİ KULLANIM
livenessProbe:
httpGet:
path: /health/liveness # Statik 200 OK döner, sadece ana thread ayakta mı diye bakar
readinessProbe:
httpGet:
path: /health/readiness # Uygulama boot state'ini kontrol eder
Hata 3: CFS Quota Limitleri Altında Agresif Timeout ve Threshold Değerleri
Neden Olur: Kubernetes’te container CPU limitleri, Linux kernel’indeki Completely Fair Scheduler (CFS) quota’ları ile uygulanır. Eğer uygulamanız resources.limits.cpu: 500m olarak ayarlandıysa ve 100ms’lik döngüde 50ms’lik kotasını erken tüketirse, kalan 50ms boyunca kernel uygulamanızı dondurur (throttle). Bu esnada timeoutSeconds: 1 ve failureThreshold: 1 olarak ayarlanmış agresif bir probe gelirse, dondurulmuş uygulama cevap veremez ve anında öldürülür.
Nasıl Tespit Edilir: Prometheus’ta container_cpu_cfs_throttled_periods_total metriklerinde ani sıçramalar görürsünüz. Bununla eş zamanlı olarak podlar OOMKilled olmadan, sadece Liveness probe failed: context deadline exceeded mesajıyla restart olur.
Gerçek Olay Örneği: Bir JVM (Java) uygulamasında, Garbage Collector (G1GC) Stop-the-World pause’u 1.4 saniye sürdü. K8s deployment dosyasında Liveness timeoutSeconds: 1 olarak ayarlandığı için, Kubelet GC işlemi yapan podu donmuş zannedip SIGTERM gönderdi. Sonuç? Yeniden başlayan podun JVM ısınma (warmup) periyodu CPU limitlerine takıldı ve sistem 45 dakika boyunca loop’tan çıkamadı.
Nasıl Çözülür: Probe’lara tolerans tanıyın. Kubelet varsayılan olarak her 10 saniyede bir kontrol yapar (periodSeconds: 10). Başarısızlık eşiğini her zaman yüksek tutun.
livenessProbe:
httpGet:
path: /health/liveness
port: 8080
periodSeconds: 10
timeoutSeconds: 5 # CFS Throttle veya GC Pause için pay bırakıldı
failureThreshold: 3 # Üst üste 3 kez başarısız olmadan öldürme
successThreshold: 1
Hata 4: Yavaş Kalkan Uygulamalarda Startup Probe Yerine InitialDelaySeconds İstismarı
Neden Olur: Spring Boot, büyük makine öğrenimi modellerini belleğe yükleyen Python servisleri veya eski tip (legacy) monolitik uygulamaların ayağa kalkıp trafiğe hazır hale gelmesi 60 saniyeden uzun sürebilir. K8s 1.16 öncesinde, bu uygulamaların ayağa kalkmadan Liveness tarafından öldürülmesini engellemek için initialDelaySeconds: 120 gibi devasa değerler verilirdi.
Neden Ölümcüldür: Uygulamanız production’da 10. saniyede deadlock’a girerse, Kubelet’in bunu fark etmesi ve müdahale etmesi için geriye kalan 110 saniye boyunca beklemesi gerekir. Bu, hatalı podun load balancer’da kalmasına (Readiness’ın da aynı değere sahip olduğu senaryolarda) veya uygulamanın felç durumunda kalarak kaynak tüketmesine sebep olur.
Nasıl Çözülür: Kubernetes 1.16 ile hayatımıza giren startupProbe‘u kullanın. Startup probe, başarısız olduğu sürece Liveness ve Readiness probe’larını susturur. Başarılı olduğu anda devreden çıkar ve kontrolü diğer probe’lara bırakır.
startupProbe:
httpGet:
path: /health/liveness
port: 8080
failureThreshold: 30
periodSeconds: 10
# Uygulamaya ayağa kalkması için maksimum 300 saniye (30 * 10s) süre tanır.
# Eğer 15. saniyede (2. denemede) kalkarsa, anında diğer probe'lara geçer. 300 saniye beklemez.
Hata 5: Probe İsteklerinde Ağır I/O veya CPU Döngüleri Tüketmek
Neden Olur: /health endpoint’i arka planda diskte log dosyası sayıyor, bir objeyi JSON’a serialize edip boyutunu kontrol ediyor veya asimetrik şifreleme ile token doğruluyorsa, probe’un kendisi uygulamanızı DDoS saldırısına uğratıyor demektir.
Nasıl Tespit Edilir: Profiling toolları (örneğin pprof, async-profiler) ile bakıldığında, CPU döngülerinin %15-20’sinin sadece Kubelet’ten gelen health check isteklerine ayrıldığı görülür. Node.js gibi single-threaded event-loop mimarilerinde ağır bir health endpoint, diğer tüm HTTP isteklerini bloke eder.
Gerçek Olay Örneği: Bir Node.js kimlik doğrulama servisi, readiness probe içerisinde veritabanına basit bir SELECT 1 atmak yerine, ORM üzerinden 12 tablolu bir health-check metodu çağırıyordu. 10 saniyede bir 50 pod üzerinden gelen bu sorgular, veritabanı bağlantı havuzunu (connection pool) tüketti. P99 yanıt süresi 45ms’den 1200ms’ye çıktı.
Nasıl Çözülür: Probe uç noktalarında atomik flag okumaları kullanın. Eğer arka planda bir metrik ölçülmesi gerekiyorsa, ayrı bir arka plan thread’i asenkron olarak state’i güncellemeli, HTTP endpoint’i ise sadece bellekteki (in-memory) boolean veya integer flag değerini okumalıdır. O(1) karmaşıklığında çalışmayan hiçbir algoritma probe endpointine girmemelidir.
Pratik Öneriler / Production Notları
- Ayrı Port Kullanımı: Uygulama metriklerini, prometheus endpointlerini ve probe rotalarını (
/health,/metrics) ana müşteri trafiğinin geldiği porttan ayırın (örneğin ana trafik 8080, management 8081). Böylece ana thread pool tükense bile, Kubelet yönetim portundan uygulamanın Liveness durumunu sağlıklı bir şekilde alabilir. - Kube-state-metrics İzleme: Prometheus üzerinde
kube_pod_container_status_restarts_totalmetriğine alert tanımlayın. Bir pod 1 saat içinde 3’ten fazla restart atıyorsa, Liveness timeout limitlerini aşan bir CPU throttling yaşanıyor olabilir. - Graceful Shutdown Uyumu: Readiness probe failure threshold’u geçtikten sonra Endpoints controller’ın podu iptal etmesi, iptables/IPVS güncellemelerinin tüm nodelara dağılması süresi kadar (yaklaşık 1-3 saniye) sürer. Podlara
preStophook’u ekleyerek SIGTERM almadan önce birsleep 5komutuyla bekletmek, bu süre zarfında gelen mevcut HTTP isteklerinin 502 Bad Gateway hatasına düşmesini engeller.
Sık Sorulan Sorular
gRPC servislerinde HTTP probe kullanamıyoruz, en güvenli yaklaşım nedir?
Kubernetes 1.24 itibarıyla Native gRPC health probe’ları varsayılan olarak desteklenmektedir. Harici grpc-health-probe binary’sini container imajına gömüp exec komutuyla çalıştırmak yerine doğrudan grpc: { port: 8080 } tanımı kullanın. Exec pattern’i Kubelet üzerinde gereksiz PID (Process ID) yükü oluşturur.
Veritabanı kontrolünü Readiness’a koymayacaksak, uygulamanın bozuk veri yazmasını nasıl engelleriz?
Eğer uygulamanız asenkron bir worker (Örn: RabbitMQ veya Kafka consumer) ise, mesaj tüketimini durdurmak için uygulamanın consumer loop’unu kendi içinde duraklatmalısınız. Veritabanı gidince podu K8s Service arkasından çıkarmak (Readiness fail) anlamsızdır, çünkü consumer podlara load balancer üzerinden HTTP trafiği gelmez. Gelen HTTP istekleri içinse, circuit breaker kütüphaneleri (Istio, Envoy veya kod içi) ile %100 hata dönen rotaları anında kısıtlayın (fast failure) ve K8s objelerinin stabil kalmasını sağlayın.
Exec probe mu, HTTPGet mi, yoksa TCPSocket mi tercih edilmeli?
Kesinlikle HTTPGet tercih edilmelidir. exec probe’u her seferinde container içerisinde yeni bir process fork’lar. Yüzlerce podun çalıştığı bir node’da bu durum Zombie process’lere veya limitlere (ulimit) takılmaya yol açar. TCPSocket ise sadece portun açık olup olmadığına bakar, içerdeki framework’ün dead-lock’a girip girmediğini anlayamaz (TCP handshake başarılı olur ama HTTP cevap dönmez).
Deployment yaparken sıfır kesinti (Zero Downtime) için probe ayarları nasıl olmalı?
Yeni podun ReadinessProbe‘u başarılı olmadan eski podlar sonlandırılmaz (RollingUpdate stratejisinde maxUnavailable değerine göre). Ancak Readiness başarılı olduğu anda trafiği almaya başlar. Eğer uygulamanız JIT (Just-In-Time) compiler kullanan Java veya C# ise, readiness başarılı olsa bile ilk isteklerde yavaş çalışır. Readiness endpoint’ine yapay bir gecikme eklemek veya Kubernetes’in minReadySeconds parametresini kullanarak podu trafikte aktif hale getirmeden önce 10-15 saniye bekletmek mantıklıdır.
Sonuç
Kubernetes’in otomatik onarım mekanizmaları, mühendislik mimarisindeki hataları kapatmak için değil, donanım ve ağ sorunlarına karşı sistemi ayakta tutmak için tasarlanmıştır. Liveness ve Readiness probe’larını aynı uç noktaya atamak, CPU kaynak limitlerini göz ardı eden agresif timeoutlar ayarlamak ve dış bağımlılıkları readiness döngüsüne katmak, uygulamanızda p99 gecikmelerinde anlık zıplamalar olduğu anda tüm kümenin çökeceği anlamına gelir.
Şimdi cluster’larınıza gidin ve kubectl get pods -A | grep -v Running komutuyla sorunlu podları listeleyin. Arkasından describe komutuyla loglara bakın. Eğer probe kaynaklı OOMKilled veya context deadline exceeded hataları görüyorsanız, ilk yapacağınız iş timeoutSeconds değerlerini en az 3’e, failureThreshold değerlerini 3-5 aralığına çekmek ve startupProbe entegrasyonunu planlamak olmalıdır.
Bunları da beğenebilirsiniz

Sıfırdan Lock-Free Ring Buffer: C++ ile p99 Latency Optimizasyonu
C++ ile lock-free ring buffer inşa ederek mesajlaşma kuyruklarında p99 latency değerlerini 14.5ms’den 0.4ms’ye düşürme, memory barrier ve cache line rehberi.

PHP ile İletişim Formlarındaki Spam Mesajları Engelleme
Merhabalar, bu içeriğimizde sayfalarımızda oldukça sık kullandığımız iletişim formlarına botlar tarafından bırakılan spam mesajları engellemenin bir kaç yönteminden bahsedeceğim. Bahsettiğim yöntemler %100 garantili olmamakla birlikte…
