Perché conmon è in un cgroup diverso quando podman viene avviato con systemd?


11

Dato podman è installato su un sistema linux e un'unità systemd chiamata baz.service:

# /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

E il baz.service è iniziato:

# systemctl daemon-reload
# systemctl start baz.service

Quindi quando controllo lo stato dell'unità non vedo il processo sho sleepnel cgroup /system.slice/baz.service

# 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
# ...

Mi aspettavo di vedere la she sleepbambini nel mio stato di baz.service perché ho sentito la gente da dire RedHat usi podman un modello tradizionale forcella-exec.

Se podman eseguisse fork e exec, allora my she sleepprocess non sarebbero figli di podman e si troverebbero nello stesso cgroup del processo podman originale?

Mi aspettavo di poter usare systemd e podman per poter gestire i miei container senza che i bambini andassero da un altro genitore e fuggissero dalla mia unità sazsystemd baz.service.

Guardando l'output di psposso vederlo she in sleeprealtà sono figli di un diverso processo chiamato conmon. Non sono sicuro da dove provenga Conmon o come sia stato avviato ma Systemd non l'ha catturato.

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

Dall'output è chiaro che la mia unità baz.service non gestisce la catena del sonno conmon -> sh ->.

  • In che modo podman è diverso dal modello del server client docker?
  • In che modo il conmon di podman è diverso dal containerd della docker?

Forse sono entrambi runtime del contenitore e il dockerddemone è ciò di cui le persone vogliono sbarazzarsi.

Quindi forse la finestra mobile è come:

  • demone dockerd
  • docker cli
  • runtime contenitore containerd

E podman è come:

  • podman cli
  • runtime contenitore conmon

Quindi forse podman usa un tradizionale modello di fork fork ma non è il podman cli che sta biforcando ed exec, è il processo comune.

Mi sento confuso.


C'è una discussione su questa domanda nella mailing list di podman
mbigras

Risposte:


8

L'idea alla base podmanè quella di allontanarsi dall'architettura centralizzata con il super-potente sorvegliante (ad esempio dockerd), in cui il demone centralizzato è un singolo punto di errore. C'è persino un hashtag su questo - " #nobigfatdaemons ".

Come evitare la gestione centralizzata dei container? Rimuovete il singolo demone principale (di nuovo dockerd) e avviate i contenitori in modo indipendente (alla fine della giornata, i contenitori sono solo processi, quindi non è necessario il demone per generarli).

Tuttavia, hai ancora bisogno del modo di farlo

  • raccogliere i registri del contenitore: qualcuno deve trattenere stdoute stderrdel contenitore;
  • raccogliere il codice di uscita del container - qualcuno deve wait(2)sul PID 1 del container;

A tale scopo, ogni contenitore podman è ancora supervisionato da un piccolo demone, chiamato conmon(da "container monitor"). La differenza con il demone Docker è che questo demone è il più piccolo possibile (controlla la dimensione del codice sorgente ) e viene generato per contenitore. Se conmonper un contenitore si arresta in modo anomalo, il resto del sistema rimane invariato.

Successivamente, come viene generato il contenitore?

Considerando che l'utente potrebbe voler eseguire il contenitore in background, come con Docker, il podman runprocesso esegue il fork due volte e solo dopo esegue 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

Il processo intermedio tra podman rune conmon(cioè il genitore diretto di conmon- nell'esempio sopra è PID 8484) uscirà e conmonsarà riparato da init, diventando così demone autogestito. Dopodiché, conmonelimina anche il runtime (ad es. runc) E, infine, il runtime esegue il punto di accesso del container (ad es /bin/sh.).

Quando il contenitore è in esecuzione, podman runnon è più necessario e potrebbe uscire, ma nel tuo caso rimane online, perché non gli hai chiesto di staccarlo dal contenitore.

Successivamente, podmanutilizza cgroups per limitare i contenitori. Ciò significa che crea nuovi cgroup per nuovi contenitori e sposta i processi lì . Secondo le regole dei cgroups, il processo può essere il membro di un solo cgroup alla volta e l'aggiunta del processo ad alcuni cgroup lo rimuove da altri cgroup (dove era precedentemente) all'interno della stessa gerarchia. Quindi, quando il contenitore viene avviato, il layout finale dei cgroup appare come il seguente: podman runrimane nei cgroup del baz.service, creato da systemd, il conmonprocesso viene inserito nei suoi cgroups e i processi containerizzati vengono inseriti nei loro cgroup:

$ 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

Nota: PID 13075 sopra è in realtà un sleep 1processo, generato dopo la morte di PID 13043.

Spero che sia di aiuto.


1
"crea nuovi cgroup per nuovi contenitori e sposta i processi lì" Non capisco perché podman stia facendo quel lavoro invece di systemd. Puoi aggiungere una spiegazione sul perché usiamo conmon per contenere stdout e stderr invece di systemd? Dall'apprendimento di systemd ho pensato che lo scopo di systemd fosse gestire i processi ed eseguire attività come acquisire stdout / stderr, capire lo stato di uscita, gestire il riavvio.
mbigras,

2
Podman gestisce i cgroups perché possiede il contenitore e deve garantire che il contenitore funzioni indipendentemente dal sistema di init che hai. Systemd gestisce i cgroup per i servizi perché possiede servizi (e i servizi non sono tenuti a gestire i cgroup per impostazione predefinita, sebbene systemd supporti alcuni tipi di delega - consultare systemd.io/CGROUP_DELEGATION ). Se vuoi che podman riutilizzi i cgroup creati da systemd per il servizio, ci deve essere un supporto dal lato podman, e attualmente non ne vedo uno (anche se potrei sbagliare).
Danila Kiver,

1
Per quanto riguarda stdout/ stderrstream: ancora una volta, podmanpossiede il contenitore e acquisisce i flussi del processo containerizzato. systemdpossiede il servizio e acquisisce i flussi del processo principale del servizio (nel tuo caso, systemdeffettivamente acquisisce stdout/ stderrdel podman runprocesso). Funziona esattamente come dovrebbe funzionare, perché conmonacquisisce i flussi del contenitore, si podman runattacca conmon, systemdcattura i flussi di podman run, quindi, alla fine, tutti i registri del contenitore vengono catturati systemde li vedi dentro systemctl status baz.service.
Danila Kiver,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.