DevOps

Kubernetes v1.36 Controller Staleness: Artık Daha Az Acı

Dürüst olmak gerekirse, Bir Kubernetes controller yazdıysanız ya da sadece kullanıp kenardan izlediyseniz, o tanıdık anı yaşamışsınızdır. Hani şu, “neden hâlâ tepki vermedi bu?” dediğiniz an. Bende çok öldü. Hem de en kötü zamanda.

Geçen yıl bir e-ticaret müşterimizde, Black Friday’e iki hafta kala HPA beklediğimiz hızda scale etmiyordu. Loglara daldık, metric server tamam, Prometheus tamam, custom controller’ın cache’ine bakana kadar her şey normal görünüyordu… İşte orada suratımız düştü. Cache, API server’ın gerçek hâlinden bazen 30-40 saniye geride kalıyordu. Controller da doğal olarak eski bilgiyle karar veriyordu. Yanı işin teknik adıyla: staleness.

Kubernetes v1.36 ile gelen iyileştirmeler tam da bu derdi hedef alıyor. Açık konuşayım, ben bunu uzun süredir bekliyordum. Şimdi detaylara girelim ama önce şu “staleness” denen meseleyi bir yere oturtalım.

Staleness Tam Olarak Ne? Kafadaki Resmî Düzeltelim

Çoğu kişi Kubernetes controller’ın nasıl çalıştığını kabaca biliyor. “Watch eder, reconcile eder” deyip geçiyoruz ya, işte orada biraz fazla kestiriyoruz.

Controller performans için yerel bir cache tutuyor. Bu cache’i de informer denen yapı API server’ı izleyerek güncel tutmaya çalışıyor (watch mekanizması yanı) (inanın bana). Ama burada küçük bir ters köşe var: Bu güncellik garanti değil, sadece çaba var. Yanı controller “şu anda 5 pod var” derken API server tarafında çoktan 7 pod olmuş olabiliyor.

Staleness dediğimiz şey de tam buradan çıkıyor; controller’ın kafasındaki dünya ile gerçek dünya arasındaki gecikme yüzünden oluyor. Üç yerde can sıkıyor:

  • Yanlış aksiyon: Controller eski bilgiyle karar veriyor. Mesela zaten silinmiş bir kaynağı silmeye uğraşıyor.
  • Aksiyonsuzluk: Aslında müdahale etmesi gerekirken hiç kıpırdamıyor, çünkü cache’te o değişiklik yok.
  • Geç aksiyon: Tepki veriyor ama 10 saniye sonra değil de 50 saniye sonra veriyor. Kritik sistemlerde bu bile yeterince kötü.

Size bir şey söyleyeyim, Bunu finans sektöründeki bir müşterimde birebir gördük — bence çok yerinde bir karar —. Custom bir operatör yazmıştık; transaction işleme pod’larını izliyordu. Pod restart olunca cache yeniden kurulurken (büyük cluster’larda birkaç saniye sürüyor) eventler bazen ters sırayla geliyordu. Sonuç mu? Controller kendisinden önce gelen bir “delete” eventini sonradan gelen “create” eventinden sonra işledi. Felaket gıbı geldi kulağa ve gerçekten öyleydi. İki gün debug ettik.

v1.36’da Neler Geldi? İki Cephede Birden Saldırı

İyileştirmeler iki katmanda geliyor: biri client-go seviyesinde, diğeri kube-controller-manager içinde yoğun trafik yiyen controller’larda. Bu ayrım önemli çünkü client-go tarafındaki değişiklikleri kendi operatör’larınızda da kullanabiliyorsunuz.

Atomic FIFO: Sıraya Girin Ama Toplu Hâlde

İlk büyük yenilik AtomicFIFO feature gate’i ile geliyor. Adı biraz ağır duruyor ama mantığı aslında gayet düz.

Daha önce informer API server’dan event aldığında bunları tek tek queue’ya atıyordu. Mesela list operasyonunda 500 obje geldiyse bunlar 500 ayrı işlem gıbı sıraya giriyordu; araya başka eventler de karışınca sıra biraz dağılıyor, cache kısa süreliğine tutarsız hâle gelebiliyordu.

Küçük bir detay: Yeni yaklaşımda işe atomic FIFO sayesinde batch operasyonlar tek parça atomic işlem gıbı ele alınıyor. Yanı 500 objelik initial list ya tamamen işlenip cache’e yazılıyor ya da hiç yazılmıyor; ortada yarım yamalak dolmuş bir cache bırakılmıyor.

Bu değişiklik özellikle controller restart anlarında baya işe yarıyor.
Cache build sürecinde controller’ın yarı bilgilendirilmiş hâlde karar vermesi gerekmiyor.

Resource Version Introspection

Peki ikinci güzel haber ne? Artık client-go üzerinden cache’inizin hangı resource version’a kadar güncel olduğunu sorgulayabiliyorsunuz. Eskiden bu bilgi neredeyse saklıydı; etrafından dolanmak zorundaydık.

Doğrusu, Siz şöyle bir şey yazabiliyorsunuz artık: artık ile ilgili önceki yazımız yazımızda bu konuya da değinmiştik.

// Pseudocode tarzı, gerçek API benzer
rv, err := informer.GetStore().LatestResourceVersion()
if err != nil {
return err
}
// API server'dan gelen son version ile karşılaştır
if isStale(rv, expectedRV) {
// Karar vermeyi ertele veya doğrudan API'ye git
return reconcileWithFreshRead(ctx)
}

Küçük görünüyor ama değil aslında; “gerektiğinde cache’i bypass et” stratejisini mümkün kılıyor bu iş.
Kritik karar öncesinde rahatça “ben gerçekten güncel mıyım?” diye sorabiliyorsunuz.
Evet, bence asıl fark burada başlıyor.

Observability Tarafı: Artık Karanlıkta Değiliz

Burası benim en sevdiğim kısım olabilir.
Çünkü staleness’in en sınır bozucu tarafı varlığını anlamanın zor olmasıydı.
Şimdi yeni metrikler geldi ve controller’ın cache durumunu Prometheus üzerinden net biçimde görebiliyorsunuz.
Tam da aradığımız şey buydu diyebilirim.

Metrik Ne işe yarar?
controller_cache_lag_seconds Cache’in API server’dan ne kadar geride olduğunu gösterir
controller_reconcile_staleness Reconcile sırasında ne kadar eski veriyle karar verildiğini ölçer
informer_resync_duration Lekelenmeden resync işleminin ne kadar sürdüğü
workqueue_atomic_batch_size Tam toplu batch işleme istatistikleri verir

Bunlara alarm kurmadan production’a çıkmayın derim.
Logosoft’taki bir bankacılık projesinde geçen ay bunu yaptık; cache lag 10 saniyeyi geçince Slack’e alarm düşüyor.
İlk hafta üç farklı sorun yakaladık — biri network’tü, ikisi de etcd performans problemi çıktı.
Hani bazen küçük görünen metrikler asıl işi çözüyor ya, aynen öyle öldü. Daha fazla bilgi için GA4’ü Bırakıp Next.js + Supabase’e Geçmek: Neden? yazımıza bakabilirsiniz.

Türkiye’deki Şirketler İçin Pratik Değerlendirme

Neyse ki gerçekçi konuşabiliriz burada.
Türkiye’de Kubernetes adoption son 3-4 yılda baya hızlandı ama büyük çoğunluk hâlâ “uygulamayı container’a söküp AKS’e atalım” seviyesinde geziyor.
Custom controller yazan ekip sayısı işe dürüst olayım, çok fazla değil. Bu konuyla ilgili Docker İmajını Küçültmek: 1,58 GB’dan 186 MB’a yazımıza da göz atmanızı tavsiye ederim.

Peki bu güncelleme size ne anlatıyor?
İki senaryoda fark ediyor diyebilirim: Daha fazla bilgi için Azure Data Studio Emekli Oldu: VS Code’a 10 Dakikada Geçiş yazımıza bakabilirsiniz. Azure DevOps Git Policy API: 10-15 Kat Hız Geldi yazımızda bu konuya da değinmiştik.

Geçen ay bir telekom müşterisinde Stork benzeri bir backup orchestrator’u custom controller olarak yazdık.
Orada cache staleness ciddi sorundu çünkü volume snapshot işlemleri zaten asenkron ilerliyor.
v1.36 çıktığında ilk denediğimiz şey AtomicFIFO öldü ve race condition sayısı yaklaşık %60 düştü.
Rakam biraz iddialı durabilir ama loglar başka söylüyor.

“`html

Sıkça Sorulan Sorular

Staleness mitigation özelliklerini kullanmak için cluster’ımı yükseltmem yeterli mi?

Hayır, maalesef o kadar basit değil. Kendi yazdığınız controller’lar varsa client-go versiyonunu da güncellemeniz gerekiyor. Hazır operatör kullanıyorsanız,. Cert-manager, ArgoCD gıbı şeyler, onların da bu yeni client-go’ya geçmesini beklemeniz lazım. Açıkçası süreç biraz dağınık ilerliyor, tek adımda bitmiyor.

AtomicFIFO feature gate’ını production’da hemen açmalı mıyım?

Açma. Yanı direkt prod’a alma. Önce dev ya da staging ortamında en az bir hafta gözlemleyin. Çoğu durumda sorunsuz çalışıyor aslında, ama çok yoğun custom controller’larınız varsa beklenmedik davranışlar görebilirsiniz. Bence en güvenli yol şu: yeni metrikleri izleyin, her şey sakinse o zaman prod’a alın.

Bu güncellemeler AKS, EKS, GKE’ye ne zaman gelir?

Managed Kubernetes servisler genelde stable sürümleri 2-4 ay gecikmeli alıyor. AKS son zamanlarda biraz daha hızlı davranıyor, EKS işe daha temkinli gidiyor tecrübeme göre. Roadmap’lerini takıp etmenizi öneririm. Bir de şunu söyleyeyim: beta feature gate’leri zaten managed servislerde çoğunlukla kapalı geliyor, sürpriz beklemeyin.

Kendi controller’ımın staleness sorunu olup olmadığını nasıl anlarım?

İlk bakacağınız yer controller_cache_lag_seconds metriği. p99 değeri 5 saniyenin üzerine sık sık çıkıyorsa, hani sürekli orada takılıp kalıyorsa, bir sorun var demektir. Bunun yanında reconcile loop’unuzun başına resource version kontrolü ekleyin ve “kaç defa stale veriyle çağrıldım” diye loglayın. Bence bu iki adım çoğu durumu açığa çıkarıyor (şaşırtıcı ama gerçek)

Bu özellikler eski Kubernetes sürümlerine backport edilecek mi?

Pek olası değil. Kapsamlı API değişiklikleri var çünkü, backport o yüzden zor. v1.34 veya v1.35 kullanıyorsanız v1.36’ya geçmek dışında alternatifiniz yok açıkçası. Ama şöyle de bakmak lazım: Kubernetes upgrade politikaları zaten 3 minor version desteği veriyor,. Planlı bir geçişle bu süreci sorunsuz atlatabiilrsiniz (yanlış duymadınız)

Bir dakika — bununla bitmedi.

Kaynaklar ve İleri Okuma

Bu konuyu daha derinlemesine incelemek isteyenler için faydalı bulduğum kaynaklar:

Aşkın KILIÇ

20+ yıl deneyimli Azure Solutions Architect. Microsoft sertifikalı bulut mimari ve DevOps danışmanı. Azure, yapay zekâ ve bulut teknolojileri üzerine Türkçe teknik içerikler üretiyor.

AZ-305AZ-104AZ-500AZ-400DP-203AI-102

Bu içerik işinize yaradı mı?

Benzer içerikleri kaçırmamak için beni sosyal medyada takip edin.

← Onceki Yazi
Markdown Rehberi: GitHub'da Sıfırdan Profesyonel README'ye
Sonraki Yazi →
CVE-2026-3854: git push Üzerinden GitHub'da RCE Vakası

Yorum Yaz

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

İçindekiler
← Markdown Rehberi: GitHub’...
CVE-2026-3854: git push Üzerin... →