3 puan yazan GN⁺ 2024-09-22 | 1 yorum | WhatsApp'ta paylaş
  • Kamal Proxy, web uygulamalarının önünde çalışan küçük bir HTTP proxy’sidir ve devam eden trafiği kesmeden dağıtımı yeni instance’a geçirmek için tasarlanmıştır
  • Yeni instance kamal-proxy deploy ile kaydedilir; proxy, yalnızca HTTP health check’i geçtikten sonra yeni trafiği bu instance’a yönlendirir
  • Dağıtım komutu, önceki instance’taki tüm trafik boşalana kadar bekler; bu yüzden komut başarıyla döndükten sonra önceki instance, devam eden istekler kesilmeden kaldırılabilir
  • Tek bir proxy üzerinde birden fazla uygulama çalıştırabilmek için host tabanlı yönlendirme, path tabanlı yönlendirme, otomatik TLS ve manuel TLS sertifikası belirtme özellikleri sunar
  • Kamal Proxy, Kamal dağıtım aracının bir parçası olarak tasarlanmıştır; ancak tek başına ya da başka dağıtım araçlarının bir bileşeni olarak da kullanılabilir

Kamal Proxy ne yapar?

  • Kamal Proxy, sıfır kesintili dağıtımı koordine etmeyi kolaylaştırmak için geliştirilmiş küçük bir HTTP proxy’sidir
  • Web uygulamanızı Kamal Proxy’nin arkasında çalıştırırsanız, devam eden trafiği kesmeden değişiklikleri dağıtabilirsiniz
  • Bunun için uygulama tarafında özel bir entegrasyon gerekmez
  • Kamal Proxy, container paketleme ve provisioning de içeren Kamal sisteminin bir parçası olarak çalışacak şekilde tasarlanmıştır
  • Tek başına veya başka bir dağıtım aracının parçası olarak da kullanılabilir

Çalıştırma ve dağıtım akışı

  • Proxy instance’ı kamal-proxy run komutuyla çalıştırılır
  • Bir yapılandırma dosyası yoktur; varsayılanlar uygulamanıza uymuyorsa seçenekler verilebilir
    • Varsayılan HTTP portu 80’dir
    • Farklı bir portta çalıştırmak için kamal-proxy run --http-port 8080 kullanılır
    • Tüm seçenekler kamal-proxy help run ile görülebilir
  • Trafiği web uygulamasına göndermek için uygulama instance’ı proxy’ye deploy edilir
  • Hedef instance hostname:port biçiminde belirtilir
    • Örnek: kamal-proxy deploy service1 --target web-1:3000
    • Bu komut web-1:3000 adresini service1 servis adıyla kaydeder

Sıfır kesintili geçiş nasıl çalışır?

  • Yeni bir instance kaydedildiğinde Kamal Proxy, erişilebilir ve çalışır durumda olduğunu doğrulamak için hemen HTTP health check başlatır
  • Health check başarılı olursa yeni trafik yeni instance’a yönlendirilmeye başlanır
  • Yeni instance uygun süre içinde healthy durumuna gelemezse deploy komutu dağıtımı durdurur ve sıfırdan farklı bir çıkış kodu döndürür
  • Her dağıtım, daha önce dağıtılmış instance’taki tüm trafiği yeni instance’a aktarır
  • deploy komutu, önceki instance’taki trafik tamamen boşalana kadar bekledikten sonra döner
    • Komut başarıyla döndükten sonra önceki instance’ı kaldırmak, devam eden istekleri kesmez
  • Yeni instance yalnızca healthy durumdayken trafik alır ve önceki instance tamamen drain olduktan sonra kaldırılır; bu sayede dağıtım sıfır kesintiyle gerçekleşir

Health check yapılandırması

  • Varsayılan health check, her servis için saniyede 1 kez /up adresine GET isteği gönderir
  • 200 yanıtı healthy durum olarak kabul edilir
  • Health check’i uygulamanıza uyarlamak için deploy bayrakları kullanılabilir
    • --health-check-path
    • --health-check-port
    • --health-check-timeout
    • --health-check-interval
  • Health check yolunu değiştirme örneği:
    • kamal-proxy deploy service1 --target web-1:3000 --health-check-path web/index.html
  • Health endpoint’ini ana servisten farklı bir portta yayınlıyorsanız:
    • kamal-proxy deploy service1 --target web-1:3000 --health-check-port 8080

Yönlendirme özellikleri

  • Host tabanlı yönlendirme

    • Host tabanlı yönlendirme, tek bir Kamal Proxy instance’ıyla aynı sunucudaki birden fazla uygulamaya trafik yönlendirmeyi sağlar
    • Dağıtım sırasında belirli bir host belirtilebilir
    • kamal-proxy deploy service1 --target web-1:3000 --host app1.example.com
    • Bu şekilde dağıtılan instance’lar yalnızca belirtilen host için gelen trafiği alır
    • Her uygulama için ayrı host tanımlarsanız, port çakışması olmadan aynı sunucuda birden fazla uygulama çalıştırabilirsiniz
    • Belirli bir host aynı anda yalnızca tek bir servise yönlendirilebilir
    • service1 zaten app1.example.com kullanıyorsa, service2 aynı host ile dağıtılmaya çalışıldığında hata döner
    • service1 kaldırıldıktan sonra service2 aynı hosta dağıtılabilir
  • Path tabanlı yönlendirme

    • Path tabanlı yönlendirme, istek yoluna göre trafiği farklı servislere ayıran uygulamalarda kullanılır
    • Servisler farklı path prefix’leri altında mount edilebilir
    • /api ile başlayan istekleri web-1’e gönderme örneği: kamal-proxy deploy service1 --target web-1:3000 --path-prefix=/api
    • Kalan trafiği web-2’ye gönderme örneği: kamal-proxy deploy service2 --target web-2:3000
    • Varsayılan olarak path prefix, upstream’e iletilmeden önce kaldırılır
    • /api/users/123 isteği web-1’e /users/123 olarak iletilir
    • Orijinal yolu aynen iletmek için --strip-path-prefix=false belirtilir

TLS desteği

  • Kamal Proxy, uygulamalar için TLS sertifikalarını otomatik olarak alabilir ve yenileyebilir
  • Otomatik TLS, dağıtım sırasında --tls bayrağı eklenerek etkinleştirilir
    • kamal-proxy deploy service1 --target web-1:3000 --host app1.example.com --tls
  • Otomatik TLS için host belirtilmesi gerekir
    • Bu, rastgele host adları için kötü niyetli sertifika taleplerini engellemek amacıyla konmuş bir koşuldur
  • Path tabanlı yönlendirmede TLS seçeneği root path üzerinde ayarlanmalıdır
    • Aynı hostun farklı path’lerine dağıtılan servisler, root path için tanımlanmış TLS ayarını kullanır
  • Manuel olarak alınmış TLS sertifikaları, kendi certificate authority’niz veya Cloudflare origin certificate kurmanız gerekiyorsa, sertifika dosyası ve private key yolunu doğrudan belirtebilirsiniz
    • --tls-certificate-path cert.pem
    • --tls-private-key-path key.pem

Ortam değişkenleri ve build

  • Docker container çalıştırma gibi ortamlarda run seçenekleri ortam değişkenleri olarak verilebilir
  • kamal-proxy run, ilgili ortam değişkeni ayarlanmışsa her seçeneğin değerini ortam değişkeninden okur
    • kamal-proxy run --http-port 8080
    • HTTP_PORT=8080 kamal-proxy run
  • Ortam değişkeni adları mevcut ortamınızla çakışıyorsa ayırt etmek için KAMAL_PROXY_ öneki kullanılabilir
    • KAMAL_PROXY_HTTP_PORT=8080 kamal-proxy run
  • Yerel build, çalışan bir Go ortamında make ile yapılır
  • Docker container olarak build almak için make docker kullanılır
  • Proxy komutlarını denemek için Docker Compose yapılandırması example klasöründe bulunur

1 yorum

 
GN⁺ 2024-09-22
Hacker News yorumları
  • Eylem adı olarak deploy seçilmesi tuhaf
    Zaten aşırı yüklenmiş bir terim; “uygulama mı dağıtıldı? Yoksa proxy’ye mi dağıtıldı?” gibi bir kafa karışıklığı yaratacak gibi
    bind, intercept, hatta sadece proxy gibi kelimeler kullanılabilirdi; neden deploy olduğunu anlamıyorum

    • “Dağıtıldı” demek, çalışıyor ve proxy’ye kaydedilmiş demek diye görülebilir
    • Gelen trafik proxy’den geliyorsa, deploy “proxy trafiği yeni uygulama instance’ına akmaya başladı” dışında başka ne anlama gelebilir, bilmiyorum
  • Bugünlerde başka sunucularla da kesintisiz dağıtım yapmak kolay; bunu ayrı bir uygulama bütününe dönüştürmeleri ilginç
    Örneğin Unix socket destekleyen bir uygulama + web proxy ile sadece dosyayı taşıyarak kesintisizlik sağlanabilir
    Atomiktir ve curl ile warm-up isteği de gönderebilirsiniz
    Bir kayıt sistemi bile yapmak bana abartı görünüyor

    • Bu, Kamal’ın (https://kamal-deploy.org) çok küçük bir parçası sadece
      Kamal, buluttan kendi donanımına geçerken milyonlarca dolar tasarruf etmek için kullanılan bir dağıtım aracı (https://basecamp.com/cloud-exit)
    • Bu yaklaşımı biraz daha açıklayabilirseniz iyi olur
      Referans olabilecek bir yazı varsa daha fazla öğrenmek isterim
  • Bu, esas olarak Docker Swarm’da servis container’ları değiştirilirken trafiğin kesilmesiyle ilgili temel sorunu ele almaya çalışıyor gibi görünüyor
    Cloud 66’da JAMStack sunucusu yaparken aynı sorunu yaşamıştık; kendi proxy’miz yerine Caddy kullanmıştık, Traefik de gayet uygun olurdu gibi geliyor
    Kamal’ın k8s veya k3s yerine neden Swarm’ı seçtiğini bilmiyorum ama karmaşıklığın bir yerde durması gerekiyor ve gizlenemiyor; sonunda kendi proxy’sine gitmiş gibi
    Kendim kullanmadım ama WebSockets, SSE, HTTP/3, çeşitli sıkıştırma ve şifreleme desteklerini sürekli kovalamak zorunda kalacaklar gibi göründüğü için epey şüpheliyim

    • Kamal, “Kubernetes fazla karmaşık” önermesi üzerine kurulmuş gibi hissettiriyor ve bu gerekçeden yola çıkarak Kubernetes’in yaptığı şeylerin önemli bir kısmını yeniden yapıyor
      Basit başlayan bir reverse proxy’nin, sonunda kaçınmaya çalıştığı karmaşıklığı sürekli içine çekmesine örnek gibi görünüyor
      Geniş ve ölçeklenebilir yürütme sistemlerinin rakiplere ihtiyacı olduğunu düşünüyorum ama Kamal, kaçınmaya çalıştığı karmaşıklığa geri geri yürümek gibi duruyor
      Kubernetes’in istenen durum yönetimi framework’ü olarak sahip olduğu yetenek ve esneklik daha da belirgin görünüyor
    • Orkestrasyon ile proxy’yi birbirine karıştırıyor gibisiniz
      Docker kullanmaya devam ederken proxy olarak Caddy, Traefik, Envoy kullanabilirsiniz
      Kubernetes de sonuçta çoğu zaman bunları ingress controller olarak kullanıyor
    • Kamal’ın Docker Swarm kullandığını nerede gördünüz bilmiyorum
      Görünüşe göre Swarm kullanmıyor
    • Kamal sıradan docker run komutları kullanır; Swarm veya orkestrasyon yoktur
      Temelde Capistrano’nun yerine geçen basit bir araçtır
    • Sebep buysa, bu konu hakkında çok temel bir araştırma bile yapılmamış gibi
      Container orkestrasyon servislerinin temeli, bağlantıları ve blue/green dağıtımı ingress controller üzerinden ele almaktır
      Daha doğrusu ingress controller, yıllardır, hatta on yıllardır bu kullanım senaryosunu ele alan sayısız reverse proxy’ye verilmiş rol adıdır
  • Kesintisiz dağıtım genel olarak nasıl çalışır, kısaca açıklayabilir misiniz?
    Uygulamanın iki sürümünün aynı anda ayakta olduğu ve yeni trafiğin yeni sürüme yönlendirildiği bir yapı olduğunu tahmin ediyorum
    Ama tek bir veritabanı kullanılıyorsa ve yeni uygulama sürümü şema değişikliği getiriyorsa, başlangıçta migration script’i şemayı değiştirecektir; eski uygulama sürümü ise eski şemayı bekler
    Bunun nasıl ele alındığını merak ediyorum

    • İlk adım migration ile dağıtımı ayırmaktır
      Birçok framework kod dağıtımı sırasında migration çalıştırır, ama pratikte çalıştırma zamanını elle kontrol etmek daha iyidir
      Her kod sürümünün hem mevcut şemada hem de gelecekteki migration sonrası şemada çalışması gerekir; bu da fiilen geriye dönük uyumlu kod demektir
      Akış “mevcut/gelecek şemaların ikisinde de çalışan yeni kodu dağıt → doğrula → migration çalıştır → doğrula → artık olmayan şemaya yönelik uyumluluk kodunu temizle” şeklinde olur
    • Migration’ların geriye dönük uyumlu olması gerekir; yani veritabanı şemasının uygulamanın iki sürümünü de destekleyebilmesi gerekir
      Kesintisiz dağıtım veya rolling deployment yapmak istiyorsanız ödemeniz gereken ek maliyet budur; büyük şirketler genelde böyle yapar
    • Gerçekten kesintisiz dağıtım gerektiğinde izlenecek yöntemi diğer yanıtlar açıklamış, ama çoğu kurum ve çoğu migration için DB migration kaynaklı kesinti süresi pratikte 0’dan ayırt edilemez
      Özellikle bölgesel kullanıcılara hizmet veriyorsanız ve dağıtım için sakin saatleri seçebiliyorsanız bu daha da geçerlidir
    • Kendim kullanmadım ama Xata, en azından Postgres için DB migration konusunda oldukça temiz bir çözüm üretmiş gibi görünüyor
      Uygulamanın iki sürümü aynı anda çalışabiliyor
      https://xata.io/blog/multi-version-schema-migrations
    • Evet, bir noktada iki sürümün de çalışıyor olması gerekir
      Load balancer Server2’de bağlantıları kabul etmeye başlar ve Server1’de yeni bağlantı kabul etmez
      Sonra Server1’deki tüm bağlantılar kapanınca Server1’i devreden çıkarır
      Bunlar farklı sunucular da olabilir, tek bir sunucudaki birden fazla worker da olabilir
      O süre boyunca, diğer yanıtların söylediği gibi migration’ların geriye dönük uyumlu olması gerekir
  • Kamal 2 şu anda RC (https://github.com/basecamp/kamal/releases) aşamasında ve otomatik SSL desteğiyle tek bir sunucuda birden fazla uygulamayı Kamal ile kolayca çalıştırmayı mümkün kılacak gibi görünüyor; heyecan verici

    • autocert paketini kullanıyor; bu da asgari düzeyde bir uygulamaya yakın
      Kırılgan ve Let's Encrypt'in sertifika verme limitleri ile eşzamanlı sertifika limitleri yüzünden proxy instance'larını yatay ölçeklendirmek zor
      Caddy/Certmagic, verileri paylaşımlı depolamaya yazarak yalnızca tek bir sertifika alınmasını ve tüm instance'ların bunu depolama üzerinden yeniden kullanıp koordine etmesini sağlayarak bu sorunu çözüyor
      Yayıncı alternatifi, limitlerden kaçınma veya ARI desteği de yok
      Upstream hazır olana kadar istekleri bekletme işini de Caddy, reverse_proxy üzerinde try_duration ve try_interval ayarlanınca gayet iyi hallediyor
      Proxy header işleme de güvenilir IP'leri dikkate almıyor; etkinleştirilirse biri X-Forwarded-For ayarlayarak IP sahteciliği yapabilir
      Varsayılan olarak kapalı olması iyi ama herhangi bir uyarı da yok
      Amacın basitlik olduğunu anlıyorum, ancak mevcut hâliyle yeterince olgun değil ve çok fazla daha iyi seçenek olduğu için pratikte kullanmak istemem
  • Bunu nasıl kullanacağımı tam bilmiyorum ve bir şeyi kaçırıyor gibiyim
    Örnek, web servisinin 4 replikasını başlatıyor
    Bunlardan example-web-1 gibi tek bir replikaya deploy edip servis oluşturabiliyorsanız, kalan 3 replikanın ne yaptığını anlamıyorum
    web'i güncelleyip kesintisiz deploy yapmak için web servisinde build komutunu çalıştırmak, bir şekilde bu servisi başlatmak ve ardından yeni hedefe deploy çalıştırmak gerekiyor gibi
    Ama docker compose up --build --force-recreate web çalıştırırsanız mevcut replikalar kapanır ve her şey anlamsız hâle gelir

    • İlk sorudaki diğer replikalar, Docker'ın VIP ya da DNS isteklerinde birden fazla IP döndürme yöntemiyle yük dengelenir[0]
      Bu proxy'nin DNS isteğinden dönen birden fazla kayda dengeleme yapıp yapmadığını kontrol etmedim, ama en azından VIP tabanlı yük dengeleme ise beklenen şekilde çalışacaktır
      İkinci güncelleme kısmı daha az net
      Aynı ağ içinde farklı isimli bir servis ayağa kaldırıp kamal-proxy deploy çalıştırılması bekleniyor olabilir
      Servis adına sürüm numarası koymak gibi bir şey olabilir; hızlı geri almak istiyorsanız eski sürümü sıcak durumda tutmak da mantıklı
      [0]: https://docs.docker.com/reference/compose-file/deploy/#endpo...
    • Sadece k8s rollout restart deployment kullanmamak için neden olduğunu anlamıyorum
      Ya da DNS'i veya router'ı iki backend arasında değiştirebilirsiniz
  • Bunun trafiği geçici durdurma desenini uygulayıp uygulamadığını merak ediyorum
    Proxy'nin trafiği fiilen birkaç saniye durdurduğu bir yöntem; gelen istekler normalden birkaç saniye daha uzun sürüyor gibi görünür ama kısa bir gecikmeden sonra tamamlanır
    O birkaç saniye içinde küçük bir DB migration ya da 5 saniye içinde bitirebileceğiniz biraz daha karmaşık, bloklayıcı bir altyapı değişikliği çalıştırabilirsiniz

    • Bunu gerçek üretim ortamında yapmış biri var mı merak ediyorum
      Oldukça riskli geliyor; birkaç yıl uygulama sunucusu şirketinde çalıştım ama bu deseni ilk kez duyuyorum
      Yine de Django'nun ortak yaratıcısı muhtemelen birçok deploy görmüştür, o yüzden bunu öylece geçiştirmek zor
    • Açıkçası tehlikeli yaşa deseni gibi geliyor
    • Caddy bunu yapıyor
      Eskiden bu konu hakkında konuştuğumuzu hatırlıyorum
  • Traefik ya da kendini kanıtlamış başka araçlar kullanmak yerine kendi proxy'lerini yapmaya karar vermelerinin nedenini nerede açıkladıklarını merak ediyorum

    • Aslında bu “v2.0.0” ön sürümüne kadar Traefik kullanılıyordu
      Neden değiştirdiklerine ve kendi uygulamalarını yapmaya karar verdiklerine dair bağlam PR'da var
      https://github.com/basecamp/kamal/pull/940
    • Burada nedenleri biraz özetlemeye çalışmıştım https://nts.strzibny.name/kamal-proxy/
      Ama Traefik dışındaki şeylerle resmi bir karşılaştırma yayımladıklarını sanmıyorum
  • Timeout ayarlamanın bir yolu olup olmadığını merak ediyorum
    https://github.com/basecamp/kamal-proxy/blob/main/internal/s...
    https://github.com/basecamp/kamal-proxy/blob/main/internal/s...
    https://blog.cloudflare.com/exposing-go-on-the-internet/

  • NIH. Söylenecek başka bir şey yok