Docker’ı herkes biliyor, Kubernetes’i herkes konuşuyor. Ama bazen ihtiyacınız olan şey birkaç MB’lık bir container runtime, bir sürü daemon ve karmaşık bir network stack değil. Bazen sadece izole bir ortam istiyorsunuz; test için, geliştirme için ya da güvenlik açısından hassas bir servisi ayırmak için. İşte tam bu noktada systemd-nspawn devreye giriyor ve çoğu Linux yöneticisinin farkında bile olmadığı bu araç, zaten sistemde kurulu geliyor.
systemd-nspawn, adından da anlaşılacağı üzere systemd ekosisteminin bir parçası. Temel olarak bir chroot’un çok daha güçlü hali diyebiliriz. Namespace izolasyonu, cgroup entegrasyonu ve systemd ile doğrudan entegrasyon sunuyor. Docker kadar kullanıcı dostu değil belki, ama sysadmin bakış açısından bakıldığında bu araç ciddi anlamda işe yarıyor.
systemd-nspawn Nedir ve Ne Zaman Kullanmalısınız?
systemd-nspawn bir “machine container” aracıdır. Yani tam bir işletim sistemi ağacını izole bir ortamda çalıştırmanızı sağlar. Bunu Docker’dan ayıran birkaç kritik nokta var:
- Kernel paylaşımı: Docker gibi host kernel’i kullanır, ama bunu çok daha minimal bir şekilde yapar
- systemd entegrasyonu: Konteynerlerinizi systemd servisi olarak yönetebilirsiniz
- machinectl desteği:
machinectlkomutu ile tüm makinelerinizi merkezi olarak yönetirsiniz - Daemon gereksizliği: Arka planda çalışan ekstra bir daemon yok, doğrudan kernel özelliklerini kullanır
Ne zaman tercih etmelisiniz? Şöyle düşünün: Bir web uygulamasını izole etmek istiyorsunuz ama Docker overhead’i istemiyorsunuz. Ya da eski bir uygulamanın farklı bir kütüphane versiyonuna ihtiyacı var. Ya da sadece hızlıca bir Debian ortamı kurup bir şey test etmek istiyorsunuz. Bu senaryoların hepsinde systemd-nspawn mükemmel bir seçenek.
Kurulum ve Ön Hazırlık
Çoğu modern Linux dağıtımında systemd-nspawn zaten kurulu gelir, çünkü systemd paketinin içinde yer alır. Kontrol edelim:
# systemd-nspawn kurulu mu kontrol et
which systemd-nspawn
systemd-nspawn --version
# Eğer kurulu değilse (Debian/Ubuntu)
sudo apt install systemd-container
# Fedora/RHEL için
sudo dnf install systemd-container
# Arch Linux için zaten mevcut
pacman -Q systemd
Konteyner dizinlerini tutacağımız yer genellikle /var/lib/machines/ olur. Bu dizin zaten systemd tarafından beklenen standart konumdur.
# Machines dizinini oluştur
sudo mkdir -p /var/lib/machines
# Dizin izinlerini kontrol et
ls -la /var/lib/
İlk Konteyner: Debian Tabanlı Ortam
En basit yoldan bir Debian konteyner oluşturalım. Bunun için debootstrap kullanacağız:
# debootstrap kurulumu
sudo apt install debootstrap # Debian/Ubuntu host için
# Debian Bookworm konteyner oluştur
sudo debootstrap --arch=amd64 bookworm /var/lib/machines/debian-test http://deb.debian.org/debian
# Bu işlem birkaç dakika sürecek, sabredin
# Tamamlandığında konteyner dizinine bakın
ls /var/lib/machines/debian-test/
Konteyner hazır olduğunda hemen başlatabilirsiniz:
# Interaktif shell ile başlat
sudo systemd-nspawn -D /var/lib/machines/debian-test
# Konteyner içinde artık Debian root'usunuz
# Çıkmak için Ctrl+] üç kez basın veya exit yazın
Bu kadar basit. Docker ile kıyasladığınızda image pull, container create, container run gibi adımlar yok. Direkt chroot gibi ama çok daha güvenli ve izole.
Ağ Yapılandırması
systemd-nspawn’un ağ konusunda birkaç farklı modu var. Bunu anlamak önemli çünkü yanlış seçim hem güvenlik hem de işlevsellik açısından sorun çıkarabilir.
Private Network Modu: Konteyner kendi network namespace’ine sahip olur.
# Private network ile başlat
sudo systemd-nspawn -D /var/lib/machines/debian-test --network-veth --network-bridge=br0
# Ya da daha basit: host ağını paylaş (test için)
sudo systemd-nspawn -D /var/lib/machines/debian-test --network-zone=myzone
Üretim ortamı için genellikle virtual ethernet pair kullanılır. Şöyle bir senaryo düşünelim: Web sunucunuzu izole etmek istiyorsunuz ama dışarıdan erişilebilir olmasını istiyorsunuz.
# Network bridge oluştur (bir kez yapılır)
sudo ip link add name br-containers type bridge
sudo ip link set br-containers up
sudo ip addr add 10.100.0.1/24 dev br-containers
# Konteyner başlat ve bridge'e bağla
sudo systemd-nspawn -D /var/lib/machines/webserver
--network-bridge=br-containers
--boot
# Konteyner içinden network yapılandırması
# ip addr show
# ip route add default via 10.100.0.1
machinectl ile Kalıcı Konteyner Yönetimi
Gerçek dünya kullanımında konteynerleri interaktif modda değil, arka planda servis olarak çalıştırmak istersiniz. İşte burada machinectl ve systemd entegrasyonu güzelleşiyor.
# Mevcut makineleri listele
machinectl list
# Makineyi başlat (--boot ile full init)
sudo machinectl start debian-test
# Makine durumunu kontrol et
machinectl status debian-test
# Makineye shell aç
machinectl shell debian-test
# Makineyi durdur
machinectl poweroff debian-test
# Boot'ta otomatik başlat
sudo machinectl enable debian-test
machinectl enable komutunu çalıştırdığınızda aslında /etc/systemd/system/machines.target.wants/ altına bir symlink oluşturulur. Bu sayede sistem her başladığında konteyneriniz otomatik olarak ayağa kalkar. Bunu bir kez görünce “işte bu” diyorsunuz.
Gerçek Dünya Senaryosu: İzole Web Sunucusu
Diyelim ki eski bir PHP uygulamanız var. PHP 7.4 gerektiriyor ama host sisteminizde PHP 8.2 kullanıyorsunuz. Klasik çözüm: ayrı bir VM. Ama VM overkill. İşte systemd-nspawn ile çözüm:
# Ubuntu 20.04 (PHP 7.4 içeren) konteyner kur
sudo debootstrap --arch=amd64 focal /var/lib/machines/legacy-php https://archive.ubuntu.com/ubuntu/
# Konteyner içine gir ve kurulumları yap
sudo systemd-nspawn -D /var/lib/machines/legacy-php --network-veth
# Konteyner içinde:
# apt update
# apt install -y php7.4 php7.4-fpm nginx
# systemctl enable php7.4-fpm nginx
# exit
Şimdi bunu kalıcı bir servis haline getirelim. /etc/systemd/nspawn/legacy-php.nspawn dosyası oluşturun:
sudo mkdir -p /etc/systemd/nspawn
sudo tee /etc/systemd/nspawn/legacy-php.nspawn << 'EOF'
[Exec]
Boot=yes
PrivateUsers=pick
[Files]
BindReadOnly=/etc/resolv.conf
[Network]
VirtualEthernet=yes
Bridge=br-containers
EOF
Bu konfigürasyon dosyası sayesinde konteynerin nasıl başlayacağını kalıcı olarak tanımlamış oldunuz. Artık:
# Servisi etkinleştir ve başlat
sudo machinectl enable legacy-php
sudo machinectl start legacy-php
# Durumu kontrol et
machinectl status legacy-php
Resource Limits: Cgroup Entegrasyonu
systemd-nspawn’un güzel yanlarından biri de cgroup entegrasyonu. Konteynerlerin ne kadar kaynak kullanabileceğini doğrudan systemd üzerinden kontrol edebiliyorsunuz.
# Konteyner servis dosyasını override et
sudo mkdir -p /etc/systemd/system/[email protected]/
sudo tee /etc/systemd/system/[email protected]/resources.conf << 'EOF'
[Service]
CPUQuota=50%
MemoryMax=512M
TasksMax=100
EOF
# Servisi yeniden yükle
sudo systemctl daemon-reload
sudo systemctl restart systemd-nspawn@legacy-php
Bu kadar! Konteynerin maksimum 512MB RAM ve toplam CPU’nun %50’sini kullanması garanti altına alındı. Docker’da bunu yaparken --memory ve --cpus flagleri kullanırsınız, burada ise doğrudan systemd unit dosyasıyla yapıyorsunuz; ki bu zaten bildiğiniz bir mekanizma.
Güvenlik: Capability Dropping ve Namespace İzolasyonu
Güvenlik konusuna gelince, systemd-nspawn oldukça kapsamlı seçenekler sunuyor. Üretim ortamında mutlaka dikkate alınması gereken ayarlar:
# Güvenlik odaklı .nspawn dosyası örneği
sudo tee /etc/systemd/nspawn/secure-app.nspawn << 'EOF'
[Exec]
Boot=yes
PrivateUsers=pick
Capability=CAP_NET_BIND_SERVICE
DropCapability=CAP_SYS_PTRACE
DropCapability=CAP_SYS_ADMIN
NoNewPrivileges=yes
[Files]
PrivateUsersOwnership=auto
ReadOnly=/usr
ReadOnly=/bin
ReadOnly=/lib
ReadOnly=/lib64
[Network]
VirtualEthernet=yes
Zone=isolated
EOF
Bu konfigürasyonda dikkat edilecek noktalar:
- PrivateUsers=pick: User namespace izolasyonu aktif, UID/GID’ler otomatik map’lenir
- DropCapability: Gereksiz Linux capability’leri kaldırıyoruz
- ReadOnly: Kritik sistem dizinleri read-only mount ediliyor
- NoNewPrivileges: Konteyner içinde privilege escalation engelleniyor
Bind Mount ile Veri Paylaşımı
Konteynerin dışındaki dizinleri içeriden erişilebilir yapmak sık yapılan bir işlem. Uygulama loglarını host üzerinde tutmak, ya da bir kaynak kodu dizinini konteyner içinde geliştirmek için kullanılır.
# Geliştirme senaryosu: kaynak kodu bind mount
sudo systemd-nspawn
-D /var/lib/machines/dev-environment
--bind=/home/user/projects/myapp:/opt/myapp
--bind=/var/log/myapp:/var/log/myapp
--boot
# .nspawn dosyasında kalıcı bind mount tanımı
sudo tee /etc/systemd/nspawn/dev-environment.nspawn << 'EOF'
[Exec]
Boot=yes
[Files]
Bind=/home/user/projects/myapp:/opt/myapp
Bind=/var/log/myapp:/var/log/myapp
BindReadOnly=/etc/localtime
BindReadOnly=/etc/resolv.conf
EOF
Bir dikkat noktası: /etc/resolv.conf bind mount etmek DNS çözümlemesi için neredeyse zorunlu. Özellikle Ubuntu/Debian konteynerlerde bunu atlarsanız apt güncelleme yapamaz, paket indiremez gibi sorunlarla karşılaşırsınız.
Anlık Snapshot ve Yedekleme
systemd-nspawn, btrfs dosya sistemiyle birlikte kullanıldığında snapshot almak son derece kolay hale gelir. Bu özelliği bilmeden geçmek olmaz.
# /var/lib/machines btrfs subvolume üzerindeyse
# snapshot almak çok basit
sudo machinectl clone debian-test debian-test-backup-$(date +%Y%m%d)
# Klonlanan makineyi listele
machinectl list-images
# Belirli bir makineyi kaldır
machinectl remove debian-test-backup-20240115
# Image bilgilerini gör
machinectl image-status debian-test
Btrfs kullanmıyorsanız bile basit bir tar arşivi yeterli:
# Konteyner yedekle
sudo machinectl poweroff debian-test
sudo tar -czf /backup/debian-test-$(date +%Y%m%d).tar.gz -C /var/lib/machines debian-test
# Geri yükle
sudo tar -xzf /backup/debian-test-20240115.tar.gz -C /var/lib/machines/
sudo machinectl start debian-test
Logging ve Monitoring
systemd entegrasyonunun en büyük avantajlarından biri merkezi log yönetimi. Konteyner içindeki tüm loglar journal’a düşer ve host üzerinden erişilebilir.
# Belirli bir makinenin loglarını görüntüle
journalctl -M debian-test
# Canlı log takibi
journalctl -M debian-test -f
# Sadece hata logları
journalctl -M debian-test -p err
# Son 100 satır
journalctl -M debian-test -n 100
# Belirli bir servise ait log (konteyner içindeki nginx)
journalctl -M webserver -u nginx
Bu journalctl -M özelliği gerçekten değerli. Ayrı log dosyalarını kurcalamak yerine tek bir noktadan tüm konteynerlerinizin loglarına bakabiliyorsunuz. Üstelik zaman filtresi, priority filtresi gibi tüm journalctl özelliklerini kullanabiliyorsunuz.
Sorun Giderme: Yaygın Hatalar ve Çözümleri
Kaçınılmaz olarak bir noktada sorunlarla karşılaşacaksınız. En sık karşılaşılanları ve çözümlerini paylaşayım:
Selinux/AppArmor Engellemeleri:
# Hata görüntüleniyorsa audit loglarına bak
sudo ausearch -m avc -ts recent
# Geçici test için (üretimde yapma!)
sudo setenforce 0
# Kalıcı çözüm için proper policy yaz veya
# konteyner için selinux label'ı güncelle
sudo chcon -R system_u:object_r:svirt_sandbox_file_t:s0 /var/lib/machines/mycontainer
Konteyner boot’ta takılı kalıyor:
# Detaylı boot logu için
sudo systemd-nspawn -D /var/lib/machines/mycontainer --boot --show-status=yes
# Konteyner içinde systemd'nin neyi beklediğini kontrol et
# Genellikle eksik getty veya broken unit file sorunu olur
sudo systemd-nspawn -D /var/lib/machines/mycontainer /bin/bash
# İçeriden: systemctl list-units --failed
Ağ sorunları:
# Host tarafındaki network interface'leri listele
networkctl list
# Konteyner içindeki interface'leri gör
machinectl shell mycontainer -- networkctl list
# NAT masquerade aktifleştir (internet erişimi için)
sudo iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -j MASQUERADE
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Performans Karşılaştırması: Ne Kadar Hafif?
“Hafif konteyner” diyoruz, gerçekten ne kadar hafif? Birkaç rakam verelim. Minimal bir Debian systemd-nspawn konteynerinin memory footprint’i genellikle 20-40MB civarındadır. Aynı şeyi Docker ile yapsaydınız Docker daemon, containerd, runc ve diğer bileşenler eklenince başlangıç maliyeti çok daha yüksek olurdu.
# Konteyner memory kullanımını gör
systemd-cgls /machine.slice/
# Detaylı resource kullanımı
systemd-cgtop
# Belirli bir makinenin resource kullanımı
machinectl status mycontainer | grep -E "Memory|CPU|Tasks"
Özellikle edge sistemlerde, gömülü Linux’ta ya da VM içinde container çalıştırmanız gerektiğinde bu fark ciddi anlam ifade ediyor.
Gelişmiş Senaryo: CI/CD Pipeline için Temiz Build Ortamı
Son olarak pratik bir senaryo daha paylaşayım. CI/CD süreçlerinde her build’in temiz bir ortamda gerçekleşmesini istiyorsunuz. systemd-nspawn ile bu oldukça verimli bir şekilde yapılabilir:
#!/bin/bash
# build-in-container.sh
APP_NAME=$1
BUILD_DIR=/tmp/build-$APP_NAME-$$
# Template konteynerden klon al (btrfs snapshot, çok hızlı)
sudo machinectl clone build-template $BUILD_DIR
# Kaynak kodu bağla
sudo systemd-nspawn
-D /var/lib/machines/$BUILD_DIR
--bind=$(pwd):/workspace
--bind=/var/cache/build-cache:/root/.cache
--as-pid2
-- /bin/bash -c "cd /workspace && ./build.sh"
BUILD_RESULT=$?
# Temizle
sudo machinectl remove $BUILD_DIR
exit $BUILD_RESULT
Bu yaklaşımda her build kendi izole ortamında çalışıyor, bırakın bitti mi gitti. Template konteynerini btrfs snapshot ile klonladığınız için bu işlem saniyeler içinde tamamlanıyor.
Sonuç
systemd-nspawn, modern Linux sistemlerin zaten içinde barındırdığı ama çoğu zaman göz ardı edilen güçlü bir araç. Docker’ın getirdiği kompleksitenin gerekmediği durumlarda, özellikle izolasyon ihtiyacının birinci planda olduğu sysadmin senaryolarında bu araç gerçekten parlıyor.
Şu ana kadar anlattıklarımı özetlersek:
- Kurulum sıfır: Zaten sistemde var, ek daemon gerektirmiyor
- systemd entegrasyonu: journalctl, systemctl, cgroup yönetimi hepsi doğal
- Resource control: CPU, memory limitleri systemd unit dosyası üzerinden
- Güvenlik: Capability dropping, namespace izolasyonu, read-only mount desteği
- Operasyonel kolaylık: machinectl ile merkezi yönetim
Tabii ki Docker ve Kubernetes’in yerini tutmuyor. Büyük ölçekli dağıtık sistemler, container orchestration, microservice mimarileri için hala doğru araçlar onlar. Ama bir servisi izole etmek, eski bir uygulamayı çalıştırmak, temiz build ortamı oluşturmak gibi senaryolar için systemd-nspawn’u araç çantanıza eklemenizi kesinlikle tavsiye ederim.
En iyi araç, işin gerektirdiği araçtır. Bazen bu Docker, bazen Kubernetes, bazen de zaten kurulu olan systemd-nspawn’dur.