- Railway, mevcut Nixpacks yerine Railpack adlı yeni bir build sistemini kullanıma sundu
- Railpack; daha ayrıntılı sürüm yönetimi, daha küçük imaj boyutları ve gelişmiş cache gibi alanlarda mevcut Nixpacks'e göre daha güçlü özellikler sunuyor
- Nixpacks'in commit tabanlı sürümleme yaklaşımı, farklı kullanıcı ihtiyaçları ve ölçeklenebilirlik açısından sınırlarını ortaya koydu
- Railpack; BuildKit entegrasyonu, gizli ortam değişkenlerinin korunması ve çeşitli dil ile framework desteği sayesinde build ortamının kararlılığını ve esnekliğini iyileştiriyor
- Şu anda Node, Python, Go, PHP ve statik HTML destekleniyor; framework ve dil desteği genişletilmeye devam ediyor
Genel Bakış ve Arka Plan
- Railway, Railpack adlı yeni nesil bir build sistemini tanıttı
- Railpack, Railway platformunda 14 milyondan fazla uygulamayı Nixpacks ile build ederken edinilen deneyim temel alınarak sıfırdan geliştirilen bir araç
- Mevcut Nixpacks, kullanıcıların %80'i için yeterliydi; ancak 200 binden fazla kullanıcı kısıtlamalarla karşılaşıp sorun yaşadı
- Kullanıcı tabanını büyütmek ve sürdürülebilir bir build ortamı sağlamak için büyük bir yükseltme gerektiğine karar verildi
Railpack'in Başlıca İyileştirmeleri
- Ayrıntılı sürüm yönetimi: Her paket için
major.minor.patch düzeyinde hassas sürüm belirtme desteği sunarak, Nix'in belirsiz sürümleme yaklaşımının sınırlarını aşıyor
- Daha küçük imaj boyutları: Node'da %38'e, Python'da %77'ye kadar daha küçük varsayılan build imajları ile daha hızlı dağıtım deneyimi sağlıyor
- Güçlü cache: BuildKit ile doğrudan entegre olarak katmanları ve dosya sistemini kontrol ediyor, cache isabet oranını artırıyor ve ortamlar arasında cache paylaşımını mümkün kılıyor
- railway.com ve merkezi servislerde Railpack build'leri halihazırda kullanılmaya başlanmış durumda
Nixpacks Kullanımındaki Sorunlar
- Nix'in paket sürümleme modeli commit tabanlı bir yapıya sahip; yalnızca en güncel major sürümü sunuyor ve her sürüm nixpkgs deposundaki belirli bir commit'e karşılık geliyor
- En küçük patch sürümlerine kadar her şeyi elle yönetmek gerekiyor; katkıda bulunanlar için de sürümleme sezgisel olmadığı için erişilebilirlik düşüyor
- Node veya Python gibi dillerde de sonuçta yalnızca en güncel major sürüm destekleniyor
- Sürüm güncellemelerinde commit hash değiştiğinde diğer paket sürümleri de topluca etkilenebiliyor; bu da güvenilirliği azaltıp beklenmeyen build hatalarına yol açabiliyor
- Nixpacks'te tüm bağımlılıklar
/nix/store içindeki tek bir katmanda yer aldığı için imajı etkili biçimde bölmek veya boyutunu küçültmek zorlaşıyor
- Cache tarafında da, ortam değişkenleri her enjekte edildiğinde katmanlar sürekli invalidate olduğu için cache verimli kullanılamıyor
Sorun Nix'in Kendisi Değil, Kullanım Biçiminin Sınırları
- Sorun Nix'in tasarımında değil, Railway'in onu kullanma ve soyutlama biçiminde ortaya çıktı
- Kullanıcıların Nix'in derivation kavramını veya iç sürüm yapısını anlamasına gerek kalmaması hedeflenmişti, ancak bunun pratikte mümkün olmadığı görüldü
- Bu sorunları çözmek için Railpack geliştirildi
Railpack'in Teknik Mimarisi
- Rust → Go kod tabanı geçişi: BuildKit'ten yararlanmayı ve ekosistemle uyumu güçlendirmek için kod tabanı Go'ya taşındı
- BuildKit LLB ve frontend: Özel BuildKit LLB ve frontend doğrudan üretilerek build imajının yapısı hassas biçimde kontrol ediliyor → Node ve Python varsayılan imajları Nixpacks'e kıyasla ciddi ölçüde hafifliyor
- Mise ile sürüm yönetimi: Paket kurulumu ve sürüm çözümleme için Mise kullanılıyor; ileride başka çalıştırılabilir kaynaklarını desteklemek de kolaylaşıyor
- Build başarıyla tamamlandığında, o andaki bağımlılıkların kilitlenmesi uygulanıyor → varsayılan Node sürümü 22'den 24'e çıksa bile mevcut build'ler bozulmuyor
- BuildKit'in secret özelliği kullanılarak ortam değişkeni güvenliği ve yönetimi iyileştiriliyor
Railpack Build Aşamaları
- Analyze: Kod analiziyle gerekli paketler, çalıştırma komutları ve başlangıç komutu çıkarılıyor
- Plan: JSON olarak serileştirilebilen bir build planı oluşturuluyor (birden fazla aşama içeriyor; her aşama önceki aşamanın sonucuna veya tüm imaja bağımlı olabiliyor)
- Generates: BuildKit için build grafiği oluşturuluyor (girdi/çıktı temelinde)
BuildKit ile Stratejik Build Yaklaşımı
- Dockerfile seri çalışırken, BuildKit birden fazla komutu paralel işleyebiliyor ve her aşamanın girdi/çıktılarını ayrıntılı biçimde kontrol edebiliyor
- Railpack, kod analizi sonucunda tüm build aşamalarını tanımlıyor ve her aşamanın bağımlılık ilişkilerini düşük seviyede ayrıntılı şekilde belirliyor
- Bu plan daha sonra bir BuildKit LLB grafiğine dönüştürülüp çözümleniyor
- Ortam değişkenleri gibi değerler değiştiğinde, ilgili değerin hash'iyle dosya mount ediliyor; kod ve değişkenlerde fark yoksa cache isabeti garanti ediliyor
- Sonuç olarak imajın nasıl üretileceği tamamen Railpack'in kontrolüne giriyor
Railpack ile Mümkün Hale Gelen Yeni Özellikler
- Vite, Astro, CRA ve Angular statik siteleri için sıfır yapılandırmayla destek
- Railway arayüzüyle build sürecinin sıkı entegrasyonu
- Dillerin en güncel sürümleri, Railpack'in kendisi yeni bir sürüm yayınlamadan da desteklenebiliyor
- Proje bazında ortamlar arası cache optimizasyonu sağlanıyor
- Şu anda Node, Python, Go, PHP ve statik HTML destekleniyor; framework ve dil desteği sürekli genişliyor
Açık Kaynak ve Gelecek Planları
- Railpack beta durumunda yayında ve etkinleştirildiğinde hemen kullanılabiliyor
- Resmî dokümantasyon, gerçek kod ve herkese açık destek kanalları railpack.com üzerinden sunuluyor
- Gelecekte önce yaygın kullanılan dillere derin destek verilecek; ardından çekirdek API ve soyutlama seviyesi oturduğunda kapsam genişletilecek
1 yorum
Hacker News görüşü
Ben bir Nix hayranıyım, ama Nix kullanmamayı seçmiş olmalarına duygusal olarak takıntılı yaklaşmadığımı düşünmenizi isterim. Yine de bu yazıdaki bazı şikayetleri pek anlayamadım ve biraz daha açıklama gerektiğini düşünüyorum. Örneğin, “Nix’in en büyük sorunu commit tabanlı paket sürümleme” deniyor. Nixpkgs harika bir kaynak, ama Nix ile Nixpkgs aynı şey değil. Toolchain’in rastgele bir sürümünü almak için Nixpkgs gerçekten pek uygun değil, ama Nix ile başka yollar var. Mesela Rust’ın rastgele sürümlerini düzgünce çeken Nix araçları gerçekten çok iyi durumda. Bir de “Nix bağımlılıkları ayrı katmanlara bölünemez” denmiş; bana göre bu hiç mantıklı değil. İstediğiniz şekilde bölmek mümkün. Nixpkgs’in Docker araçları da bunu destekliyor. Kod tabanını Rust’tan Go’ya taşıma kısmı Nix’le doğrudan ilgili değil ama ilginç geldi. İnsanlar genelde dil değişimini hafife alarak vermez; çoğu zaman zaten baştan yeniden yapmayı düşündüklerinde olur. Railpacks ile Nixpacks’in farklı kişiler tarafından geliştirilmiş olmasından şüpheleniyorum. Nix’i çok iyi bilmeyen insanların, kurum içinde yarım kalmış bir Nix çözümünü yönetmek zorunda kaldığı durumları da gördüm. Pek iyi görünmüyor ve çoğu insan Nix öğrenmek istemiyor. Bu yüzden eski iş yerimde böyle bir durumdan kaçınmak için Nix’i neredeyse hiç kullanmıyoruz
Nix’ten yararlanmayı seviyorum ama Nix’in temel kullanım sorunları tartışıldığında sürekli “bir çözüm yolu var” cevabını almak yorucu oluyor; ama bunun bedeli de yetersiz dokümantasyon, tuhaf bir dil, kötü hata mesajları ve sadece daha önce kullanmış olanların bildiği eksik bilgilerle onlarca hatta yüzlerce satır kod eklemek oluyor. Nix’le ilgili sorunların çoğu Turing-complete olmasından değil, sezgisel API’ler gibi temel yerleşik imkanların olmamasından kaynaklanıyor. Her projede Nix kullanımı giderek Nix’in kendi sorunlarını çözmeye dönüşüyorsa, ortada iyi dokümante edilmiş ana akım araçlar varken Nix kullanmak için bir sebep kalmıyor. Gerçekte de insanlar çoğunlukla Docker’ı seçiyor. Nix’in geliştirici deneyiminin gerçek sorunlarını makul sürede çözmek yerine ideal saflıkta ısrar etmesi büyük bir hayal kırıklığı. Elbette herkes gönüllü katkı veriyor ama bunca teknik emeğin kötü tasarlanmış UX yüzünden pratikte kullanılamaz halde kalmasını görmek çok üzücü
Nix kullanmıyorum ama “Nix ≠ Nixpkgs” iddiası bana gerçeklikten kopuk geliyor. Kullanıcıların büyük çoğunluğu için, alternatifler ek araştırma ve çaba gerektiriyorsa, sonuçta Nixpkgs fiilen Nix’in kendisi oluyor. “Ayrı katmanlara bölünebilir” deniyorsa, bunun gerçekten sezgisel, basit ve varsayılan davranış olup olmadığını merak ediyorum
Buradaki önemli nokta, Railway kullanıcılarının istedikleri paket sürümünü belirtmek isteyen geliştiriciler olması. Nix ve Nixpkgs yapısı gereği, bir paketin sürümünü sabitlemek tüm nixpkgs ağacının commit’ini sabitlemek anlamına geliyor. node/python/ruby paket derlemeleri ağaç dışındaki şeylere çok bağımlı olduğu için sürümle commit arasında eşleme gerekiyor. Bu soyutlama kusursuz değil; kullanıcı basitçe “yarn add paket” yapmak istese bile ağaç durumunu da uyumlu hale getirmesi gerekebilir. Nixpkgs olmadan yalnızca Nix kullanmak sınırlı kullanım için kabul edilebilir ama Railway gibi bir platform için zor bir tercih
Sürümleme tartışmasını pek anlamıyorum. Nix’i ilk kez kullanıyorum ama belli bir commit’ten alınmış paketlere sahip olduğum çok açık
Bence oldukça isabetli anlatmış. Nixpkgs ile Nix farklı ama fiiliyatta asıl avantaj Nixpkgs. NixOS kullanırken ilk kez Linux kernel’in en yeni sürümünü çıktığı gün kullandım. Debian Stable da iyi ama hep birkaç yıl geçmişe dönmüşüm gibi hissettiriyor. Yine de Nix dili fazlasıyla eleştiriyi hak ediyor. Eski bir dil ve elinden gelenin en iyisi yapılmış olsa da değiştirmeye değmez diye düşünüyorum. Nix build sistemi klasik yapıda ve gereksiz yeniden derlemeler çok gibi geliyor. Mesela NixOS kurulum ISO’sunda kernel’e verilen komut satırında yalnızca bir şeyi değiştirmek bile — örneğin konsol port hızı — yaklaşık 3 dakikalık tuhaf bir build’e yol açıyor. Komik ama bu yüzden Nix’ten vazgeçmiyorum. Sadece kendi build sistemimde asla kabul etmeyeceğim bir durum. Docker image üretmek için Nix kullanmak bana göre en kötü senaryo. Eskiden Go ile üretilmiş bir binary’ye yalnızca Postgres’in pg_dump binary’sini eklemek istemiştim; altyapı ekibi Nix önerdi, kullandım ve sıkıştırılmış Go binary’si 50MB iken ortaya 1.5GB’lık bir canavar image çıktı. pg_dump ise sadece 464KB. Sonunda Bazel, rules_debian ve distroless kombinasyonuyla işi çok daha temiz çözdüm. Neredeyse tüm Nix sistemleri varsayılan olarak 1.4GB gibi hissettiriyor. Büyük C++ projelerini derlemede de Nix olağanüstü değil. Hatta kendi yazılımınızı derlemek için kullanılan sistemler çoğu zaman kendi ihtiyaçlarına daha iyi uyuyor. Ben Bazel’i seviyorum ve Go projelerinde sadece
go buildkullanmak istiyorum. Vakaların %99’unda Nix yerine böyle araçları kullanırım; yalnız güncelleme veya dağıtım için flake yazıp home-manager’da kullanabilirimSürüm seçimi bana tuhaf geliyor. nixpkgs sürümü bir sistemi çalıştırırken ya da build alırken gayet mantıklı. Runtime/compiler sağlayan bir platformsa devenv gibi sürümleri doğrudan sunması gerekir. Örneğin nixpkgs-python, “tüm Python sürümleri, Nix ile her saat güncellenmiş” sağlıyor. Railway’in deployment ID ortam değişkenini tüm build’lere enjekte etmesi de kurulum sonrası bir katmanda yapılabilirdi. Paketler de birden fazla katmana ayrılabilir, hatta katman sayısını ayarlamak da otomatikleştirilebilir
DevOps/SRE deneyimi olan biri olarak, birinin bağımlılık yönetim sistemi yapmaya çalıştığında işin genelde iki yoldan birine çıktığını görüyorum (örnek olarak Python). Seçenek 1: “monorepo + ortak ortam”. Artıları: yönetmesi kolay, güvenlik yamaları rahat, her şey merkezileşmiş. Eksileri: biri her zaman özel bir sürüm ister, kademeli rollout zordur, slim image üretmek sıkıntılıdır. Seçenek 2: “herkes kendi conda/venv ortamını kullansın”. Artıları: kişiye özel uyarlama, gereksiz paketlerin dışarıda kalması, kademeli yükseltme mümkün. Eksileri: çok fazla ortam oluşur, aralarındaki uyumluluk test edilmemiştir, güvenlik yönetimi kabusa döner. Sonuçta kariyer ilerledikçe “çözüm yok, sadece trade-off var” sözünün ne kadar doğru olduğunu daha çok hissediyorum
“Nix’in kendisinde sorun yok. Sorun nasıl kullanıldığıydı” cümlesi, “işe uygun aracı kullan” düşüncesine iyi bir örnek bence. Nix bazı yerlerde harika, bazı yerlerde ise berbat. Sorun şu ki öğrenmesi çok zaman alıyor; belli bir seviyeye gelip karar verecek noktaya geldiğinizde de çoktan ciddi zaman yatırmış oluyorsunuz. Bu yüzden yön değiştirmek zorlaşıyor ve sonunda insanlar Nix’i aslında uygun olmadığı amaçlar için de zorla kullanmaya devam ediyor
shell.nixya daconfiguration.nixdosyalarını bir spesifikasyona göre üretebilmesi de biraz bu yapı sayesinde. Ben de sık sık depo bazında tamamen kapsüllenmiş env’ler kuruyorum; flakes ile daha da yeniden üretilebilir ortamlar elde edilebilir gibi. (flake.nix,shell.nix’e benziyor ama sürüm sabitlemeyi de destekliyor…)Bana göre sürüm olmayan bir yere zorla sürüm kavramı sokmaya çalışıyorlar. “Varsayılan sürüm” yüzünden bağımlılıklar bozuluyormuş? Bu, Docker’da
:latestetiketi kullanıp her değişiklikte sunucunun bozulmasına benziyor. Blog yazısını pek anlamadım. “Nix bağımlılıkları ayrı katmanlara bölünemez” iddiasına da katılmıyorum./nix/storeistediğiniz kadar parçaya ayrılabilir ve bence burada konteynerlerle Nix’in nasıl kullanılacağı pek bilinmiyor. Yeterlilik bu kadar düşükse, önerilen alternatif de sonunda aynı sorunları tekrar eder gibi geliyor. Klasik bir NIH (kendi aracını icat etme) sendromu örneğiNix uygun değilse kullanılmaması normal ama zaten çalışan bir sistemi, başkalarının da çözmüş olduğu ve biraz araştırmayla bulunabilecek sorunlar yüzünden, baştan sona yeniden yapmak bana temelden tuhaf geliyor. nix2container veya flakes bütün sorunları çözebilir gibi duruyor. Sürümleme konusunda da, 3 yıl önce yazdığım flakes bugün hâlâ aynı şekilde build oluyor ve sonuç değişmiyor. Bana biraz pazara açılma ya da yatırım toplama odaklı bir platform dönüşümü kokusu veriyor. Bu arada nixpacks GitHub’ına baktım; sadece rustPlatform kullanıyor gibi görünüyor ve sorun Rust ise rust-overlay fiilen doğru çözüm
Hangi yaklaşımın VC çekmeyi kolaylaştırdığını düşünürseniz, bir Nix wrapper’ından ziyade “deployment platform” etiketi daha avantajlıdır
“Nix bağımlılıkları ayrı katmanlara bölünemez” denmesine rağmen, nix2container tam olarak bunu yapabiliyor. Örneğin bash gereken bir image varsa, yalnızca bash içeren katmanı ayrı oluşturabilirsiniz ve bu katman sadece bash değiştiğinde yeniden build edilip push edilir. “Bağımlılıklar yüzünden devasa bir image tek bir
/nix/storekatmanı olarak oluşuyor” iddiası danixpkgs.dockerTools.buildImageiçin geçerli olabilir amanix2containerveyanixpkgs.dockerTools.streamLayeredImageiçin geçerli değil. Bu araç aslında bir script üretip image’ı onunla push ediyor.nix2container, tüm katman yollarını JSON’a dönüştürüyor ve Skopeo kullanarak image’ı Docker, registry, podman vb. yerlere push ediyor. (Bu aradanix2containerın yazarı benim)nix2containeriçin gerçekten teşekkür etmek istiyorum. AWS (ECR) dağıtımında kullanıyoruz ve build’ler arası geçiş süresi tek haneli saniyelere düştüBiz de Docker image boyutu sorunları yüzünden
nix2containertest etmeyi planlıyorduk. Güzel araç için teşekkürlerBence buradaki asıl sorun, dil paket yöneticilerinin teşvik ettiği “özel sürüm çorbası” yaklaşımını sürdürmek istemeleri ve bunun zaten sürdürülebilir olmaması. Alternatif olarak önerilen Mise, paketler arası sürüm kısıtlarını anlamıyor ve her paketin testini de hiç yapmıyor. Aynı seviyede güvenilirlik beklenemez
Özel sürüm çorbasının sürdürülemez olduğu doğru, ama insanların bunu kullanmaya devam etmesinin nedeni işe yaraması. İşletim sistemi seviyesindeki kütüphaneler çok tutucu yönetiliyor, bu yüzden kolay kolay bozulmuyor; üstüne mise veya asdf gibi araçlarla özel sürüm kombinasyonları koysanız da çoğu zaman sorun çıkmıyor. Kırılsa bile sürüm ya da ayarlarla oynayıp hemen çözebiliyorsunuz. Bozulması can sıkıcı ama kritik değil. Ek öğrenme veya çaba isteyen sistemler zaman kaybı gibi görülüyor. Buna karşılık “bozulmayan durum”u daha önemli görenler, öğrenme eğrisi ve rahatsızlığa rağmen Nix’i tercih ediyor. Railway gibi çok sayıda kullanıcıya hitap eden bir yerde de sonuçta ilk grubu, yani kolaylık ve ataleti, daha fazla önemseyen bir seçim yapılmış oluyor
“Özel sürüm çorbası” ile tam olarak ne kastediliyor ve alternatif ne, merak ettim
İkisi de pekâlâ mümkün. Örneğin Rust paketleri Cargo.lock bilgisiyle Nix üzerinde kolayca build edilebiliyor. Nixpkgs özel sürüm kombinasyonlarıyla çatışıyor olabilir ama Nix’in kendisi bu işi gayet iyi yapıyor
Nix rastgele sürümleri değil, commit düzeyinde garantiyi hedefliyor. glibc değişiklikleri veya paylaşımlı kütüphane çakışmaları gibi uç durumlarda uğraştırabilir. Belki artık geçtir ama Nix’i daha zarif kullanma yöntemleri konusunda danışmanlık verebilirim. Ürünün kendisi bence etkileyici
Nix, paylaşımlı kütüphane çakışmalarını çok güçlü biçimde engelliyor. Ama ufak değişikliklerde bile — yorum, dokümantasyon vb. — ilgili tüm alt bağımlılıklar yeniden build ediliyor. Sonuçta çok büyük yeniden derleme ihtiyacı doğuyor ve geliştirme acı verici hale gelebiliyor. Bunu
nixpkgsin staging sürecine bakınca görebilirsinizNix’in değerini gayet iyi anlıyorum. Yine de “mahvolursunuz” demenin biraz abartı olduğunu düşünüyorum. Nix’e kıyasla bazı büyük garantileri kaybediyorsunuz, doğru, ama buna rağmen çoğu yazılıma kıyasla hâlâ çok daha sorunsuz çalışma ihtimali yüksek
Kendi derivation’larını oluşturmadan neden ille de nixpkgs hash’ine bağımlı kaldıklarını anlayamıyorum
Pek çok yorumun havası şu: “Aslında Nix her şeyi çözer, tabii benim gibi uzman olmanız şart” ve bunu ilginç buldum
Diyelim ki bir şirket tüm teknoloji ve iş tarafını JavaScript ile yürütüyor ama mevcut temel kavramları — fonksiyonlar, diziler vb. — anlayamadığı için NIH kapsamında kendine ait yeni bir dil geliştiriyor; o zaman sorun daha çok şirketin iç yetersizliğiyle ilgili olurdu
Nix konuşulunca her zaman ortaya çıkan o tanıdık atmosfer işte
Bu tam olarak Nix’in havası. Bir yanda “dünyayı ben kurtaracağım” tarzı tipik anlatı, öte yanda “istediğim özellik çalışmıyor” diyenlere sürekli “sen doğru kullanmıyorsun” cevabı verilmesi