· kaynak dev.to (home feed)
Curl döngüsü kanıtları: symlink takasıyla yapılan deploy'larda her sürümde hâlâ 502'ler dönüyor
Bir dev.to yazısı, symlink takasıyla yapılan her deploy'da kabaca üç saniye boyunca 502 döndüğünü ölçüyor, bilindik nginx retry satırının neden işe yaramadığını açıklıyor ve systemd tabanlı bir blue-green çözüm çiziyor.

Atomik olmayan deploy
dev.to üzerindeki bir yazı, birçok ekibin basit altyapıda güvenli varsayılan olarak gördüğü bir dağıtım kurulumunu inceliyor: tek bir sanal makine üzerinde Capistrano tarzı bir release ağacı; her build zaman damgalı bir dizine düşüyor ve servis yeniden başlatılmadan önce current symlink'i yeni release'e yönlendiriliyor. Yazar, bunun deploy'ları atomik kıldığını varsayıyordu — ta ki gerçek bir deploy sırasında curl'ü bir döngüde çalıştırıp, uygulamanın önyüklemesini tamamlayıp portunu yeniden bağlaması için gereken yaklaşık üç saniye boyunca her isteğin 502 ile başarısız olduğunu görene kadar.
Yazarın öne sürdüğü temel ayrım şu: symlink takası dosyaları atomik olarak değiştirir, ama systemctl restart bir durdurma ve ardından bir başlatmadır; bu iki adım arasında dinleyen hiçbir şey yoktur. Eski release'e karşı başlayan bir istek sorunsuz tamamlanır; boşluk sırasındaki isteklerin gidecek bir yeri yoktur.
Symlink takasının bile tuzakları var
Yeniden başlatmaya geçmeden önce yazı, linki yeniden yönlendirmenin üç bariz yolundan ikisinin bozuk olduğunu belirtiyor. ln -sf, bir dizine çözümlenen mevcut bir symlink'i takip eder ve yeni linki sessizce hedefin içinde oluşturur. ln -sfn bundan kaçınır ama unlink ve ardından bir symlink çağrısı olarak uygulandığından, yolun kısa bir süre hiçbir şeye çözümlenmediği bir boşluk bırakır. Yazara göre doğru yaklaşım, hedefin yanında geçici bir link oluşturup mv -Tf ile yerine taşımaktır; bu, rename(2)'ye dayanır ve gerçekten atomiktir.
İki mekanizma, tek 502
Yazı, kesintinin aldığı iki biçimi tanımlıyor. İlki basit bir reverse proxy vakası: nginx trafiği 127.0.0.1:3000 adresine geçirir, process ölür, port kapanır, bağlantı reddedilir ve nginx 502 döner.
İkincisi insanları yakalayan. Geleneksel bir PHP kurulumunda nginx document root'un sahibidir ve yalnızca .php istekleri bir unix socket üzerinden php-fpm'e ulaşır. İçgüdü, nginx'in dosyaları kendisinin sunmasının yeniden başlatmayı zararsız kılması gerektiğidir — ama fpm master, uygulama ile aynı systemd unit'i altında çalışıyorsa (log'ların, kaynak limitlerinin ve yaşam döngüsünün uygulama başına kalması için yaygın bir tercih), unit'i yeniden başlatmak socket dosyasını unlink eder ve nginx, o dönene kadar ENOENT alır. Statik varlıklar sunulmaya devam eder, bu da boşluğun deploy kaynaklı değil de uygulama hatası gibi görünmesine yol açar.
Hiçbir şeyi değiştirmeyen nginx satırı
Refleks çözüm proxy_next_upstream'dir. Yazar, literal bir proxy_pass adresinin yanında bunun etkisiz olduğunu açıklar; çünkü bu, tam olarak tek bir peer içeren bir upstream grubu oluşturur — denenecek bir sonraki sunucu yoktur, dolayısıyla sorunun çözüldüğünü ima eden bir config satırıyla aynı 502 geri döner.
İşe yarayan versiyon yazım hatası gibi görünür: aynı adresi iki kez listeleyen bir upstream bloğu; böylece reddedilen bir bağlantı ikinci girdiye karşı yeniden denenebilir. max_fails=0 da önemlidir. Varsayılan max_fails=1 ve fail_timeout=10s ile, tek bir reddedilen bağlantı iki girdiyi de on saniye boyunca devre dışı bırakır ve 200 ms'lik bir boşluğu on saniyelik bir kesintiye dönüştürür. Yazı ayrıca, başlayan bir process bozuk bir upstream olmadığından ve durum kodunun istemcilerin, CDN'lerin ve health check yapanların harekete geçebileceği kısım olduğu için 502 yerine 503 ve bir Retry-After başlığıyla yanıt vermeyi öneriyor.
Uyarı açık: bu bir retry satın alır, sıfır kesinti değil. Çok saniyelik bir önyüklemeyi değil, bir saniyenin altındaki bir boşluğu emer.
Gerçek çözüm: her iki sürümü birden çalıştırın
Yazının asıl cevabı, bir systemd template unit'i olan [email protected] ve slots/blue ile slots/green'in her birinin bir release'e symlink olduğu ve kendi port atamasını taşıdığı bir slots diziniyle yönetilen blue-green deployment. Bir deploy, hizmet vermekte olandan hiçbir şeye dokunmadan yeni release'i derler, beklemedeki slot'u ona yönlendirir, yalnızca beklemedeki servisi yeniden başlatır ve onu — hâlâ eski sürüme yönlendiren proxy üzerinden değil — kendi portunda curl ile doğrular. Yayınlanan metin dizinin ortasında kesildiği için son geçiş adımları eksiksiz gösterilmiyor.
Neden önemli
Symlink takası, uzun süredir yaygın biçimde tekrarlanan, çoğunlukla container veya load balancer olmadan sıfır kesintili deploy'lar sunduğu söylenen bir tarif. Bu yazı iddiayı ölçüyor ve yaygın durumda yanlış olduğunu görüyor: atomik dosya değiştirme process erişilebilirliği hakkında hiçbir şey söylemez ve ortaya çıkan kesinti, mühendislerin bunu deploy kaynaklı değil kararsızlık olarak dosyalamasına neden olacak kadar hızlı, kendi kendine düzelir. Yazı ayrıca standart nginx hafifletmesinin hiçbir şey yapmadığı — ya da yanlış yapılandırıldığında kesintiyi milisaniyelerden on saniyeye uzattığı — bir tuzak belgeliyor. Düz VM'ler üzerindeki ekipler için çıkarım şu: deploy sırasındaki erişilebilirlik, filesystem işaretçisinin ne kadar zekice hareket ettiğinden değil, iki instance çalıştırıp aralarında geçiş yapmaktan gelir.
- #deployment
- #nginx
- #systemd
- #zero-downtime
- #blue-green