Warum befindet sich conmon in einer anderen Gruppe, wenn podman mit systemd gestartet wird?


10

Der angegebene Podman ist auf einem Linux-System und einer Systemd-Einheit namens baz.service installiert:

# /etc/systemd/system/baz.service
[Service]
ExecStart=/usr/bin/podman run --rm --tty --name baz alpine sh -c 'while true; do date; sleep 1; done'
ExecStop=/usr/bin/podman stop baz

Und der baz.service hat begonnen:

# systemctl daemon-reload
# systemctl start baz.service

Wenn ich dann den Status des Geräts überprüfe, wird der Prozess shoder sleepin der Gruppe /system.slice/baz.service nicht angezeigt

# systemctl status baz
● baz.service
   Loaded: loaded (/etc/systemd/system/baz.service; static; vendor preset: enabl
   Active: active (running) since Sat 2019-08-10 05:50:18 UTC; 14s ago
 Main PID: 16910 (podman)
    Tasks: 9
   Memory: 7.3M
      CPU: 68ms
   CGroup: /system.slice/baz.service
           └─16910 /usr/bin/podman run --rm --tty --name baz alpine sh -c while
# ...

Ich hatte erwartet, die shund sleepKinder in meinem baz.service-Status zu sehen, weil ich von Redhat gehört habe, dass Podman ein traditionelles Fork-Exec-Modell verwendet.

Wenn Podman Fork und Exec gemacht hätte, wären meine shund sleepProcess dann nicht Kinder von Podman und würden in derselben Gruppe wie der ursprüngliche Podman-Prozess sein?

Ich hatte erwartet, systemd und podman verwenden zu können, um meine Container verwalten zu können, ohne dass die Kinder zu einem anderen Elternteil gehen und aus meiner baz.service ssystemd-Einheit entkommen.

Wenn psich mir die Ausgabe von ansehe, kann ich das sehen shund bin sleeptatsächlich Kinder eines anderen Prozesses namens conmon. Ich bin nicht sicher, woher conmon kam oder wie es gestartet wurde, aber systemd hat es nicht erfasst.

# ps -Heo user,pid,ppid,comm
# ...
root     17254     1   podman
root     17331     1   conmon
root     17345 17331     sh
root     17380 17345       sleep

Aus der Ausgabe geht hervor, dass meine baz.service-Einheit die conmon -> sh -> Schlafkette nicht verwaltet.

  • Wie unterscheidet sich podman vom Docker-Client-Server-Modell?
  • Wie unterscheidet sich Podmans Conmon von Dockers Containerd?

Vielleicht sind sie beide Container-Laufzeiten und der dockerdDaemon ist das, was die Leute loswerden wollen.

Vielleicht ist Docker wie folgt:

  • Dockerd Daemon
  • Docker Cli
  • Containerd Container Laufzeit

Und Podman ist wie:

  • podman cli
  • Conmon Container Laufzeit

Vielleicht verwendet Podman ein traditionelles Fork-Exec-Modell, aber es ist nicht das Podman-Cli, das Forking und Exec ist, sondern der Conmon-Prozess.

Ich bin verwirrt.


Es gibt eine Diskussion über diese Frage auf der Podman-Mailingliste: lists.podman.io/archives/list/podman@lists.podman.io/thread/…
mbigras

Antworten:


7

Die ganze Idee dahinter podmanist, sich von der zentralisierten Architektur mit dem übermächtigen Aufseher (z. B. dockerd) zu entfernen , bei dem der zentralisierte Dämon eine einzige Fehlerquelle darstellt. Es gibt sogar einen Hashtag dazu - " #nobigfatdaemons ".

Wie vermeide ich das zentralisierte Containermanagement? Sie entfernen den einzelnen Hauptdämon (erneut dockerd) und starten die Container unabhängig voneinander (am Ende des Tages sind Container nur Prozesse, sodass Sie den Dämon nicht benötigen, um sie zu erzeugen).

Sie brauchen jedoch noch den Weg zu

  • collect Containers logs - hat jemand zu halten , stdoutund stderrdes Behälters;
  • Container-Exit-Code sammeln - jemand muss wait(2)die PID 1 des Containers eingeben ;

Zu diesem Zweck wird jeder Podman-Container weiterhin von einem kleinen Daemon conmonüberwacht , der (vom "Container-Monitor") aufgerufen wird . Der Unterschied zum Docker-Daemon besteht darin, dass dieser Daemon so klein wie möglich ist (überprüfen Sie die Größe des Quellcodes ) und pro Container erzeugt wird. Wenn conmonein Container abstürzt, bleibt der Rest des Systems davon unberührt.

Wie wird der Container als nächstes erzeugt?

In Anbetracht der Tatsache, dass der Benutzer den Container möglicherweise wie bei Docker im Hintergrund ausführen möchte, wird der podman runProzess zweimal verzweigt und erst dann ausgeführt conmon:

$ strace -fe trace=fork,vfork,clone,execve -qq podman run alpine
execve("/usr/bin/podman", ["podman", "run", "alpine"], 0x7ffeceb01518 /* 30 vars */) = 0
...
[pid  8480] clone(child_stack=0x7fac6bffeef0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tid=[8484], tls=0x7fac6bfff700, child_tidptr=0x7fac6bfff9d0) = 8484
...
[pid  8484] clone(child_stack=NULL, flags=CLONE_VM|CLONE_VFORK|SIGCHLD <unfinished ...>
[pid  8491] execve("/usr/bin/conmon", ... <unfinished ...>
[pid  8484] <... clone resumed>)        = 8491

Der mittlere Prozess zwischen podman runund conmon(dh das direkte übergeordnete Element von conmon- im obigen Beispiel ist es PID 8484) wird beendet und von conmonrepariert init, wodurch ein selbstverwalteter Dämon wird. Danach gibt es conmonauch die Laufzeit ab (z. B. runc) und schließlich führt die Laufzeit den Einstiegspunkt des Containers aus (z /bin/sh. B. ).

Wenn der Container ausgeführt wird, podman runist er nicht mehr erforderlich und wird möglicherweise beendet. In Ihrem Fall bleibt er jedoch online, da Sie ihn nicht aufgefordert haben, sich vom Container zu lösen.

Als nächstes werden podmancgroups verwendet, um die Container zu begrenzen. Dies bedeutet, dass neue Gruppen für neue Container erstellt und die Prozesse dorthin verschoben werden . Nach den Regeln von cgroups kann der Prozess jeweils nur Mitglied einer cgroup sein, und wenn Sie den Prozess zu einer cgroup hinzufügen, wird er aus einer anderen cgroup (wo er zuvor war) innerhalb derselben Hierarchie entfernt. Wenn der Container gestartet wird, sieht das endgültige Layout von cgroups wie folgt aus: podman runBleibt in cgroups von baz.service, erstellt von systemd, wird der conmonProzess in seinen eigenen cgroups platziert, und containerisierte Prozesse werden in ihren eigenen cgroups platziert:

$ ps axf
<...>
 1660 ?        Ssl    0:01 /usr/bin/podman run --rm --tty --name baz alpine sh -c while true; do date; sleep 1; done
 1741 ?        Ssl    0:00 /usr/bin/conmon -s -c 2f56e37a0c5ca6f4282cc4c0f4c8e5c899e697303f15c5dc38b2f31d56967ed6 <...>
 1753 pts/0    Ss+    0:02  \_ sh -c while true; do date; sleep 1; done
13043 pts/0    S+     0:00      \_ sleep 1
<...>

$ cd /sys/fs/cgroup/memory/machine.slice
$ ls -d1 libpod*
libpod-2f56e37a0c5ca6f4282cc4c0f4c8e5c899e697303f15c5dc38b2f31d56967ed6.scope
libpod-conmon-2f56e37a0c5ca6f4282cc4c0f4c8e5c899e697303f15c5dc38b2f31d56967ed6.scope

$ cat libpod-2f56e37a0c5ca6f4282cc4c0f4c8e5c899e697303f15c5dc38b2f31d56967ed6.scope/cgroup.procs 
1753
13075

$ cat libpod-conmon-2f56e37a0c5ca6f4282cc4c0f4c8e5c899e697303f15c5dc38b2f31d56967ed6.scope/cgroup.procs 
1741

Hinweis: PID 13075 oben ist eigentlich ein sleep 1Prozess, der nach dem Tod von PID 13043 ausgelöst wurde.

Hoffe das hilft.


1
"Erstellt neue Gruppen für neue Container und verschiebt die Prozesse dorthin." Ich verstehe nicht, warum Podman diese Arbeit anstelle von systemd ausführt. Können Sie eine Erklärung hinzufügen, warum wir conmon verwenden, um stdout und stderr anstelle von systemd zu halten? Nach dem Erlernen von systemd dachte ich, dass der Zweck von systemd darin besteht, Prozesse zu verwalten und Aufgaben wie stdout / stderr zu erfassen, den Exit-Status herauszufinden und den Neustart durchzuführen.
Mbigras

1
Podman verwaltet cgroups, weil es den Container besitzt und sicherstellen muss, dass der Container funktioniert, unabhängig davon, über welches Init-System Sie verfügen. Systemd verwaltet cgroups für Dienste, da es Dienste besitzt (und Dienste sollten standardmäßig keine cgroups verwalten, obwohl systemd einige Arten der Delegierung unterstützt - siehe systemd.io/CGROUP_DELEGATION ). Wenn Sie möchten, dass podman die von systemd für den Dienst erstellten Gruppen wiederverwendet, muss eine Unterstützung von podman-Seite vorhanden sein, und ich sehe derzeit keine (obwohl ich mich möglicherweise irre).
Danila Kiver

1
Bezüglich stdout/ stderrStreams - podmanbesitzt wiederum den Container und erfasst die Streams des containerisierten Prozesses. systemdbesitzt den Dienst und erfasst die Streams des Hauptprozesses des Dienstes (in Ihrem Fall systemdtatsächlich stdout/ stderrdes podman runProzesses). Dies funktioniert genau so, wie es funktionieren sollte, da conmondie Streams des Containers erfasst , podman runangehängt conmonund systemderfasst werden podman run, sodass schließlich alle Protokolle des Containers erfasst werden systemdund Sie sie in sehen systemctl status baz.service.
Danila Kiver
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.