Ana içeriğe geç
Blog'a Dön
Spring BootKubernetesDevOpsJava
Ağaç (Tamamlanmış)

Spring Boot ile Zero-Downtime Deployment Üzerine Notlar

2025-10-286 dk

Üretim ortamına dağıtım yapmak yıllardır değişmeyen bir gerilim alanıdır. Servisler güncellenir, pod’lar kapanır, yenileri açılır; ama kullanıcı o sırada sayfasını yenilediğinde hiçbir şey olmamış gibi devam etmelidir. Zero-downtime kavramı da tam bu beklentinin karşılığıdır: uygulama değişir ama sistemin ritmi bozulmaz. Bunun gerçekleşmesi için Spring Boot’un kapanış davranışıyla Kubernetes’in trafik yönlendirme mantığının aynı hizaya gelmesi gerekir.

Graceful Shutdown: Kapanmayı Yönetmek

Spring Boot bir SIGTERM aldığında hemen ölmek yerine elindeki işi toparlayabilir. Bu toparlama süresi düzgün tanımlanmadığında, özellikle uzun süren işlemler yarım kalır ve dışarıya hata olarak yansır. Basit ama etkili bir ayarla uygulamaya kendini düzgün kapatması için zaman tanıyoruz:

server:
  shutdown: graceful

spring:
  lifecycle:
    timeout-per-shutdown-phase: 20s

Bu yapılandırma uygulamanın yeni istek kabul etmeyi bırakıp mevcut işlemlerini tamamlamasına imkân sağlar. Kapanış bir kesinti değil, kontrollü bir geçiş hâline dönüşür.

Liveness ve Readiness: Kubernetes’in Karar Mekanizması

Kubernetes açısından çalışan bir süreç ile trafiği kabul etmeye hazır bir süreç aynı şey değildir. Uygulamanın ayağa kalkması, veritabanı bağlantılarının stabil olması, cache ve thread havuzlarının kullanılabilir hâle gelmesi zaman alır. İşte readiness probe bu ayrımı yönetir:

readinessProbe:
  httpGet:
    path: /actuator/health/readiness
    port: 8080

Readiness hazır olmadığı sürece Kubernetes pod’a trafik yönlendirmez. Böylece daha açılışını tamamlamamış bir pod’a istek düşmesi engellenir.

Diğer tarafta liveness probe ise uygulamanın gerçekten yaşıyor olup olmadığını kontrol eder. Stuck bir thread, sonsuz döngü veya kilitlenmiş bir süreç varsa pod otomatik olarak yenisiyle değiştirilir. Bu iki probe yanlış ayarlanırsa dağıtım sırasında trafik beklenmedik şekilde hataya düşer.

RollingUpdate ve maxUnavailable Ayrıntısı

Kubernetes’in rolling update davranışı çoğu zaman güvenli kabul edilir; ancak yanlış konfigürasyon zero-downtime beklentisini kolaylıkla bozar. Sorunun kaynağı genellikle şudur: yeni pod henüz hazır olmadan eski pod devreden çıkar.

Bu yüzden maxUnavailable değeri sıfır olmalıdır:

rollingUpdate:
  maxSurge: 25%
  maxUnavailable: 0

Bu ayar, sistemde her zaman minimum gerekli sayıda pod’un ayakta kalacağını garanti eder. Zero-downtime’ın temel taşlarından biri budur.

preStop: Kapanış Anını Yumuşatmak

Kubernetes bir pod’u kapatmaya karar verdiğinde, o pod’un trafiğin tamamen dışına alınması anlık gerçekleşmez. Endpoint güncellemeleri ve iptables değişiklikleri birkaç saniyelik gecikmeyle yayılır. Bu küçük gecikme, trafik hâlâ eski pod’a düşebileceği anlamına gelir.

Bu riski ortadan kaldırmak için pod’un kapanmadan hemen önce kısa bir bekleme süresi tanımlıyoruz:

lifecycle:
  preStop:
    exec:
      command: ["/bin/sh", "-c", "sleep 10"]

Bu gecikme Kubernetes’in “bu pod artık yok” bilgisini kümeye tam olarak yayması için yeterlidir. Uygulama açısından da kapanış daha temiz ve iz bırakmayan bir hâle gelir.

Sonuç

Zero-downtime aslında sihirli bir özellik değil; doğru yapılandırılmış bir kapanış sürecinin, tutarlı probe ayarlarının ve Kubernetes’in trafik yönetimiyle uyumlu bir dağıtım stratejisinin doğal sonucudur. Uygulamanın davranışıyla Kubernetes’in beklentileri aynı noktada buluştuğunda, dağıtımlar sistemin günlük ritmi içinde sıradan bir operasyon hâline gelir. Yıllar içinde gördüğüm şey şu: stres, çoğunlukla belirsizlikten doğar. Bu ayarlar belirsizliği ortadan kaldırır ve dağıtımı güvenilir bir süreç hâline getirir.

Bağlantı Haritası

Mühendislik
Tarih
Anlatılar
Graph Loading...