Fork me on My GIT

systemd-nspawn

~4 min read

systemd-nspawn, aber was ist das ?

Das Wochenende ist vorbei, aber das Thema noch nicht. Ich war am Wochenende zum zweiten Mal mit einem Workshop in einem Veranstaltungsprogramm vertreten. Dort habe ich jeweils kurz meine Nutzung der hier genannten Technologie dargestellt.

Doch ist es damit getan ?
Nein, denn nun will ich alles aufschreiben.

Also um was geht es eigentlich ?

Also fangen wir mal mit der ganzen Sache an.
Mir kamen ein paar Ideen, zu denen ich technologisch etwas benötigte, was ich nach der Nutzung wieder bereinigen kann. Dabei bin ich auf die Möglichkeiten von systemd-nspawn gestoßen, und habe diese verwendet. Doch was ist systemd-nspawn überhaupt?

Der Service "systemd-nspawn@.service" ist eigentlich auch nur ein systemd-Service, jedoch wird hier ein wenig systemd-run verwendet. Und zwar ist das ein wenig "CHRoot on Steroids" incl. CGroups und ein wenig Namespacing.
Kurzum, man könnte das ganze bspw. mit LXC vergleichen.

Wir nutzen hier ein paar systemd-Services und -Tools, um uns hier im lokalen Environment Container-Systeme starten und verwalten zu können. Doch was machen wir da genau? Und wie funktioniert das ganze ?

Und wie funktioniert es denn nun ?

Wie bereits angesprochen, verwenden wir hier verschiedene Services. Doch eines benötigen wir hier durchaus auch noch außerhalb von systemd.
Da wir betreffend Netzwerk portabel sein wollen, können wir keine direkte, externe Kommunikation einrichten. Somit benötigen wir eine Funktion, welche im physischen Netzwerken unsere Heimrouter übernehmen.

Also brauchen wir die Möglichkeit, Verbindungen weiterleiten zu können.

$ cat /proc/sys/net/ipv4/ip_forward
1

Des weiteren sollten natürlich die internen IPs nicht nach außen gelangen.

table inet filter {
    chain INPUT {
        type filter hook input priority filter; policy drop;
        iifname "mol0" tcp flags & (fin | syn | rst | ack) == syn ct state new jump tcp_internal
        iifname "mol0" meta l4proto udp ct state new jump udp_internal
    }

    chain FORWARD {
        type filter hook forward priority filter; policy drop;
        iifname "mol0" accept
        oifname "mol0" accept
    }

    chain tcp_internal {
        tcp dport 53 accept
        tcp dport 67 accept
        tcp dport 68 accept
    }

    chain udp_internal {
        udp dport 53 accept
        udp dport 67 accept
        udp dport 68 accept
    }
}

table inet nat {
    chain postrouting {
        type nat hook postrouting priority srcnat + 1; policy accept;
        iifname "mol0" masquerade
    }
}

Jetzt haben wir zumindest einmal die Basis für mögliche Kommunikationen gesetzt. Entsprechender Netzwerk-Verkehr ist jetzt möglich. Doch funktioniert das auch ?
Nicht wirklich, denn uns fehlt ja noch das Netzwerk selbst.

Jetzt kommen wir zum ersten Service aus dem Bereich "systemd". Der systemd-networkd, ein Netzwerkkonfigurationstool, welches uns hier, ähnlich wie im Server-Umfeld, einfache statische Netzwerkkonfigurationen ermöglicht.

 $ cat /etc/systemd/network/mol0.netdev
[NetDev]
Name=mol0
Kind=bridge
 $ cat /etc/systemd/network/mol0.network
[Match]
Name=mol0

[Network]
Address=172.21.42.254/24

Nachfolgend können wir den entsprechenden Service neu starten, um so zum einen das Netzwerkdevice herzustellen, als auch dessen Konfiguration zu laden. Jetzt würde auch unsere Firewall funktionieren, denn das referenzierte Interface ist vorhanden.

Und was machen wir mit DNS ?
Auch dazu gibt es etwas von "systemd". Hier nutze ich den systemd-resolved, welcher mir aus anderen Gründen bereits gute Dienste leistet.

 $ cat /etc/systemd/resolved.conf 
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it under the
#  terms of the GNU Lesser General Public License as published by the Free
#  Software Foundation; either version 2.1 of the License, or (at your option)
#  any later version.
#
# Entries in this file show the compile time defaults. Local configuration
# should be created by either modifying this file (or a copy of it placed in
# /etc/ if the original file is shipped in /usr/), or by creating "drop-ins" in
# the /etc/systemd/resolved.conf.d/ directory. The latter is generally
# recommended. Defaults can be restored by simply deleting the main
# configuration file and all drop-ins located in /etc/.
#
# Use 'systemd-analyze cat-config systemd/resolved.conf' to display the full config.
#
# See resolved.conf(5) for details.

[Resolve]
# Some examples of DNS servers which may be used for DNS= and FallbackDNS=:
# Cloudflare: 1.1.1.1#cloudflare-dns.com 1.0.0.1#cloudflare-dns.com 2606:4700:4700::1111#cloudflare-dns.com 2606:4700:4700::1001#cloudflare-dns.com
# Google:     8.8.8.8#dns.google 8.8.4.4#dns.google 2001:4860:4860::8888#dns.google 2001:4860:4860::8844#dns.google
# Quad9:      9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net 2620:fe::fe#dns.quad9.net 2620:fe::9#dns.quad9.net
#DNS=
#FallbackDNS=1.1.1.1#cloudflare-dns.com 9.9.9.9#dns.quad9.net 8.8.8.8#dns.google 2606:4700:4700::1111#cloudflare-dns.com 2620:fe::9#dns.quad9.net 2001:4860:4860::8888#dns.google
FallbackDNS=9.9.9.10 149.112.112.10 2620:fe::10 2620:fe::fe:10
#Domains=
#DNSSEC=no
#DNSOverTLS=no
#MulticastDNS=yes
#LLMNR=yes
#Cache=yes
#CacheFromLocalhost=no
#DNSStubListener=yes
DNSStubListenerExtra = 172.21.42.254
#ReadEtcHosts=yes
#ResolveUnicastSingleLabel=no
#StaleRetentionSec=0

Der Service wird einfach unser Resolver innerhalb des "internen Netzwerks".
Durch den zusätzlichen Listener-Eintrag können wir hier einfach den Container-Systemen einen DNS-Resolver auf ihrem Gateway konfigurieren. Die Systeme haben keine Probleme, und ggf. notwendige Anpassungen können zentral eingesteuert werden.

Und was machen wir jetzt betreffend der Container ?

Zuerst brauchen wir eine Systemkonfiguration, welche uns das entsprechende Environment definiert. Dazu gehört ein entsprechender Hostname, als auch eine Info, auf welchem Netzwerkdevice der Container mit der Außenwelt kommunizieren soll.

 $ cat /etc/systemd/nspawn/deb13.nspawn 

[Exec]
Hostname=deb13

[Network]
Bridge=mol0

Dann brauchen wir ja nur noch einen Container, bzw. ein Container-Image.

 $ machinectl show-image deb13
Name=deb13
Path=/var/lib/machines/deb13
Type=directory
ReadOnly=no
CreationTimestamp=Sat 2025-08-16 15:35:48 CEST
Usage=18446744073709551615
Limit=infinity
UsageExclusive=18446744073709551615
LimitExclusive=infinity

Doch wie bekommen wir sowas ?
Ich bevorzuge hier, solche Container selbst zu erstellen. Technologisch kann hier vieles verwendet werden, und je nach Distribution gibt es unterschiedliche Möglichkeiten.

Wir sind hier aktuell mit einem Debian-Container beschäftigt. Dieser kann unter Verwendung des Tools debootstrap erstellt werden. In meinem Fall wäre eine vollständige Commandline etwa so:

debootstrap --include=systremd-container,openssh-server,python3,python3-apt,dbus-broker,systemd-resolved --components=main,contrib,non-free-firmware trixie deb13 http://deb.debian.org/debian/

Ausgeführt würde dies hier bspw. in dem Pfad /var/lib/machines, und durch den Namen im vorherigen Befehl würde der notwendige Ordner im Prozes selbst erstellt.

Nachfolgend können wir dann einen Container starten, bzw. verwenden. Durch die Erstellung gewisser Symlinks werden die notwendigen Services vor dem Start noch für den automatischen Start konfiguriert. Dies beinhaltet folgendes innerhalb des Containers:

  • /etc/systemd/system/dbus-org.freedesktop.network1.service
  • /etc/systemd/system/multi-user.target.wants/systemd-networkd.service
  • /etc/systemd/system/sockets.target.wants/systemd-networkd.socket
  • /etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service
  • /etc/systemd/system/dbus-org.freedesktop.resolve1.service
  • /etc/systemd/system/multi-user.target.wants/systemd-resolved.service
  • /etc/systemd/system/multi-user.target.wants/sshd.service

Und natürlich benötigt auch der Container noch eine Netzwerkkonfiguration:

 $ sudo cat /var/lib/machines/deb13/etc/systemd/network/80-container-host0.network
[Match]
Name=host0

[Network]
Address=172.21.42.12/24
Gateway=172.21.42.254
DNS=172.21.42.254

Jetzt sind wir abschließend in der Lage, den Container zu starten, und zu verwenden. Der Spaß mit systemd-nspawn kann endlich beginnen.

links

social