Wir verfolgen seit langem das Thema der Nutzung von systemd in Containern. Bereits 2014 schrieb unser Sicherheitsingenieur Daniel Walsh einen Artikel , und ein paar Jahre später einen weiteren mit dem Titel , in dem er feststellte, dass sich die Situation nicht wirklich verbessert hatte. Insbesondere schrieb er: „Leider, und zwei Jahre später, wenn man nach „Docker system“ googelt, taucht als erstes immer noch sein alter Artikel auf. Es wird Zeit, etwas zu ändern.“ Zudem haben wir schon einmal über .
berichtet. In diesem Artikel zeigen wir, was sich seitdem geändert hat und wie uns Podman dabei helfen kann.
Es gibt viele Gründe, systemd innerhalb eines Containers auszuführen, wie zum Beispiel:
- Multiservice-Container – viele möchten ihre Multiservice-Anwendungen aus virtuellen Maschinen herauslösen und in Containern ausführen. Es wäre besser, solche Anwendungen in Mikrodienste zu zerlegen, aber nicht jeder kann das derzeit oder hat einfach keine Zeit dazu. Daher ist es durchaus sinnvoll, solche Anwendungen als von systemd verwaltete Dienste in Form von Unit-Dateien auszuführen.
- Unit-Dateien von Systemd – Die meisten Anwendungen, die innerhalb von Containern betrieben werden, bestehen aus Code, der zuvor auf virtuellen oder physischen Maschinen lief. Diese Anwendungen verfügen über eine Einheitendatei, die speziell für sie erstellt wurde und weiß, wie sie gestartet werden müssen. Daher ist es besser, Dienste mit unterstützten Methoden zu starten, anstatt die eigene Init-Daemon zu modifizieren.
- Systemd ist ein Prozessmanager. Er verwaltet Dienste (stoppt, startet Dienste neu oder beendet Zombie-Prozesse) besser als jedes andere Werkzeug.
Dennoch gibt es viele Gründe, warum man systemd in Containern vermeiden sollte. Der Hauptgrund ist, dass systemd/journald die Ausgaben von Containern steuert, während Werkzeuge wie oder annehmen, dass Container ihre Logs direkt in stdout und stderr schreiben. Wenn Sie Container also über Orchestrierungswerkzeuge wie die oben genannten verwalten möchten, sollten Sie ernsthaft über den Einsatz von systemd-basierten Containern nachdenken. Zudem waren die Entwickler von Docker und Moby oft entschieden gegen die Nutzung von systemd in Containern.
Das Aufkommen von Podman
Wir freuen uns, Ihnen mitteilen zu können, dass sich die Situation endlich weiterentwickelt hat. Das Team bei Red Hat, das für das Starten von Containern verantwortlich ist, hat beschlossen, Diese trägt den Namen und bietet eine ähnliche Befehlszeilenschnittstelle (CLI) wie Docker. Praktisch alle Docker-Befehle lassen sich auch in Podman verwenden. Wir veranstalten oft Workshops, die jetzt " und die erste Folie fordert auf: alias docker=podman.
Das tun viele.
Wir sind mit unserem Podman keinesfalls gegen Container, die auf systemd basieren. Immerhin wird Systemd häufig als Init-Subsystem in Linux verwendet, und es wäre falsch, ihm in Containern nicht richtig zu funktionieren zu erlauben, da viele Menschen so gewohnt sind, Container zu starten.
Podman weiß, was zu tun ist, damit systemd in einem Container richtig funktioniert. Es benötigt Dinge wie das Mounten von tmpfs auf /run und /tmp. Es mag es, wenn die "Container"-Umgebung aktiviert ist, und erwartet Schreibrechte auf seinen Teil des cgroup-Verzeichnisses und im Ordner /var/log/journald.
Wenn ein Container gestartet wird, in dem der erste Befehl init oder systemd ist, konfiguriert Podman automatisch tmpfs und Cgroups, um einen reibungslosen Start von systemd zu gewährleisten. Um diesen automatischen Startmodus zu blockieren, verwenden Sie die Option —systemd=false. Bitte beachten Sie, dass Podman den systemd-Modus nur aktiviert, wenn es erkennt, dass der Befehl systemd oder init ausgeführt werden soll.
Hier ist ein Auszug aus dem Handbuch:
man podman run
…–systemd=true|false
Startet den Container im systemd-Modus. Standardmäßig aktiviert.
Wenn im Container der Befehl systemd oder init ausgeführt wird, konfiguriert Podman die tmpfs-Mountpunkte in den folgenden Verzeichnissen:
/run, /run/lock, /tmp, /sys/fs/cgroup/systemd, /var/lib/journal
Als Stoppsignal wird standardmäßig SIGRTMIN+3 verwendet.
All dies ermöglicht es systemd, in einem isolierten Container ohne jegliche Modifikationen zu arbeiten.
HINWEIS: systemd versucht, in das Dateisystem cgroup zu schreiben. Allerdings verbietet SELinux standardmäßig, dass Container dies tun. Um das Schreiben zu erlauben, aktivieren Sie den logischen Parameter container_manage_cgroup:
setsebool -P container_manage_cgroup true
Sehen Sie sich jetzt an, wie eine Dockerfile für den Start von systemd im Container unter Verwendung von Podman aussieht:
# cat Dockerfile
FROM fedora
RUN dnf -y install httpd; dnf clean all; systemctl enable httpd
EXPOSE 80
CMD [ "/sbin/init" ]
Das war's.
Jetzt bauen wir den Container:
# podman build -t systemd .
Wir erklären, wie man SELinux erlaubt, dass systemd die Cgroups-Konfiguration modifiziert:
# setsebool -P container_manage_cgroup true
Viele vergessen übrigens diesen Schritt. Zum Glück muss dies nur einmal gemacht werden, und die Einstellung bleibt nach einem Neustart des Systems erhalten.
Jetzt starten wir einfach den Container:
# podman run -ti -p 80:80 systemd
systemd 239 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=hybrid)
Detected virtualization container-other.
Detected architecture x86-64.
Welcome to Fedora 29 (Container Image)!
Set hostname to <1b51b684bc99>.
Failed to install release agent, ignoring: Read-only file system
File /usr/lib/systemd/system/systemd-journald.service:26 configures an IP firewall (IPAddressDeny=any), but the local system does not support BPF/cgroup based firewalling.
Proceeding WITHOUT firewalling in effect! (This warning is only shown for the first loaded unit using IP firewalling.)
[ OK ] Listening on initctl Compatibility Named Pipe.
[ OK ] Listening on Journal Socket (/dev/log).
[ OK ] Started Forward Password Requests to Wall Directory Watch.
[ OK ] Started Dispatch Password Requests to Console Directory Watch.
[ OK ] Reached target Slices.
…
[ OK ] Started The Apache HTTP Server.
Fertig, der Dienst läuft und funktioniert:
$ curl localhost
<html xml_lang="en" lang="en">
…
</html>
HINWEIS: Versuchen Sie nicht, dies mit Docker zu wiederholen! Dort sind immer noch viele Umwege nötig, um solche Container über den Daemon zu starten. (Es werden zusätzliche Felder und Pakete benötigt, damit alles nahtlos in Docker funktioniert, oder man muss in einem privilegierten Container starten. Details finden Sie in .)
Noch ein paar coole Dinge über Podman und systemd
Podman funktioniert besser als Docker in systemd-Einheitsdateien
Wenn Container beim Systemstart gestartet werden sollen, können die entsprechenden Podman-Befehle einfach in die systemd-Einheitsdatei eingefügt werden, die den Dienst startet und überwacht. Podman verwendet das Standardmodell des Forkens beim Ausführen. Mit anderen Worten, die Containerprozesse sind Tochterprozesse des Podman-Prozesses, sodass systemd sie leicht überwachen kann.
Docker verwendet ein Client-Server-Modell, und die CLI-Befehle von Docker können ebenfalls direkt in der Einheitendatei platziert werden. Sobald der Docker-Client jedoch mit dem Docker-Daemon verbunden ist, wird er (der Client) einfach zu einem weiteren Prozess, der stdin und stdout verarbeitet. In diesem Zusammenhang weiß systemd nichts über die Verbindung zwischen dem Docker-Client und dem Container, der unter dem Docker-Daemon läuft, und kann daher in diesem Modell den Dienst grundsätzlich nicht überwachen.
Aktivierung von systemd über einen Socket
Podman verarbeitet die Aktivierung über einen Socket korrekt. Da Podman das Fork-Exec-Modell verwendet, kann es den Socket an seine untergeordneten Containerprozesse weitergeben. Docker kann dies nicht, da es das Client-Server-Modell verwendet.
Der varlink-Dienst, den Podman zur Interaktion mit entfernten Clients und Containern verwendet, wird tatsächlich über einen Socket aktiviert. Das Paket cockpit-podman, das in Node.js geschrieben ist und Teil des Cockpit-Projekts ist, ermöglicht es Benutzern, über eine Weboberfläche mit Podman-Containern zu interagieren. Der Web-Daemon, auf dem cockpit-podman läuft, sendet Nachrichten an den varlink-Socket, der von systemd überwacht wird. Anschließend aktiviert systemd das Podman-Programm, um Nachrichten zu empfangen und die Containerverwaltung zu starten. Die Aktivierung von systemd über den Socket ermöglicht es, auf einen ständig aktiven Daemon bei der Implementierung von Remote-APIs zu verzichten.
Darüber hinaus entwickeln wir einen weiteren Client für Podman mit dem Namen podman-remote, der das gleiche Podman-CLI implementiert, jedoch varlink aufruft, um Container zu starten. Podman-remote kann über SSH-Sitzungen arbeiten, was eine sichere Interaktion mit Containern auf verschiedenen Maschinen ermöglicht. Im Laufe der Zeit planen wir, podman-remote zur Unterstützung von MacOS und Windows neben Linux einzusetzen, damit Entwickler auf diesen Plattformen eine Linux-VM mit einem funktionierenden Podman varlink ausführen und das Gefühl haben, dass die Container auf ihrem lokalen Rechner laufen.
SD_NOTIFY
Systemd ermöglicht es, den Start unterstützender Dienste bis zu dem Zeitpunkt zu verzögern, an dem der benötigte containerisierte Dienst gestartet wird. Podman kann den SD_NOTIFY-Socket an den containerisierten Dienst weiterleiten, damit dieser systemd über seine Betriebsbereitschaft informiert. Im Gegensatz dazu kann Docker, das ein Client-Server-Modell verwendet, dies nicht.
Geplant
Wir planen, das Kommando podman generate systemd CONTAINERID hinzuzufügen, das eine Systemd-Einheit für die Verwaltung eines spezifischen Containers generiert. Dies sollte sowohl im Root- als auch im Rootless-Modus für unprivilegierte Container funktionieren. Wir haben sogar Anfragen gesehen, um eine OCI-kompatible Ausführungsumgebung systemd-nspawn zu erstellen.
Fazit
Das Ausführen von systemd in einem Container ist ein durchaus nachvollziehbares Bedürfnis. Dank Podman haben wir endlich eine Umgebung für die Ausführung von Containern, die nicht im Widerspruch zu systemd steht, sondern es einfach ermöglicht.
Quelle: habr.com
