1 puan yazan GN⁺ 1 시간 전 | 1 yorum | WhatsApp'ta paylaş
  • Deptool, DNS ve web sunucusu yapılandırmalarını doğrudan işletmek için yapılmış bir dağıtım aracıdır; önce değişiklik planını gösterir, onaydan sonra hedef ana makinelere uygular
  • Tüm küme yapılandırmasını önceden render edip Git ile yönetir; ana makine bazında /var/lib/deptool altında commit başına dizinler tutar ve current sembolik bağlantısını değiştirerek sürümü atomik olarak geçirir
  • Dağıtımdan önce her ana makinede kilit alır, yerelin bildiği commit ile gerçek dağıtım durumunu karşılaştırıp bayat planı durdurur ve yalnızca etkilenen tüm ana makinelerin kilitleri alınmışsa devam eder
  • Servisler systemd birimleri olarak çalışır; yapılandırma değiştiğinde yeniden başlatılır ve başlatma başarısız olursa bağlantı önceki bilinen iyi sürüme geri alınarak tekrar başlatılır, böylece milisaniye düzeyinde otomatik rollback yapılır
  • Uzak yürütme, SSH’yi yalnızca taşıma katmanı olarak kullanan statik agent yaklaşımıdır; Flatcar Linux gibi Python ve paket yöneticisi olmayan ortamlarda bile yalnızca coreutils ile otomatik kurulum yapılabilir

Deptool’u yapma motivasyonu

  • Avrupa dijital egemenliği hakkında bir yazıyı ABD barındırması ve ABD kontrolündeki hyperscaler altyapısı üzerinde yayımlama çelişkisinden kaçınmak için blogu Avrupa’ya taşıma çalışmasıyla başladı
  • DNS de Cloudflare’a bağlı olduğu için DNS sunucularını doğrudan işletme ihtiyacı doğdu
  • Mevcut web sunucusu küçük bir VM üzerinde Nginx ve sertifika yenileme için Lego çalıştırıyor, Nginx yapılandırması Nix ile üretiliyor, ardından küçük bir Python betiğiyle sunucuya kopyalanıp Nginx yeniden başlatılıyordu
  • DNS sunucusu işletmek için en az iki sunucu, daha fazla systemd birimi, yapılandırma dosyası ve zonefile gerektiğinden mevcut betik yetersiz kaldı
  • NixOS’a geçmek bir seçenekti, ancak en az temel işletim sistemi ile salt okunur chroot içinde yalnızca gereken ikilileri içeren mevcut yaklaşımı koruyup yeni bir dağıtım aracı yazmaya karar verildi

Deptool’un kullanım görünümü

  • Deptool, küme yapılandırmasındaki değişiklik planını önce gösterir ve onay aldıktan sonra hedef ana makinelere uygular
  • DNS kaydı güncelleme örneğinde deptool deploy çalıştırıldıktan sonra s4.ruuda.nl ve s5.ruuda.nl üzerinde nsd yapılandırma dosyası değişikliği ve nsd.service yeniden başlatması plan olarak gösterilir
  • Dağıtım başarısız olursa otomatik rollback uygulanır; örnekte prod kümesindeki 2 ana makineye uygulanıp uygulanmayacağı sorulur ve 0.99 saniyede başarıyla tamamlanır
  • Çıktı, hedef ana makineleri, değişen uygulamaları, değişen dosyaları ve yeniden başlatılacak systemd birimlerini ayrı göstererek dağıtımdan önce gerçekten ne yapılacağını görmeyi sağlar

İstenen dağıtım aracının koşulları

  • Hızlı

    • Yapılandırma güncellemeleri 1 saniyenin altında olmalıdır; transatlantik ping bile 100 ms düzeyindeyken özünde daha yavaş olması için bir neden olmadığı düşünülür
  • Öngörülebilir

    • Araç, ne yapacağını önce göstermeli ve sonra aynen uygulamalıdır
    • OpenTofu’daki gibi plan ve apply aşamalarını ayıran bir yaklaşım istenir
    • Ansible’ın check mode’u, zincirleme değişikliklerin ancak buyurgan adımlar çalıştıktan sonra ortaya çıkabilmesi ve check ile gerçek çalıştırma arasında ana makine durumunun değişmesini engelleyememesi nedeniyle güvenilir bulunmaz
  • Güvenli

    • Nginx yapılandırması bozulduğunda web sunucusunun dakikalarca kapalı kalmaması için araç milisaniye düzeyinde otomatik rollback yapmalıdır
  • Basit

    • Gereken şey yalnızca dizüstünden sunucuya yapılandırma dosyalarını kopyalamak ve birkaç systemd birimini yeniden başlatmaktır
    • Tüm dağıtım sorunlarını çözmesi ya da kontrol akışı ve keyfi kod çalıştırma sağlaması gerekmez
    • Yapılandırma dosyası şablonlama işi ayrı araçlarla yapılabilir; YAML şablonlarına dair sorunlar generate ve ayrı dosya üretim araçları ile ele alınır
  • Bildirimsel olmalı

    • Yapılandırmadan bir dosya veya uygulama kaldırıldığında sunucudan da kaldırılmalıdır
    • Açık bir temizleme adımı eklemek gerekmez; unutma nedeniyle drift veya artık dosya oluşmamalıdır
  • Başlangıç kurulumu gerektirmemeli

    • Sunucu provision edildikten hemen sonra yönetilebilir olmalıdır
    • Agent, daemon, bağımlılıkların elle kurulması ya da ana makine kayıt prosedürü gerekiyorsa, bu prosedürü ayrıca otomatikleştirme sorunu doğar

Yapılandırma üretimi ile dağıtımın ayrılması

  • Temel fikir, yapılandırma üretimi ile dağıtımı ayırmaktır
  • İş yerinde David’in yaptığı Unsible, Ansible playbook’larını adım adım çalıştırmak yerine yerelde bir tarball üretip bunu ana makineye göndererek dosyaları yerleştirir
  • Mevcut basit dağıtım betikleri de dışarıda yapılandırma üretir, betik ise neredeyse yalnızca dosya kopyalama işi yapardı
  • NixOS da bu fikrin yerel sisteme uygulanmış hâli sayılabilir; Nix’ten öğrenilecek nokta, üretilen çıktıları birden fazla sürümün yan yana bulunabildiği bir yerde tutmak ve sistem yönetiminin buyurgan kısmını birkaç sembolik bağlantı değişikliğinden oluşan küçük bir etkinleştirme adımıyla sınırlamaktır
  • Bu tasarım hem paket yönetimi hem de sistem yapılandırması için uygundur

Deptool nasıl çalışır

  • Tüm küme yapılandırmasını önceden render eder

    • Tüm kümenin yapılandırma dosyaları önceden üretilir ve diskteki bir dizine yazılır
    • Dizin ağacı iki seviyelidir; üst seviyede hedef ana makine dizinleri, onun altında uygulama dizinleri bulunur
  • Git deposuna koyar

    • Yapılandırma dizini bir Git deposuna konursa sürümler arası farklar karşılaştırılabilir ve tüm kümede neyin değiştiği görülebilir
    • diffstat ile etkilenen ana makineler ve değişen uygulamalar anlaşılır; ayrıca her yapılandırma dosyasının tam diff’i incelenebilir
  • Dosyaları ana makinedeki yalıtılmış dizinlerde somutlaştırır

    • Tüm dosyalar, başka unsurlarla çakışmaması için /var/lib/deptool altında tutulur
    • Dağıtılacak commit adıyla dizinler oluşturulduğu için birden fazla sürüm diskte yan yana bulunabilir
    • current sembolik bağlantısı dağıtılmış sürümü işaret ederek sürümün atomik biçimde değiştirilmesini sağlar
    • Silinen dosyalar sonraki sürümde somutlaştırılmadığı için artık dosya kalmaz
    • Dosyaları belirli konumlarda bekleyen uygulamalar için dosya sistemindeki gerekli yerlerden /var/lib/deptool içine sembolik bağlantılar oluşturulabilir
    • Sembolik bağlantı oluşturma ve silme atomik değildir, ancak bu yalnızca dosya içeriği değiştirirken değil, bağlantı ekleme veya kaldırma gerektiğinde lazımdır
    • Sonraki dağıtım sürümünde ilgili sembolik bağlantı yer almazsa diff üzerinden silinmesi gerektiği anlaşılır; böylece artık dosya kalmaz
  • Uzak izleme ref’leriyle dağıtım durumunu kaydeder

    • Operatörün dizüstü bilgisayarından her ana makineye hangi commit’in dağıtıldığını takip eder
    • Dağıtım durumu, kümenin genel bir özelliği değil, ana makine bazlı bir özelliktir
    • Bir değişiklik belirli bir ana makineyi etkilemiyorsa o ana makineye yeni bir commit dağıtmaya gerek yoktur
    • Bu bilgiyle küme diff’i çevrimdışı hesaplanabilir ve bu diff dağıtım planı olur; böylece plan milisaniyeler içinde gösterilebilir
  • Dağıtımdan önce hedef ana makinelerde kilit alır

    • SSH ile bağlanıp kilit isteği gönderir; istekte, o ana makinede dağıtıldığını düşündüğü commit de yer alır
    • Kilit alınabiliyorsa plan geçerlidir ve kilit bırakılana kadar başka bir dağıtım o ana makinede ilerleyemez; dolayısıyla plan geçerliliğini korur
    • Dağıtım yalnızca değişiklikten etkilenen tüm ana makinelerin kilitleri elde edilmişse ilerler
    • Ref eskiyse ve ana makineye başka bir şey dağıtılmışsa plan bayat sayılır ve iptal edilir
    • Daha sonra yerel ref güncellenirse sonraki çalıştırmada güncel plan görülebilir
  • systemd birimlerini yeniden başlatır

    • Tüm servisler systemd birimleri olarak çalışır ve hızlı açılır; bu yüzden emin olunmadığında yeniden başlatmak tercih edilir
    • Uygulama yapılandırması değişirse etkilenen systemd birimleri yeniden başlatılır
    • Birim başlatılamazsa sembolik bağlantı önceki bilinen iyi sürüme döndürülür ve yeniden başlatılır; böylece milisaniye düzeyinde otomatik rollback mümkün olur

İyimser eşzamanlılık modeli

  • Deptool dağıtımında iyimser eşzamanlılık unsuru vardır
  • Mevcut küme durumunun bilindiği varsayımıyla plan yapılır; bu varsayım yanlışsa yeniden denemek gerekir
  • Çakışma olmadığında çok hızlıdır; kişisel altyapıyı tek kişinin aynı dizüstünden dağıttığı durum buna örnektir
  • Birden çok kişinin sürekli dağıtım denediği ortamlarda yalnızca biri başarılı olur, diğerleri yeniden denemek zorunda kalır; bu da performansı ciddi biçimde düşürebilir
  • Bu model git push gibidir; yüzlerce kişi veya binlerce sunuculuk ölçeğe uygun değildir ama kişisel altyapı için yeterlidir
  • Kendi aracını yapmak, tam kullanım senaryona göre optimize etmeyi mümkün kılar

Agent oluşturma

  • Flatcar Linux ve ilk host kısıtları

    • Web sunucuları Flatcar Linux üzerinde çalışır
    • Flatcar Linux, image tabanlı bir işletim sistemidir; userspace’i çok küçüktür, coreutils ve Bash vardır ama paket yöneticisi ve Python yoktur
    • Bu, saldırı yüzeyini azaltmak için iyidir ancak bir şey kurmayı zorlaştırır
    • Araç çalışmadan önce bir şey kurulması gerekiyorsa, o kurulum sürecini otomatikleştirmek gibi yeni bir sorun doğar
  • SSH yalnızca taşıma katmanı olarak kullanılır

    • Yeni host’ları dışarıdan yönetmek gerektiği için SSH ve passwordless sudo kullanılabilir
    • Komutları doğrudan SSH üzerinden çalıştırmak yalnızca handshake yüzünden yavaş değildir; aynı zamanda argv SSH sınırını güvenle geçemez ve shell-over-SSH’deki word splitting ile escaping sorunlarıyla uğraşmak gerekir
    • Deptool, öngörülebilir bir konumdaki argümansız tek bir programı çalıştırır ve bunu agent olarak kullanır
    • Agent, stdin’den mesajları okur ve stdout’a yanıt verir
    • SSH, yalnızca soket benzeri bir taşıma aracı olarak kullanılır; kullanıcı kontrollü girdi SSH veya shell komutlarının içine girmediği için escaping sorunları önlenir
  • Statik binary kullanır

    • Agent, statik binary olarak derlenir
    • Çekirdek dışında ne bulunduğuna dair varsayım yapmaz ve işe yarar bir şey yapmadan önce megabaytlarca kod parse etmesi gereken bir yorumlayıcı da gerektirmez
    • Ansible, en kötü kusurlarını hafiflettikten sonra bile her bağlantıda birkaç MB Python modülü aktarır; ayrıca Flatcar’da Python da yoktur
  • Binary’yi commit tabanlı yola koyar

    • Agent binary’si, derlendiği commit’i içeren bir yolda saklanır
    • Bu, bağlantının iki ucunun da aynı sürümü çalıştırmasını garanti eder ve protokol uyumluluğu sorunlarını önler
    • Yol biçimi /var/lib/deptool/bin/deptool-<version>-<commit> şeklindedir
  • Önce binary’nin var olduğu varsayılır

    • SSH handshake pahalı olduğu için probe veya idempotent kurulum adımına harcanmaz
    • Agent binary’si yaklaşık 1.6 MB’tır; göndermesi yasak ölçüde büyük değildir ama ücretsiz de sayılmaz
    • Küme yapılandırma değişiklikleri, Deptool güncellemelerinden çok daha sık olur; bu yüzden genellikle binary’nin zaten mevcut olduğu varsayılır
  • Çalıştırma başarısız olursa binary kurulur

    • Binary başlatılamazsa ikinci bir SSH bağlantısıyla kurulum yapılır
    • Çalıştırma komutu şöyledir
uname -sm
&& sudo mkdir -p /var/lib/deptool/{bin,apps,store}
&& sudo dd status=none of=<remote_bin_path>
&& sudo chmod +x <remote_bin_path>
&& sudo sha256sum <remote_bin_path>
  • Önce stdout’tan bir satır okunup uname çıktısı alınır; böylece işletim sistemi ve CPU mimarisi belirlenir ve uygun platform binary’si gönderilir
  • Binary stdin’e yazılır, uzaktaki dd bunu diske kaydeder
  • Son olarak stdout’tan bir satır daha okunup uzakta hesaplanan shasum doğrulanır ve aktarımın başarılı olduğu kontrol edilir
  • Bu süreç yalnızca standart coreutils programlarına dayanır
  • Ardından agent yeniden çalıştırıldığında başarılı olması gerekir; agent da diskin dolmaması için eski sürümleri temizler

Agent yaklaşımının etkileri ve maliyeti

  • Uzak host üzerinde agent çalıştırıp onunla iletişim kurma yöntemi sağlanır
  • Uzak host’ta coreutils dışında bir gereksinim olmadan otomatik kurulum yapılabilir
  • Her iki taraf aynı sürümü çalıştırdığı için protokol uyumluluğu yapısal olarak garanti edilir
  • Kullanıcı kontrollü girdi yalnızca SSH tabanlı soket üzerinden iletilir; SSH veya shell komutlarına girmediği için escaping sorunları ve uzunluk sınırları önlenir
  • Normal durumda yalnızca tek bir SSH handshake gerektiğinden gecikme düşüktür
  • Yeni makineye ilk dağıtımda veya araç güncellemesinden sonra gibi seyrek durumlarda 2 ek bağlantı ve tek seferlik 1.6 MB aktarım gerekir
  • ControlMaster kullanılırsa sonraki bağlantıların büyük kısmındaki ek yük atlanabilir; toplam maliyet birkaç saniye düzeyine iner
  • Bu durumda dağıtım 1 saniyenin altında olmaz ama yine de Ansible’dan daha iyidir
  • Yapılandırmayı dağıtıp biraz düzenleyip yeniden dağıtma akışında SSH temel bağlantıyı açık tutabildiğinden dağıtımlar anlık hissedilir

Kullanım sonuçları ve yayımlanması

  • Deptool son bir aydır kişisel altyapıyı yönetmek için kullanılıyor
  • Bağlanmadan önce tam planı anında görebilmek ve otomatik rollback olması değerli, ancak en büyük değişim 1 saniyenin altındaki dağıtım
  • Doğru dağıtım yöntemi dakikalar sürerse geri bildirim döngüsünü kısaltmak için sunucuda doğrudan dosya düzenleme isteği doğar; ancak Deptool ile yerelde değiştirip dağıtmak, SSH ile sunucuya bağlanıp editör açmaktan daha hızlıdır
  • En az sürtünmeli yöntem doğru yöntem hâline gelir ve uygulanan tüm değişiklikler Git geçmişine yazılır
  • Bir şey bozulsa bile, bozulduğunu fark etmeden önce Deptool geri alır
  • Deptool, kişisel bir sorunu tam olarak çözmek için yapıldı; herkesin tüm dağıtım sorunlarını çözmeye çalışmaması, kendi kullanım senaryosunda onu güçlü kılan şeydir
  • Özellikle image tabanlı işletim sistemlerinde yararlı olabilir; Codeberg ve GitHub üzerinde açık kaynak olarak yayımlanmıştır ve ayrıntılı bir manual da sunulur

1 yorum

 
GN⁺ 1 시간 전
Lobste.rs yorumları
  • Bu projeye LLM tarafından üretilmiş metin koymadığını açıkça belirtmesi gerçekten sevindirici: not putting LLM-generated text anywhere near this
    Aracın kendisi de iyi rafine edilmiş ve tasarımı güçlü görünüyor, ama ben bir süre daha NixOS kullanmaya devam edeceğim gibi

  • Kesinlikle denemeyi düşünüyorum. systemd tabanlı servisleri dağıtmak için kendim yaptığım sistemin daha cilalanmış bir sürümü gibi görünüyor
    Eğitim içeriği güzel görünüyor ama yerel durumun nasıl ele alınmasının daha doğru olacağını merak ediyorum. Örneğin uygulamanın sqlite veritabanının nereye kaydedilmesi gerektiğini belgelerde bulamadım
    Bir de uygulama ikilisini sunucuya gönderip systemd biriminde kullanmanın bir yolu var mı merak ediyorum. Yoksa ikili dağıtımını nasıl yaptığını bilmek isterim

    • Sunucu tarafında ise genelde daha önce nereye koyuyorsanız oraya koyabilirsiniz; standart konum /var/lib/<yourapp> olur
      Uygulamayı bir systemd birimi olarak çalıştırıyorsanız, systemd'nin doğru kullanıcı sahipliğiyle dizini oluşturması için StateDirectory= kullanabilirsiniz
    • Deptool tek başına ikili dosya aktarımı yapmıyor
      Çalıştırdığım uygulamaları Nix tabanlı bu script ile küçük EROFS imajları olarak derliyorum; script aynı zamanda imajı sunucuya push etme işini de yapıyor. Eskiden ayrı bir adımdı ama şimdi build ve push tek adımda birleşti, ayrıca benzersiz dizinlere yerleştiği için birden çok sürüm yan yana bulunabiliyor
      Build çıktısı dosya yollarını içeren bir JSON da üretiyor; bunu küme yapılandırmasına aktarıp systemd birimlerine render ediyorum ve ardından Deptool ile dağıtıyorum. Yani bir araç imaj dağıtımını üstleniyor, Deptool ise etkinleştirmeyi yapıyor
      Konteyner kullanıyorsanız genelde registry'ye push edersiniz; sunucuda da sadece neyin çekileceğini belirten yapılandırma dosyaları olur, bu kısmı yalnızca Deptool ile yönetmek mümkündür
  • Alternatif bir yaklaşım olarak bootable containers kullanmak da oldukça iyi
    Şimdilik eksik olan şey, doğru host üzerinde gerçekten bootc update --apply çalıştıracak bir mekanizmanın olmaması. Otomatik güncelleme mekanizması var ama orkestre edilmediği için kümede istenen bir davranış değil
    Şu anda bunu elle yapıyorum ama sonuçta çalıştırılması gereken tek şey bir bootc komutu olduğu için, ileride script'e dökmek kolay görünüyor

  • Her yeni dağıtım aracı çıktığında biraz şüpheyle bakıyorum, ama bu iyi tasarlanmış ve iyi rafine edilmiş görünüyor
    ssh komutunu doğrudan kullanması da doğru bir tercih gibi. Kullanıcı, elindeki ssh'nin gerçekten çalıştığını biliyor; hatta çok özel ayarlara veya yamalanmış bir ssh ikilisine sahip olabilir
    Harici bir kütüphane ile ssh'yi yeniden uygulamaya çalışan araçlar, bazı kullanıcılar için engel çıkarma riski taşıyor

  • EROFS'u nasıl ve neden kullandığını daha ayrıntılı duymak isterim

    • Bunu Nginx ve birkaç uygulamayı Flatcar'a dağıtmak için kullanıyorum; insanların bu amaçla OCI imajı kullanma biçimine oldukça benziyor
      Flatcar'da paket yöneticisi olmadığı için yazılımı ve bağımlılıklarını bir şekilde kendiniz yerleştirmeniz gerekiyor; kendi içinde tamamlanmış bir dosya sistemi imajı da bunun yollarından biri
      OCI imajlarında Podman veya Docker gibi ayrı araçların tar arşivini bir yere açıp overlay mount katmanları kurması gerekiyor; ama zaten bir dosya sistemi imajınız varsa, bunu systemd biriminde doğrudan RootImage= ile çalıştırabilirsiniz
      İmajları Nix ile derliyorum, bu yüzden içinde gerçekten yalnızca minimum bileşenler var. Nginx ikilisi, LibreSSL, libc ve birkaç paylaşımlı kütüphane; Bash bile yok
      Bu, savunmayı derinleştirme yaklaşımının bir parçası. Nginx'te uzaktan kod çalıştırma açığı olsa bile, saldırgan neredeyse hiç ek araç içermeyen bir dosya sistemi namespace'i içinde kalıyor; ayrıca tüm dosya sistemi salt okunur. Sadece salt okunur mount edildiği için değil, EROFS'ta yazma desteği zaten yok
      Eskiden Squashfs kullanıyordum ve iyi çalışıyordu ama o dosya sistemi live CD dönemi düşünülerek tasarlanmıştı. EROFS, günümüz sistemleri için daha uygun ödünleşimler seçiyor, fakat dürüst olmak gerekirse benim kullanımımda ölçülebilir bir fark olmayabilir
      İmajlar daha küçük oluyor, ama bunun nedeni farklı sıkıştırma ayarları kullanmam. Teoride EROFS, farklı sürümlerdeki imajlar arasında veri yeniden kullanımını hedefliyorsanız content-defined chunking için daha uygun; ancak bunu imaj aktarımında henüz fiilen kullanmıyorum
  • Tam da bir arkadaşımla basit bir dağıtım stratejisini konuşuyorduk ve bu yazı o sırada çıktı; vardığımız sonuca epey yakın
    Yalnız bu kurulumda gizli değer yönetimi nasıl yapılıyor, onu merak ediyorum

  • “Prompting the deployment tool I wish I had” denmiş ama,
    https://codeberg.org/ruuda/deptool/…
    Bir bakıma kayan noktalı sayıların Rust kullanmaya ikna edilmiş olması etkileyici

    • Kod üretmek için LLM kullanıyorsam, birçok açıdan aslında Rust tercih ederim
      Olumlu tarafından bakarsak Rust “disiplinli” bir dil; güçlü teamülleri ve araç ekosistemi var. Bunların ikisi de LLM'e yardımcı oluyor
      İlginç şekilde LLM'ler, en azından biraz yönlendirme verilirse, bazı dillere kıyasla Rust'ta daha kısa programlar üretme eğiliminde. Nasıl olsa tüm kodu okuyup elden geçireceğim için, benim açımdan kısa olması daha iyi
  • Bununla gizli değerleri nasıl ele aldığını merak ediyorum. Tercih ettiğin özel bir iş akışı var mı; bunları EROFS imajına mı koyuyorsun yoksa systemd ile mi enjekte ediyorsun?

    • Şu anda tek gizli değer TLS sertifikaları; bunların yalnızca tek bir sunucuda bulunması gerekiyor ve Lego onları doğrudan oraya yerleştiriyor
      İlgili dizin Lego biriminde okuma-yazma olarak, Nginx biriminde ise salt okunur olarak mount ediliyor