Container mit Bordmitteln - systemd-nspawn
1 Diese Webseite …
… befindet sich unter https://notes.defaultroutes.de
2 Namespaces
- Dieses Kapitel zeigt, das Namespaces (und damit Container) eine
Standard-Technologie des Linux-Kernel sind und keiner weiteren
speziellen Software benötigt.
systemd-nspawn
, Podman, LXC/LXD und auch Docker sind nur Verwaltungsprogramme für die Namespaces und Controll-Groups des Linux-Kernels.- Dies ist ein Unterschied zu Virtuelisierungs-Lösungen wie QEMU, VirtualBox, VMWare, Xen etc. Bei diesen gibt es technische Unterschiede in der Implementation der Virtualisierung, welche sich auf den Speicherverbrauch und der Performance dieser Lösungen auswirkt.
- Bei Containers (Namespaces) gibt es diese Unterschiede nicht, es wird immer die gleiche Namespace-Funktion des Linux-Kernels benutzt
- Namepspaces 'virtualisieren' die Sicht auf Ressourcen des Linux-Kernels
- Programme wie Docker, Podman, Chrome, systemd-nspawn, LXC/LXD, Firejail etc. benutzen die Namespaces im Linux-Kernel
- Verfügbare Namespaces in Linux
Namespace | Konstante | Isolation |
---|---|---|
Cgroup | CLONE_NEWCGROUP | Cgroup root Verzeichnis (Ressourcen wie CPU/RAM) |
IPC | CLONE_NEWIPC | System V IPC, POSIX message queues |
Network | CLONE_NEWNET | Network devices, stacks, ports, Firewall etc. |
Mount | CLONE_NEWNS | Mount points (Dateisysteme) |
PID | CLONE_NEWPID | Process IDs |
User | CLONE_NEWUSER | Benutzer und Gruppen IDs |
UTS | CLONE_NEWUTS | Hostname und NIS Domain Name |
2.1 Namespace Beispielprogramm
- mit diesem kleinen Beispielprogramm wird gezeigt, das Linux-Container mit nur einem Systemaufruf erzeugt werden.
- Quelle: https://blog.lizzie.io/linux-containers-in-500-loc.html
- C-Compiler und Entwicklungs-Tools installieren
apt install build-essential
- Unser Ausgangs-C-Programm: Leeres Verzeichnis anlegen und die leere Quelltextdatei im Editor öffnen
cd /usr/src mkdir namespaces cd namespaces nano namespaces.c
- Inhalt des C-Programms
#define _GNU_SOURCE #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <sched.h> #include <signal.h> #include <unistd.h> #define STACK_SIZE (1024 * 1024) static char child_stack[STACK_SIZE]; char* const child_args[] = { "/bin/bash", NULL }; int child_main(void* arg) { printf("Namespace aktiv\n"); execv(child_args[0], child_args); printf("Ooops\n"); return 1; } int main() { printf("Namespace wird erzeugt\n"); int child_pid = clone(child_main, child_stack+STACK_SIZE, \ CLONE_NEWUTS | CLONE_NEWIPC | SIGCHLD, NULL); waitpid(child_pid, NULL, 0); printf("Namespace beendet\n"); return 0; }
- Programm übersetzen
gcc -o namespaces namespaces.c
- Programm ausführen
./namespaces
- Den Namespace mit
exit
verlassen, dann einen Process-Namespace zum Programm hinzufügen
... int child_pid = clone(child_main, child_stack+STACK_SIZE, \ CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | SIGCHLD, NULL); ...
- Neu übersetzen und ausführen (im Namespace das Proc-Dateisystem neu
mounten um die Prozess-Isolierung via
top
oderps
zu sehen:mount -t proc proc /proc
)
gcc -o namespaces namespaces.c
- Namespace via
exit
beenden und dasproc
Dateisystem auf dem Host neu mountenmount -t proc proc /proc
- Einen Netzwerk-Namespace hinzufügen
... int child_pid = clone(child_main, child_stack+STACK_SIZE, \ CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNET | SIGCHLD, NULL); ...
- Die Netzwerkconfiguration im Namespace mit
ip
oderifconfig
anschauen
3 Container/Namespace mit Systemd
- Jedes Linux mit Systemd bringt mächtige Container-Verwaltungs-Werkzeuge mit
systemd-nspawn
arbeitet neben Image-Dateien für Container auch mit installieren Linux-Root-Dateien in einem beliebigen Verzeichnis auf dem Container-Host-System- Damit ist es sehr einfach, ein Container-System aufzusetzen und Dateien zwischen dem Container-Host und dem Linux im Container auszutauschen
3.1 Container Linux manuell installieren
- In diesem Kapitel installieren wir als Beispiel ein Rocky-Linux
(eine freie Red Hat Enterprise Linux Distribution) in einem
Verzeichnis unter Debian
- Andere Linux-Distributionen wie Ubuntu, Suse, Arch-Linux oder ältere Debian-Versionen wären auch möglich
- Wichig ist das die Dateien im Container-Verzeichnis für die CPU-Architektur des Container-Hosts übersetzt wurden und die Programme keinen neueren Kernel benötigen (keine neuen System-Calls)
- Seit Debian 9 müssen die Systemd-Container-Tools separat installiert werden:
apt install systemd-container
- Wir erstellen ein Verzeichnis für den neuen Container
mkdir -p /srv/container/rocky-linux8
- Initialisieren eine neue RPM-Instanz im Container-Verzeichnis (bei Debian mit debboostrap, bei SUSE mit RPM und zypper)
apt -y install rpm dnf rpm --root /srv/container/rocky-linux8 --initdb
- Das Basis-Paket für Rocky-Linux laden
wget https://ftp.plusline.net/rockylinux/8/BaseOS/x86_64/os/Packages/r/rocky-release-8.8-1.8.el8.noarch.rpm wget https://ftp.plusline.net/rockylinux/8/BaseOS/x86_64/os/Packages/r/rocky-repos-8.8-1.8.el8.noarch.rpm rpm --nodeps --root /srv/container/rocky-linux8 -ivh rocky-release-8.8-1.8.el8.noarch.rpm rocky-repos-8.8-1.8.el8.noarch.rpm
- Das Rocky-Linux Basis-System installieren
dnf -y --nogpg --releasever=8 --installroot=/srv/container/rocky-linux8 \ install systemd passwd dnf procps-ng iproute tmux dhcp-client rocky-gpg-keys echo 8 > /srv/container/rocky-linux8/etc/dnf/vars/releasever
- Eine Shell im Container starten
systemd-nspawn -D /srv/container/rocky-linux8
- Root-Passwort setzen und neuen Benutzer anlegen
-bash-4.2$ passwd -bash-4.2$ adduser nutzerXX -bash-4.2$ passwd nutzerXX
- Shell im Container verlassen
-bash-4.2# exit
- Container booten
systemd-nspawn -bD /srv/container/rocky-linux8
- Weitere Software im Container installieren (hier den Apache Webserver)
dnf install httpd
- Anwendung im Rocky Linux Container starten (prüfen das kein andere Prozess auf dem Container-Host die Ports 80 und/oder 443 belegt)
systemctl enable --now httpd
- Der Apache Webserver innerhalb des Rocky Linux Containers sollte nun vom Firefox des Debian unter http://localhost erreichbar sein.
- Container stoppen (im Container eingeben)
conainter# poweroff
- Container mit privatem Netzwerk-Namespace starten:
systemd-nspawn -bD /srv/container/rocky-linux8 --private-network
Container mit eigener (virtuellen) Netzwerkkarte (neue
MAC-Adresse). enp1s0f1
ist der Name der physischen
Netzwerkschnittstelle des Container-Hosts.
systemd-nspawn --network-macvlan=enp1s0f1 -M rocky01 \ -bD /srv/container/rocky-linux8 container# ip links container# dhclient mv-enp1s0f1 container# ip address show container# ping 1.1.1.1
- Systemd-Befehle um einen Container vom Host aus zu kontrollieren
machinectl list machinectl status rocky-linux8 machinectl poweroff rocky-linux8 machinectl terminate rocky-linux8 machinectl kill rocky-linux8
- Per nsenter mit dem Container verbinden (es wird eine Prozess-ID eines Container-Prozesses benötigt!)
nsenter -m -u -i -n -p -t <pid-im-container> /bin/bash
3.2 Container aus dem NSpawn-Image-Hub laden und starten
- Unter
https://hub.nspawn.org
können fertige Systemd-NSpawn Container-Images geladen werden. Eigene NSpawn-Container-Repositories können mittels beliebiger HTTP-Server erstellt werden. Die Systemd-Container-Images werden mittels GNU-Privacy-Guard nach dem Download geprüft- Die Images sind mit dem GPG Schlüssel des NSpawn-Projektes
signiert. Damit der Befehl
machinectl
die Images nach dem Download verifizieren kann, muss der öffentliche Schlüssel des Projektes in einen eigenen GPG-Schlüsselring importiert werden - Schlüsselring anlegen:
- Die Images sind mit dem GPG Schlüssel des NSpawn-Projektes
signiert. Damit der Befehl
sudo gpg --no-default-keyring \ --keyring=/etc/systemd/import-pubring.gpg \ --fingerprint
- Schlüssel laden und importieren:
sudo gpg --no-default-keyring \ --keyserver=keys.openpgp.org \ --keyring=/etc/systemd/import-pubring.gpg \ --search 9E31BD4963FC2D19815FA7180E2A1E4B25A425F6
- Container-Image laden (hier ein Arch-Linux)
machinectl pull-tar https://hub.nspawn.org/storage/archlinux/archlinux/tar/image.tar.gz ArchLinux
- NSpawn-Container-Images können in zwei Formaten bereitgestellt werden:
- TAR: ein Tape-Archiv mit den Inhalten eines Linux-Root-Dateisystems
- RAW: Ein Storage-Abbild einer Linux-Installation (Format
QCOW2
wie von QEMU und anderen Virtualisierungs-Lösungen benutzt, oder ein perdd
erstelltes Abbild eines Dateisystems
- Docker-Images können mittels des
docker
oderpodman
Befehls in ein Verzeichnis mit einem Linux-Root-Dateisystems exportiert werden - Auflisten der verfügbaren Images:
machinectl list-images
- Starten eines Systemd-nspawn Containers mittels
machinectl
machinectl start ArchLinux
- Status eines Systemd-NSpawn Container abfragen
machinectl status ArchLinux
- Alle laufenden Container anzeigen (NSPawn und andere)
machinectl list
- Mit dem Login-Prompt des Containers verbinden (Benutzer/Password:
root=/=root
)
machinectl login ArchLinux
- Eine Root-Shell im Namensraum des Containers erzeugen
machinectl shell ArchLinux
- Einen Container herunterfahren
machinectl poweroff ArchLinux
- Einen Container hart (!) stoppen
machinectl terminate ArchLinux
- Die per
machinectl
verwalteten Container liegen im Dateisystem unter/var/lib/machines
und können auch direkt von dort gestartet werden:
systemd-nspawn -bD /var/lib/machines/ArchLinux