← blog · 4 Ekim 2026

Kubernetes'te PodDisruptionBudget ve Düğüm Boşaltma: Bütçe Nasıl Yazılır, Bakım Neden Kilitlenir

PodDisruptionBudget yalnızca gönüllü kesintileri sınırlar ve yanlış yazıldığında ya hiçbir şeyi korumaz ya da düğüm boşaltmayı süresiz kilitler. minAvailable ile maxUnavailable arasındaki seçim, sağlıksız pod politikası ve drain sırasındaki tuzaklar.

Bir Kubernetes kümesinde düğümleri güncellemek, ölçeklendirici fazla düğümü kapatmak ya da donanım değiştirmek için düğüm boşaltılır. Bu işlemlerin hepsi gönüllü kesintidir: kümeyi işleten taraf bir pod'u bilerek yerinden eder. PodDisruptionBudget (PDB) tam bu anlar için vardır ve "bu uygulamadan aynı anda en fazla şu kadarı gidebilir" kuralını koyar. Kâğıt üzerinde basit bir nesnedir, ama yanlış yazıldığında iki uç sonuç üretir: ya hiçbir şeyi korumaz ya da bütün bakım işlerini süresiz kilitler.

PDB neyi korur, neyi korumaz

PDB yalnızca Eviction API üzerinden gelen istekleri sınırlar. kubectl drain, küme otomatik ölçeklendiricisi ve yönetilen servislerin düğüm havuzu güncellemeleri bu API'yi kullanır. Bütçe izin vermezse API isteği 429 koduyla reddeder ve çağıran taraf bir süre sonra yeniden dener.

Korumadığı durumlar ise en az bunlar kadar önemlidir:

  • Düğümün çökmesi, çekirdek paniği, bellek yetersizliği nedeniyle sürecin öldürülmesi gibi gönülsüz kesintiler. PDB bunları engelleyemez, yalnızca bu kesintiler bütçeden düşülür ve ardından gelen gönüllü boşaltmalar daha temkinli olur.
  • kubectl delete pod ile doğrudan silme. Silme işlemi Eviction API'den geçmez.
  • Deployment'ın kendi kademeli güncellemesi. Yeni sürüm yayılırken kaç pod'un aynı anda gideceğini maxUnavailable ve maxSurge belirler, PDB değil.

Bu ayrım önemlidir çünkü ekipler sık sık "PDB koyduk, artık kesinti olmaz" diye düşünür. PDB yalnızca kümeyi işleten tarafın uygulamaya saygı göstermesini sağlar.

minAvailable mı maxUnavailable mı

İki alan vardır ve bir PDB'de yalnızca biri kullanılabilir. İkisi de tam sayı ya da yüzde alır.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app: api

Tercihim çoğu durumda maxUnavailable. Gerekçesi şu: minAvailable: 2 yazıldığında bu değer replika sayısından bağımsızdır. Uygulama ileride 2 replikaya indirilirse bütçe sıfır kesintiye düşer ve düğüm boşaltma kilitlenir. maxUnavailable: 1 ise replika sayısı değişse de aynı anda bir pod'un gitmesine izin verir ve ölçeklendirmeyle birlikte doğru davranmaya devam eder.

minAvailable'ın doğru seçim olduğu yer, mutlak bir alt sınırın olduğu durumlardır. Üç üyeli bir uzlaşı (quorum) kümesinde en az iki üyenin ayakta kalması gerekir; burada minAvailable: 2 niyeti en açık anlatan yazımdır. Yine de üç üyede maxUnavailable: 1 aynı sonucu verir ve üye sayısı beşe çıkarıldığında daha esnek kalır.

Yüzde kullanırken küçük replika sayılarında yuvarlamanın sonucu beklenenden farklı olabilir. Tahmin etmek yerine PDB'yi uyguladıktan sonra kubectl get pdb çıktısındaki ALLOWED DISRUPTIONS sütununa bakın. O sütun sıfırsa boşaltma o uygulamada bekleyecektir.

Boşaltmanın sırası

Elle yapılan bir düğüm bakımı tipik olarak şöyle ilerler:

kubectl cordon node-a
kubectl drain node-a --ignore-daemonsets --delete-emptydir-data --timeout=15m
# bakım
kubectl uncordon node-a

cordon düğümü yeni pod almaz hâle getirir. drain aynı işi yapar ve ardından pod'ları tahliye eder. DaemonSet pod'ları zaten her düğümde koştuğu için atlanır; emptyDir kullanan pod'lar için verinin kaybolacağını kabul ettiğinizi bayrakla açıkça belirtmeniz gerekir. Bir denetleyiciye bağlı olmayan çıplak pod'lar varsa drain durur, çünkü bu pod'lar tahliye edildiğinde hiçbir yerde yeniden oluşturulmaz. --force bu kontrolü geçer, ama o pod gerçekten kaybolur.

--timeout vermezseniz drain bütçe açılana kadar süresiz bekler. Otomasyonda her zaman bir süre sınırı koyun ve sınır aşıldığında süreci başarısız sayın; sessizce sonraki düğüme geçen bir betik yarım kalmış bakımları biriktirir.

Tuzaklar

Tek replikalı uygulamaya PDB. minAvailable: 1 ya da maxUnavailable: 0 ile korunan tek replikalı bir Deployment hiçbir zaman tahliye edilemez. Düğüm boşaltma o pod'da sonsuza kadar bekler. Yönetilen servislerde davranış değişir: bazıları belirli bir süreden sonra bütçeyi yok sayıp zorla siler, bazıları güncellemeyi başarısız sayar. Her iki sonuç da istediğiniz şey değildir. Tek replikalı bir uygulama kesintiye zaten açıktır; bunu PDB ile gizlemek yerine ya replikayı artırın ya da PDB koymayın ve kesintiyi kabul edin.

Sağlıksız pod'lar bütçeyi kilitler. PDB, hazır (Ready) durumdaki pod'ları sayar. Bir uygulamanın pod'larından biri sürekli çöküyorsa bütçe zaten tükenmiş görünür ve sağlıklı pod'lar da tahliye edilemez. Daha kötüsü, bozuk pod'un kendisi de tahliye edilemez. Kubernetes 1.27'den beri varsayılan olarak açık olan unhealthyPodEvictionPolicy: AlwaysAllow ayarı, hazır olmayan pod'ların bütçeye bakılmadan tahliye edilmesine izin verir. Çoğu durumsuz servis için bu doğru ayardır; bozuk bir pod'u korumanın kimseye faydası yoktur.

spec:
  maxUnavailable: 1
  unhealthyPodEvictionPolicy: AlwaysAllow
  selector:
    matchLabels:
      app: api

Hazır olma süresi boşaltmayı yavaşlatır. Tahliye edilen pod'un yerine gelen pod hazır olmadan bütçe yeniden açılmaz. Açılışı birkaç dakika süren, önbelleğini ısıtan ya da büyük bir veri yükleyen uygulamalarda yirmi düğümlük bir havuzun güncellemesi saatler alır. Hazır olma kontrolünün gerçekten trafik almaya hazır olmayı ölçtüğünden ve gereksiz yere geciktirilmediğinden emin olun.

Seçici ile gerçek pod'lar uyuşmuyor. PDB'nin seçicisi hiçbir pod'la eşleşmezse hata vermez, sadece hiçbir şeyi korumaz. Etiketler yeniden adlandırıldığında bu durum fark edilmeden oluşur. Tersi de sorundur: bir pod birden fazla PDB'nin seçicisine düşerse Eviction API o pod için isteği reddeder ve boşaltma takılır. Her uygulama için tek PDB, seçicisi Deployment'ın seçicisiyle birebir aynı olsun.

Replikalar aynı düğümde. PDB aynı anda kaç pod'un gidebileceğini söyler, pod'ların nereye yerleşeceğini söylemez. Üç replikanın üçü de aynı düğümdeyse o düğüm çöktüğünde PDB'nin yapabileceği bir şey yoktur. topologySpreadConstraints ile replikaları düğümlere ve mümkünse bölgelere yayın. PDB ile yayılım birlikte çalışır; biri olmadan diğeri eksiktir.

Kapasite yoksa bütçe açılmaz. Boşaltılan düğümdeki pod'ların gidebileceği boş kapasite yoksa yeni pod'lar beklemede kalır, hazır olmazlar ve bütçe kapalı kalır. Düğüm güncellemelerinde önce yeni düğüm ekleyip sonra eskisini boşaltan bir sıra izleyin. Yönetilen servislerin çoğu bunu "surge" ayarıyla sunar.

Ne zaman PDB koymamalı

Tek replikalı ve kesintiyi tolere edebilen işler, toplu işler (Job) ve geliştirme ortamları için PDB genellikle zarardan başka bir şey getirmez. Toplu işlerde tahliye işi baştan başlatır, ama PDB ile korumak düğüm bakımını işin süresine bağlar; bunun yerine işi yeniden başlatılabilir yazmak daha sağlam bir yoldur.

Benzer şekilde, düğüm havuzu güncellemelerini otomatik yapan bir ortamda her takımın kendi PDB'sini serbestçe yazmasına izin vermek, bir tek hatalı bütçenin tüm kümenin güncellemesini durdurmasına yol açabilir. Bunu önlemenin pratik yolu, kabul denetleyicisi ya da politika motoruyla maxUnavailable: 0 gibi kilitleyici değerleri reddetmek ve tek replikalı iş yüklerine PDB eklenmesini engellemektir.

Kısa kontrol listesi

Her durumsuz servis için en az iki replika, maxUnavailable: 1, unhealthyPodEvictionPolicy: AlwaysAllow ve replikaları düğümlere yayan bir yerleşim kuralı makul bir başlangıçtır. Uzlaşı gerektiren durumlu servislerde bütçeyi uzlaşı matematiğine göre yazın ve hazır olma kontrolünü üyenin gerçekten kümeye katıldığını gösterecek şekilde tanımlayın. Son olarak, bu ayarları bir bakım gününde değil, sıradan bir günde bir düğümü boşaltarak deneyin. ALLOWED DISRUPTIONS sıfır olan her uygulama, gerçek bakımda sizi bekletecek olan uygulamadır.