Wir verfolgen seit langem das Thema der Verwendung von systemd in Containern. Bereits 2014 schrieb unser Sicherheitsexperte Daniel Walsh einen Artikel , und ein paar Jahre später – einen weiteren, der hieß , in dem er feststellte, dass sich die Situation nicht wesentlich verbessert hatte. Insbesondere schrieb er: „Leider, auch zwei Jahre später, wenn man nach „Docker system“ googelt, taucht zuerst sein alter Artikel auf. Das bedeutet, es ist an der Zeit, etwas zu ändern.“ Darüber hinaus haben wir bereits ü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 herausnehmen und in Containern betreiben. Es wäre natürlich besser, solche Anwendungen in Mikrodienste zu zerlegen, aber nicht jeder kann das momentan oder hat einfach nicht die Zeit. Daher macht es durchaus Sinn, solche Anwendungen in Form von Diensten zu betreiben, die systemd aus Unit-Dateien startet.
- Systemd-Unit-Dateien – die meisten Anwendungen, die innerhalb von Containern betrieben werden, bestehen aus Code, der zuvor auf virtuellen oder physikalischen Maschinen ausgeführt wurde. Diese Anwendungen haben eine Unit-Datei, die für diese Anwendungen geschrieben wurde und versteht, wie sie gestartet werden müssen. Daher ist es besser, Dienste mit unterstützten Methoden zu starten, als seine eigene Init-Dienste zu hacks.
- Systemd ist ein Prozessmanager. Er verwaltet Dienste (stoppt, startet Dienste neu oder befreit Zombie-Prozesse) besser als jedes andere Werkzeug.
Es gibt jedoch auch viele Gründe, systemd in Containern nicht auszuführen. Der Hauptgrund ist, dass systemd/journald die Ausgabe der Container kontrolliert, während Werkzeuge wie oder davon ausgehen, dass Container ihre Logs direkt in stdout und stderr schreiben. Daher sollte man, wenn man Container über die oben genannten Orchestrierungswerkzeuge verwalten möchte, ernsthaft über die Verwendung von Container basierend auf systemd nachdenken. Darüber hinaus waren die Entwickler von Docker und Moby oft stark gegen die Verwendung von systemd in Containern.
Die Ankunft von Podman
Wir freuen uns, bekannt zu geben, dass sich die Situation endlich bewegt hat. Das Team von Red Hat, das für den Start von Containern verantwortlich ist, hat beschlossen, . Er trägt den Namen und bietet die gleiche Befehlszeilenschnittstelle (CLI) wie Docker. Praktisch alle Docker-Befehle lassen sich auch in Podman verwenden. Wir führen häufig Seminare durch, die nun " " genannt werden, und die erste Folie fordert dazu auf, folgendes zu schreiben: alias docker=podman.
Das machen viele.
Wir sind mit unserem Podman in keiner Weise gegen Container auf der Grundlage von systemd. Schließlich wird Systemd häufig als Init-Subsystem unter Linux verwendet und es wäre ignorant, es nicht ordnungsgemäß in Containern zu unterstützen, wie es Tausende von Menschen gewohnt sind, Container zu starten.
Podman weiß, was zu tun ist, damit systemd im Container korrekt funktioniert. Es benötigt Dinge wie das Einhängen von tmpfs auf /run und /tmp. Es funktioniert gut, wenn die "Container-Umgebung" aktiviert ist, und es erwartet Schreibrechte für seinen Teil des cgroup-Verzeichnisses und den Ordner /var/log/journald.
Beim Start eines Containers, bei dem der erste Befehl init oder systemd ist, konfiguriert Podman automatisch tmpfs und Cgroups, damit der Start von systemd problemlos verläuft. Um diesen automatischen Startmodus zu deaktivieren, wird die Option —systemd=false verwendet. Beachten Sie, dass Podman den systemd-Modus nur dann verwendet, wenn es sieht, dass der Befehl systemd oder init ausgeführt werden muss.
Hier ist ein Auszug aus dem Manual:
man podman run
…–systemd=true|false
Starten Sie den Container im systemd-Modus. Standardmäßig aktiviert.
Wenn im Container der Befehl systemd oder init ausgeführt wird, konfiguriert Podman die tmpfs-Mount-Punkte in den folgenden Verzeichnissen:
/run, /run/lock, /tmp, /sys/fs/cgroup/systemd, /var/lib/journal
Außerdem wird standardmäßig als Stopp-Signal SIGRTMIN+3 verwendet.
All dies ermöglicht es systemd, in einem abgeschotteten Container ohne Modifikationen zu arbeiten.
HINWEIS: systemd versucht, in das cgroup-Dateisystem zu schreiben. Allerdings verbietet SELinux standardmäßig Containern dies. Um das Schreiben zu erlauben, aktivieren Sie die logische Option container_manage_cgroup:
setsebool -P container_manage_cgroup true
Jetzt sehen wir uns an, wie die Docker-Datei zum Starten 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 ist alles.
Jetzt bauen wir den Container:
# podman build -t systemd .
Wir sagen SELinux, dass es systemd erlauben soll, die Konfiguration von Cgroups zu modifizieren:
# setsebool -P container_manage_cgroup true
Viele vergessen übrigens diesen Schritt. Zum Glück muss man das nur einmal machen, 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.
Alles klar, der Dienst wurde gestartet und läuft:
$ curl localhost
<html xml_lang="en" lang="en">
…
</html>
HINWEIS: Versuchen Sie das nicht in Docker! Dort sind weiterhin einige zusätzliche Schritte nötig, um solche Container über den Daemon zu starten. (Es werden zusätzliche Felder und Pakete benötigt, damit alles reibungslos in Docker funktioniert, oder es muss in einem privilegierten Container gestartet werden. Details siehe in .)
Noch ein paar coole Dinge über Podman und systemd
Podman funktioniert besser als Docker in systemd-Einheitsdateien
Wenn Container beim Systemstart gestartet werden müssen, können einfach die entsprechenden Podman-Befehle in die systemd-Einheitsdatei eingefügt werden, die den Dienst startet und überwacht. Podman verwendet ein standardmäßiges Fork-Exec-Modell. Mit anderen Worten, die Containerprozesse sind Kindprozesse von Podman, sodass systemd sie leicht überwachen kann.
Docker verwendet ein Client-Server-Modell, und Docker-CLI-Befehle können ebenfalls direkt in der Einheitsdatei platziert werden. Nachdem sich der Docker-Client jedoch mit dem Docker-Daemon verbunden hat, wird er (der Client) einfach zu einem weiteren Prozess, der stdin und stdout verarbeitet. Systemd hat hingegen keine Vorstellung von der Verbindung zwischen dem Docker-Client und dem Container, der unter dem Docker-Daemon läuft, und kann in diesem Modell den Dienst nicht überwachen.
Aktivierung von systemd über einen Socket
Podman funktioniert korrekt mit der Aktivierung über einen Socket. Da Podman das Fork-Exec-Modell verwendet, kann es den Socket an seine Kind-Containerprozesse weitergeben. Docker kann das so nicht, da es ein Client-Server-Modell verwendet.
Der varlink-Dienst, den Podman zur Interaktion mit Remote-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, erlaubt es den Nutzern, ü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. Danach aktiviert systemd das Programm Podman, um Nachrichten zu empfangen und mit der Verwaltung der Container zu beginnen. Die Aktivierung von systemd über den Socket ermöglicht es, ohne einen ständig laufenden Daemon für die Implementierung der Remote-APIs auszukommen.
Darüber hinaus entwickeln wir einen weiteren Client für Podman mit dem Namen podman-remote, der die gleiche Podman-CLI implementiert, aber varlink für den Start von Containern aufruft. 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 auch für MacOS und Windows neben Linux zu unterstützen, damit Entwickler auf diesen Plattformen eine Linux-VM mit aktivem Podman varlink starten und das Gefühl haben können, dass die Container lokal ausgeführt werden.
SD_NOTIFY
Systemd ermöglicht es, den Start von unterstützenden Diensten bis zu dem Zeitpunkt zu verschieben, an dem der erforderliche containerisierte Dienst gestartet wird. Podman kann den SD_NOTIFY-Socket in den containerisierten Dienst weiterleiten, damit dieser systemd über seine Einsatzbereitschaft informiert. Wiederum kann Docker, das ein Client-Server-Modell verwendet, dies nicht.
Geplante Funktionen
Wir planen die Hinzufügung des Befehls podman generate systemd CONTAINERID, der eine systemd-Einheitendatei zur Verwaltung eines bestimmten, angegebenen Containers generiert. Dies sollte sowohl im Root- als auch im rootless-Modus für unprivilegierte Container funktionieren. Wir haben sogar einen Antrag auf die Erstellung einer OCI-kompatiblen Ausführungsumgebung mit systemd-nspawn gesehen.
Fazit
Das Ausführen von systemd in einem Container ist ein durchaus nachvollziehbares Bedürfnis. Und dank Podman haben wir endlich eine Container-Ausführungsumgebung, die nicht im Widerspruch zu systemd steht und dessen Nutzung erleichtert.
Quelle: habr.com
