Wir haben das Thema der Verwendung von systemd in Containern schon lange verfolgt. Bereits 2014 schrieb unser Sicherheitsingenieur Daniel Walsh einen Artikel mit dem Titel
Running systemd in einem Docker-Container und einige Jahre später einen weiteren Artikel mit dem Titel
Running systemd in einem nicht privilegierten Container , in dem er erklärte, dass dies nicht der Fall sei sehr viel verbessert. Insbesondere schrieb er: „Leider und zwei Jahre später, wenn Sie das Docker-System googeln, erscheint als erstes derselbe alte Artikel von ihm. Es ist also Zeit, etwas zu ändern. “ Darüber hinaus haben wir bereits über den
Konflikt zwischen den Entwicklern von Docker und systemd gesprochen .

In diesem Artikel werden wir zeigen, was sich in der letzten Zeit geändert hat und wie Podman uns in dieser Angelegenheit helfen kann.
Es gibt viele Gründe, systemd in einem Container auszuführen, z.
- Multiservice-Container - Viele Benutzer möchten ihre Multiservice-Anwendungen aus virtuellen Maschinen herausholen und in Containern ausführen. Es wäre natürlich besser, solche Anwendungen in Microservices zu unterteilen, aber noch kann nicht jeder dies tun, oder es bleibt einfach keine Zeit. Daher ist das Starten solcher Anwendungen in Form von Diensten, die von systemd aus Einheitendateien gestartet werden, absolut sinnvoll.
- Systemd-Einheitendateien - Die meisten Anwendungen, die in Containern ausgeführt werden, werden aus Code kompiliert, der zuvor auf virtuellen oder physischen Maschinen ausgeführt wurde. Diese Anwendungen verfügen über eine Einheitendatei, die für diese Anwendungen geschrieben wurde und deren Ausführung versteht. Es ist daher besser, die Dienste mit den unterstützten Methoden zu starten, als Ihren eigenen Init-Dienst zu hacken.
- Systemd ist ein Prozessmanager. Es verwaltet Dienste (fährt herunter, startet Dienste neu oder crawlt Zombie-Prozesse) besser als jedes andere Tool.
Es gibt viele Gründe, systemd nicht in Containern auszuführen. Das wichtigste ist, dass systemd / journald die Ausgabe von Containern steuert und Tools wie
Kubernetes oder
OpenShift erwarten, dass Container das Protokoll direkt in stdout und stderr schreiben. Wenn Sie Container über Orchestrierungs-Tools wie die oben genannten verwalten möchten, müssen Sie daher die Verwendung von Containern auf der Basis von systemd ernsthaft in Betracht ziehen. Darüber hinaus waren die Entwickler von Docker und Moby häufig stark gegen die Verwendung von systemd in Containern.
Podman kommt
Wir freuen uns, Ihnen mitteilen zu können, dass sich die Situation endlich geändert hat. Das Team, das für den Start von Containern bei Red Hat verantwortlich ist, hat beschlossen, eine
eigene Containermaschine zu entwickeln . Er erhielt den Namen
Podman und bietet die gleiche Befehlszeilenschnittstelle (CLI) wie Docker. Und fast alle Docker-Befehle können in Podman auf dieselbe Weise verwendet werden. Wir veranstalten häufig Seminare, die jetzt als "
Docker in Podman ändern" bezeichnet werden. Auf der ersten Folie werden Sie aufgefordert, sich zu registrieren: alias docker = podman.
Viele tun dies.
Mein Podman und ich sind in keiner Weise gegen systemd-basierte Container. Schließlich wird Systemd am häufigsten als Linux-Init-Subsystem verwendet. Wenn es in Containern nicht normal funktioniert, muss ignoriert werden, wie Tausende von Menschen es gewohnt sind, Container auszuführen.
Podman weiß, was zu tun ist, damit systemd im Container ordnungsgemäß funktioniert. Sie braucht Dinge wie das Mounten von tmpfs auf / run und / tmp. Sie mag es, wenn die "Container" -Umgebung aktiviert ist und sie auf Schreibberechtigungen für ihren Teil des cgroup-Verzeichnisses und für den Ordner / var / log / journald wartet.
Beim Starten eines Containers, in dem init oder systemd der erste Befehl ist, konfiguriert Podman tmpfs und Cgroups automatisch so, dass systemd problemlos gestartet wird. Verwenden Sie die Option --systemd = false, um diesen Autostartmodus zu blockieren. Bitte beachten Sie, dass Podman den systemd-Modus nur verwendet, wenn er sieht, dass der Befehl systemd oder init ausgeführt werden muss.
Hier ist ein Auszug aus dem Handbuch:
Mann Podman laufen
...
–Systemd = true | false
Ausführen des Containers im systemd-Modus. Standardmäßig aktiviert.
Wenn ein systemd- oder init-Befehl im Container ausgeführt wird, konfiguriert Podman die tmpfs-Mountpunkte in den folgenden Verzeichnissen:
/ run, / run / lock, / tmp, / sys / fs / cgroup / systemd, / var / lib / journal
Außerdem wird SIGRTMIN + 3 standardmäßig als Stoppsignal verwendet.
All dies ermöglicht es systemd, ohne Änderungen in einem geschlossenen Container zu arbeiten.
HINWEIS: systemd versucht, in das cgroup-Dateisystem zu schreiben. Standardmäßig verhindert SELinux jedoch, dass Container dies tun. Aktivieren Sie zum Aktivieren des Schreibens den Stapelparameter container_manage_cgroup:
setsebool -P container_manage_cgroup true
Schauen Sie sich nun an, wie die Docker-Datei aussieht, um systemd im Container auszuführen, wenn Sie Podman verwenden:
# cat Dockerfile FROM fedora RUN dnf -y install httpd; dnf clean all; systemctl enable httpd EXPOSE 80 CMD [ "/sbin/init" ]
Das ist alles.
Sammeln Sie nun den Behälter:
# podman build -t systemd .
Wir weisen SELinux an, systemd zu erlauben, die Konfiguration von Cgroups zu ändern:
# setsebool -P container_manage_cgroup true
Viele vergessen diesen Schritt übrigens. Glücklicherweise reicht es aus, dies nur einmal zu tun, und die Einstellung wird nach einem Systemneustart gespeichert.
Führen Sie jetzt einfach den Container aus:
# 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, der Service hat begonnen und funktioniert:
$ curl localhost <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> … </html>
HINWEIS: Versuchen Sie nicht, dies auf Docker zu wiederholen! Dort werden noch Tänze mit einem Tamburin benötigt, um solche Behälter durch einen Dämon zu starten. (Damit dies in Docker nahtlos funktioniert, sind zusätzliche Felder und Pakete erforderlich, oder es muss in einem privilegierten Container ausgeführt werden. Weitere
Informationen finden Sie im
Artikel .)
Noch ein paar coole Sachen über Podman und systemd
Podman funktioniert in systemd-Unit-Dateien besser als Docker
Wenn die Container beim Systemstart gestartet werden müssen, können Sie einfach die entsprechenden Podman-Befehle in die systemd-Einheitendatei einfügen, um den Dienst zu starten und zu überwachen. Podman verwendet das Standard-Fork-Exec-Modell. Mit anderen Worten, Containerprozesse sind mit dem Podman-Prozess verbunden, sodass systemd sie problemlos überwachen kann.
Docker verwendet das Client-Server-Modell, und Docker-CLI-Befehle können auch direkt in die Einheitendatei eingefügt werden. Nachdem der Docker-Client jedoch eine Verbindung zum Docker-Dämon hergestellt hat, wird er (der Client) nur ein weiterer Prozess, der stdin und stdout verarbeitet. Systemd hat wiederum keine Ahnung von der Verbindung zwischen dem Docker-Client und dem Container, auf dem der Docker-Dämon ausgeführt wird, und daher kann systemd unter diesem Modell den Dienst nicht grundlegend überwachen.
Systemd Aktivierung über Socket
Podman führt die Aktivierung über einen Socket korrekt aus. Da Podman das Fork-Exec-Modell verwendet, kann es einen Socket an seine untergeordneten Containerprozesse weiterleiten. Docker weiß nicht wie, da es ein Client-Server-Modell verwendet.
Der Varlink-Dienst, den Podman verwendet, um mit Remoteclients mit Containern zu interagieren, wird tatsächlich über den Socket aktiviert. Das in Node.js geschriebene Cockpit-Podman-Paket, das Teil des Cockpit-Projekts ist, ermöglicht die Interaktion mit Podman-Containern über eine Weboberfläche. Der Web-Daemon, auf dem Cockpit-Podman ausgeführt wird, sendet Nachrichten an den Varlink-Socket, den systemd abhört. Danach aktiviert systemd das Podman-Programm, um Nachrichten zu empfangen und Container zu verwalten. Wenn Sie systemd über einen Socket aktivieren, können Sie bei der Implementierung von Remote-APIs auf einen ständig funktionierenden Daemon verzichten.
Darüber hinaus entwickeln wir einen weiteren Client für Podman namens podman-remote, der dieselbe Podman-CLI implementiert, jedoch varlink aufruft, um Container zu starten. Podman-remote kann zusätzlich zu SSH-Sitzungen arbeiten, sodass Sie sicher mit Containern auf verschiedenen Computern interagieren können. Im Laufe der Zeit planen wir, podman-remote zur Unterstützung von MacOS und Windows zusammen mit Linux zu verwenden, damit Entwickler auf diesen Plattformen die virtuelle Linux-Maschine mit Podman varlink ausführen können und das volle Gefühl haben, dass die Container auf dem lokalen Computer ausgeführt werden.
SD_NOTIFY
Mit Systemd können Sie den Start von Zusatzdiensten verzögern, bis der erforderliche Containerdienst gestartet wird. Podman kann den Socket SD_NOTIFY an den containerisierten Dienst weiterleiten, damit der Dienst systemd über seine Arbeitsbereitschaft informiert. Und wieder weiß Docker, das das Client-Server-Modell verwendet, nicht wie.
In den Plänen
Wir planen, den Befehl podman generate systemd CONTAINERID hinzuzufügen, der die systemd-Einheitendatei generiert, um einen bestimmten Container zu verwalten. Dies sollte sowohl im Root- als auch im Rootless-Modus für nicht privilegierte Container funktionieren. Wir haben sogar eine Anfrage zum Erstellen einer OCI-kompatiblen systemd-nspawn-Laufzeit gesehen.
Fazit
Das Ausführen von systemd in einem Container ist verständlich. Und dank Podman haben wir endlich eine Container-Launcher-Umgebung, die nicht systemd feindlich ist, aber einfach zu bedienen ist.