Nitro: küçük ve esnek bir init sistemi ile süreç süpervizörü
(git.vuxu.org)- Nitro, gömülü sistemler, sunucular, masaüstü sistemler ve konteynerlerde kullanılabilen çok küçük bir süreç süpervizörü ve init sistemidir
- Sistem durumunu yalnızca RAM'de saklar; bu sayede salt okunur dosya sistemlerinde de sorunsuz çalışır ve hızlı, verimli bir olay tabanlı tasarım sunar
- Yapılandırma yöntemi basit bir betik dizini yapısıdır; karmaşık yapılandırma dosyaları veya ek derleme süreçleri olmadan servis yönetimi sağlar
- Parametreli servisler, sağlam yeniden başlatma, her servis için güvenilir günlükleme gibi konteyner ve gömülü ortamlara optimize edilmiş özellikler sunar
- nitroctl aracıyla uzaktan kontrol, sinyal tabanlı davranış kontrolü gibi yüksek esneklik ve denetim sağlar
Genel bakış
Nitro, Linux'ta pid 1 olarak da kullanılabilen çok küçük bir süreç süpervizörüdür
Başlıca kullanım alanları şunlardır
- gömülü, masaüstü, sunucu gibi farklı amaçlı Linux makineleri için init
- Linux initramfs'in init'i
- Docker/Podman/LXC/Kubernetes gibi konteyner ortamlarının init'i
- POSIX sistemlerde yetki gerektirmeden çalışan bir süpervizyon daemon'u
Yapılandırma, dizin tabanlı bir betik yapısı kullanır ve varsayılan konum /etc/nitro'dur
Gereksinimler
- çekirdeğin Unix socket desteği gerekli
tmpfsveya yazılabilir bir/rundizini gerekli
Diğer sistemlere göre avantajları
- tüm durum bilgileri yalnızca RAM'de tutulur; bu yüzden salt okunur kök dosya sistemlerinde ek hilelere gerek kalmadan çalışır
- olay tabanlı, polling yapmayan çalışma biçimi ile verimlilik sağlar
- çalışma sırasında dinamik bellek tahsisi yoktur
- dosya tanımlayıcıları sınırsız biçimde tüketilmez
- yalnızca tek bir self-contained ikili dosya gerekir (isteğe bağlı olarak ek bir kontrol ikilisiyle)
- yapılandırma dosyası dönüştürme ve derleme gerekmez; servisler sadece betik içeren basit dizinlerdir
- servis yeniden başlatma ve günlükleme zinciri desteği sunar
- sistem saati doğru olmasa bile düzgün çalışır
- FreeBSD'de
/etc/ttysüzerinden çalıştırılabilir - musl libc ile çok küçük bir statik ikili üretilebilir
Servis yönetimi
-
her servis dizini (varsayılan olarak
/etc/nitroaltında) şu dosyaları içerebilirsetup: servis başlamadan önce çalıştırılan isteğe bağlı betik; servis yalnızca normal çıkışta (0) başlatılırrun: servis çalışma betiği; sonlanmadığı sürece servis ayakta kabul edilir, yoksa one-shot servis olarak işlenirfinish:runsona erdikten sonra çalışan isteğe bağlı betik; çıkış durumu ve sinyal değeri argüman olarak verilirlog: başka bir servis dizinine işaret eden sembolik bağ;runçıktısı o servisin girdisine pipe edilir (günlükleme zinciri için kullanılabilir)down: bu dosya varsa nitro bu servisi varsayılan olarak ayağa kaldırmaz- dizin adı
@ile bitiyorsa yok sayılır ve parametreli servis olarak kullanılabilir - servis adı 64 karakterden kısa olmalı ve
/,,, satır sonu karakteri içeremez
-
runit'in
chpstyardımcı aracı,runbetikleri yazarken kullanışlıdır
Özel servisler
LOG:logbağlantısı olmayan tüm servislerin günlükleri için varsayılan servisSYS:SYS/setup, tüm servisler başlamadan önce çalışır; sıralı servis başlatma uygulanabilirSYS/finish: genel kapanış aşamasına girilmeden önce çalışırSYS/final: tüm süreçler sonlandıktan sonra çalışırSYS/fatal: ölümcül hata oluşursa çıkış yerine çalışır (varsa)SYS/reincarnate: shutdown yerine çalışır; örneğin initramfs'in yeniden uygulanması için kullanılabilir
Parametreli servisler
@ile biten servis dizinleri nitro tarafından yok sayılır, ancak sembolik bağ veyanitroctlkomutuyla doğrudan belirtilebilir@sonrasındaki parametre, her betiğe ilk argüman olarak aktarılır- örnek:
agetty@/runveagetty@tty1sembolik bağı varsaagetty@/run tty1çalıştırılır nitroctl up agetty@tty2girildiğindeagetty@/run tty2çalıştırılabilir (dizinin var olup olmaması önemli değildir)
- örnek:
Çalışma modları
- tüm yaşam döngüsü önyükleme, servis çalıştırma (süpervizyon), kapanış olmak üzere üç aşamadan oluşur
- önyükleme: özel servis
SYSvarsasetupile başlar, ardındandownolmayan tüm servisler başlatılır - bir servis sonlanırsa yeniden başlatılır; ancak son yeniden başlatma çok yeniyse 2 saniye beklenir
nitroctl RebootveyaShutdownile kapanış sinyali gönderilebilir- bu durumda
SYS/finish→ tüm servislere SIGTERM (en fazla 7 saniye beklenir) → SIGKILL →SYS/final→ kapanış sırası uygulanır
- bu durumda
- konteyner veya yetkisiz süpervizör kullanımında yalnızca süreçler sonlandırılır
- önyükleme: özel servis
nitroctl ile kontrol
- nitroctl CLI aracıyla nitro uzaktan kontrol edilebilir
Komut örnekleri:
- list: servis listesi, durum, PID, uptime, son çıkış durumu çıktılanır
- up/down/start/stop/restart: servis başlatma, durdurma, yeniden başlatma gibi işlemler
- sinyal gönderme: p(SIGSTOP), c(SIGCONT), h(SIGHUP), a(SIGALRM), i(SIGINT), q(SIGQUIT), 1(SIGUSR1), 2(SIGUSR2), t(SIGTERM), k(SIGKILL)
- pidof: belirtilen servisin PID'sini çıktılar
- rescan: servis dizinlerini yeniden okur, eklenen/kaldırılan servisleri yansıtır
- Shutdown/Reboot: tüm sistemi kapatma veya yeniden başlatma
Sinyallerle kontrol
- nitro sürecine doğrudan sinyal göndererek kontrol sağlanabilir
- SIGHUP: servisleri yeniden tara (
rescan) - SIGINT: yeniden başlat
- SIGTERM: kapat (nitro pid 1 değilse)
- SIGHUP: servisleri yeniden tara (
Linux'ta init olarak nitro
- Nitro, self-contained bir ikili olarak Linux'ta doğrudan pid 1 şeklinde önyüklenebilir
- gerekirse
/devve/runbağlanır; diğer işlemlerSYS/setupiçinde yapılır - Ctrl-Alt-Del olayı, düzenli bir yeniden başlatma sürecini tetikler
Docker konteynerinde init olarak Nitro kullanımı
- Nitro statik olarak derlenebilir ve konteynere kolayca eklenebilir
- varsayılan socket yolunun kullanılabilmesi için konteynerde
/runbulunmalıdır - kontrol socket'i bind mount edilirse dışarıdan
nitroctlile uzaktan kontrol sağlanabilir
FreeBSD'de Nitro
- FreeBSD init'in nitro'yu süpervize etmesi için
/etc/ttysdosyasına aşağıdaki satır eklenebilir/etc/nitro "/usr/local/sbin/nitro" "" on
Yazar
- Leah Neukirchen leah@vuxu.org
Teşekkürler
- daemontools, freedt, runit, perp, s6 gibi mevcut süreç süpervizyon sistemlerinin ayrıntılı analizi temel alınarak geliştirilmiştir
Lisans
- 0BSD lisansı (ayrıntılar için LICENSE dosyasına bakın)
1 yorum
Hacker News görüşleri
runit ile bir karşılaştırma görmek isterdim. runit son derece minimal ama neredeyse tam bir init sistemi. Kontrol dizini, bildirimsel olmayan bağımlılıklar, benzer betik yapısı, loglama yaklaşımı gibi pek çok benzerlik var. Açıklama sayfasında da runit’ten kısaca bahsediliyor ve chpst aracının birlikte kullanılması öneriliyor. Fark yaratan taraf olarak, tek bir servis diziniyle birden çok benzer süreci (ör. agetty) parametreleştirerek yönetme yapısını iyi buluyorum. reboot veya shutdown doğrudan tek bir ikili dosya (
nitroctl) ile çalıştırılabiliyor. Buna karşılık runit birden fazla ikili dosyadan oluşan bir yapıya sahipGeçen yıl süreçleri runit ile yöneten son sunucuları da emekliye ayırırken içimde bir burukluk vardı. Yaklaşık 15 yıl önce ilk kez kendi runit servislerimi yazdığımda bunun Linux’ta servis yönetmenin standart yolu olduğuna inanmıştım. Sonra 5 yıl Linux’tan uzak kaldım; geri döndüğümde systemd varsayılan haline gelmişti. Hakkında pek çok kötü yorum duymuştum ama zamanla bunların çoğunun çarpıtılmış bir antipati olduğunu fark ettim. Şu anda bir sürüngen vivarium’unda Pi Zero üzerinde kamera ve sıcaklık verisi akışı servisleri çalıştırıyorum ve systemd ile kurulum yapmak son derece kolaydı. OpenSuse masaüstümde ve iş dizüstü bilgisayarımda da systemd ile çeşitli servisleri rahatça çalıştırabildim. “Bir standardın olması aslında iyi bir şey” diye düşünüyorum
runit ve nitro arasında uygun, minimal bir karşılaştırma 2024’te yayımlanan Leah Neukirchen sunum slaytlarında (PDF) var
https://leahneukirchen.org/talks/#nitroyetanotherinitsy
Leah Neukirchen, Void Linux topluluğunda aktif biri. Bu projenin Void ile yakından bağlantılı olacağını tahmin ediyorum. Void üzerinde nitro’nun nasıl kullanılacağına dair daha resmi bir yazı yazılsa güzel olurdu
“Bildirimsel bağımlılıkların olmaması” gerçekten bir avantaj mı, merak ediyorum. systemd’nin init olarak eleştirildiğini çok duydum ama bildirimsel tasarımın kendisinin eleştirildiğini pek görmedim. Bunun nedenini daha ayrıntılı duymak isterim
Void Linux sayesinde runit ile tanıştım ve init sistemi olarak memnuniyetle kullanıyorum ama arayüz ve dokümantasyon eksikliği can sıkıcıydı. Özellikle loglama yapılandırması gerçekten zordu. Benzer derecede basit ama daha makul varsayılanlara, daha sezgisel bir arayüze ve daha iyi belgelere sahip bir alternatif denemek isterim
Konteyner içinde init sistemi çalıştırma fikri her gündeme geldiğinde hep ikilemde kalıyorum. Bazen gerçek bir ihtiyaçtan doğuyor ama çoğu zaman işleri gereğinden fazla karmaşıklaştırdığını da gördüm (özellikle Kubernetes ve bulut ortamlarında, aslında ayrıştırma tasarımı daha düzgün yapılmalıydı). “Nasıl olsa herkes böyle yapıyor” durumu var gibi geliyor; o yüzden “daha iyi yapalım” derken sorunun yayılmasına katkı mı sağlanıyor, yoksa insanların mevcut çözümlerle sert biçimde duvara toslamasına izin vermek mi daha doğru, emin olamıyorum
Uygulama konteynerlerinin Unix felsefesindeki “tek bir işi iyi yap” ilkesini izlemesi gerektiğini düşünüyorum. Ama konteyner içinde herhangi bir nedenle
forkyapılacaksa, PID 1’de gerçek bir init olması gerektiği görüşündeyimRobotik alanındaki deneyimime göre, birçok konteyner aslında başlangıçta çıplak metal üzerinde çalışan karmaşık sistemlerin konteynere taşınmış hali. Süreçler arasında çok sayıda yapılandırılmamış RPC bulunduğundan, bunları bir sürü ayrı konteynere bölmenin büyük bir faydası yok. Monolitik uygulama konteynerinin içinde birden fazla süreci çalıştırmak için supervisor, runit, systemd, hatta tmux gibi her tür seçenek kullanılıyor
Fly.io, Render ve Google Cloud Run gibi konteyner başına ücretlendiren hosting hizmetlerini kullandım. Fiyat nedeniyle bazen tek bir konteynerde birden fazla süreç çalıştırmak gerekiyor
NixOS’un yeni özelliği olan modular-services artık Nixpkgs’e dahil edildi. Bu sayede NixOS’u yeni bir init sistemine ya da yeni bir çekirdeğe taşımak çok daha kolay olacak; bence nitro gibi deneyler için tam zamanı
Chimera Linux’ta kullanılan dinit ile nitro’yu karşılaştırmak isterdim. README’ye hızlıca göz atınca servis bağımlılığı yönetiminin henüz olmadığını düşündüm
dinit: https://github.com/davmac314/dinit
Nitro, servis bağımlılıklarını bildirimsel olarak ele almıyor. Tek bir komutla servisler arası bağımlılık grafiğini güzelce görmek mümkün değil. Ama setup betiğinde gerekli servisleri belirtirseniz, o servislerin ayakta olup olmadığını kontrol ediyor ve gerekirse otomatik bekleyip yeniden deniyor. Bağımlılık grafiğini görmek için
grepgibi araçlarla kendi betiğinizi yazmanız gerekiyor. Öte yandan bir servis öldüğünde ona bağlı servisleri de zincirleme biçimde düzgün kapatmayı unutmak kolay; nitro’nun kendi içinde bunu tespit etmeye yarayan pratik bir yöntem yokArtix Linux’ta dinit kullanmıştım; gerçekten hafif ve etkileyiciydi
Artix FAQ: https://artixlinux.org/faq.php
Bu tür düşük seviye projeleri görmek gerçekten ilgi çekici. systemd’nin geleneksel SysV·POSIX çerçevesini aşıp Linux çekirdeğine özgü özellikleri iyi kullanmasını beğenmiştim. Ama umarım hikâye burada bitmez; yeni fikirler ve yenilikler gelmeye devam eder. Kısa süre önce üretim otomasyonu için, UEFI aygıt yazılımından doğrudan netboot edilen bir Linux çekirdeğine Go ile kendim yazdığım tek bir init ikili dosyasını gömdüğüm bir kurulum yaptım. Kendi aldığınız kod ve yüksek seviyeli bir dille tüm işletim sistemi ortamını kontrol etmek, türlü alt süreçleri ve sayısız metin yapılandırma dosyasını yönetme ihtiyacını ortadan kaldırdığı için gerçekten özgürleştiriciydi
Yaklaşık 13 yıl önce C ile kendi init sistemimi kurmuştum. Beklediğimden çok daha fazla emek gerektirdi ve GUI ile backend’i düşük performanslı donanımda hızlı başlatmak için kullanıldı. Eğlenceli bir programlama alıştırmasıydı ama sonradan, belki de buna benzer çözümler zaten vardı diye düşündüm. Aynı şirkette bir iş arkadaşım da başka bir init yazmıştı; bu yüzden benim ilk sürümüm neredeyse yalnızca libc dışında bağımlılığı olmayan hafif bir şeyken, onun sürümü libevent tabanlıydı ve daha gelişmiş özellikler içeriyordu
AWS Nitro ile isim ve işlev çakışması olması biraz rahatsız ediyor
https://docs.aws.amazon.com/whitepapers/latest/security-design-of-aws-nitro-system/the-nitro-system-journey.html
Sadece isim çakışıyor; init sistemi ile hipervizör temelden tamamen farklı şeyler
Bunun sorun çıkaracağını pek sanmıyorum. Biri herkesin kullanabildiği bir init sistemi, AWS Nitro ise şirket içinde kullanılan bir KVM çatalı
nitro’nun s6 ile karşılaştırıldığında nasıl olduğunu merak ediyorum. Yakın zamanda Docker konteynerinde s6 ile bir init sistemi kurmayı denedim ama s6-overlay ile elle çok sayıda dosya oluşturmak gerekti ve düşündüğüm kadar sezgisel değildi
tini’ye de bakılabilir: https://github.com/krallin/tini
Distrust’te Rust ile 500 satırın altında son derece basit bir init sistemi yazdık; bazı müşteriler bunu güvenliğin zorunlu olduğu enclave ortamlarında üretimde kullanıyor. Yalnızca Rust standart kütüphanesini kullandığımız için denetimi çok kolay oldu
https://git.distrust.co/public/nit
Bağımlılık belirtme yok, kullanıcı/grup ayarı yok, sırayı elle vermek gerekiyor, paralel servis başlatma yok, kaynak yönetimi yok. Böyle eksik bir şeye init sistemi denmemesi gerektiğini düşünüyorum. Bu sadece çıplak bir süreç denetleyicisi