podmanをsystemdで起動すると、なぜ別のcgroupにconmonが表示されるのですか?


11

与えられたpodmanはLinuxシステムとbaz.serviceという名前のsystemdユニットにインストールされています:

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

そして、baz.serviceが開始しました:

# systemctl daemon-reload
# systemctl start baz.service

次に、ユニットのステータスを確認すると、/ system.slice / baz.service cgroupにプロセスshまたはsleepプロセスが表示されません。

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

podmanが従来のfork-execモデルを使用しているとredhatの人々から聞いたので、私はbaz.serviceステータスでshsleep子供が表示されることを期待していました。

podmanがforkとexecを実行した場合、私のshand sleepプロセスはpodmanの子になり、元のpodmanプロセスと同じcgroupに含まれるのではないでしょうか?

私はsystemdとpodmanを使用して、子供たちが別の親に出向いて私のbaz.service ssystemdユニットから脱出することなく、私のコンテナーを管理できることを期待していました。

ps私の出力を見るとsh、それsleepが実際にと呼ばれる別のプロセスの子であることがわかりconmonます。conmonがどこから来たのか、どのように開始されたのかはわかりませんが、systemdはそれをキャプチャしませんでした。

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

出力から、私のbaz.serviceユニットがconmon-> sh-> sleepチェーンを管理していないことは明らかです。

  • podmanはDockerクライアントサーバーモデルとどう違うのですか?
  • ポッドマンのコンモンはドッカーのコンテナとどのように違うのですか?

多分それらは両方ともコンテナーランタイムであり、dockerdデーモンは人々が取り除きたいものです。

だからおそらくドッカーは次のようなものです:

  • dockerdデーモン
  • ドッカークリ
  • コンテナー化されたコンテナーランタイム

そしてpodmanは次のようなものです:

  • ポッドマンCLI
  • 共通コンテナーランタイム

つまり、podmanは従来のfork execモデルを使用しているかもしれませんが、フォークして実行するのはpodman cliではなく、共通のプロセスです。

戸惑う。


podmanメーリングリストでこの質問についての議論があります:lists.podman.io/archives/list/podman@lists.podman.io/thread/...
mbigrasは

回答:


8

背後にpodmanある全体的なアイデアはdockerd、集中型デーモンが単一障害点である超強力な監視者(例:)を備えた集中型アーキテクチャから離れることです。これについてのハッシュタグもあります-" #nobigfatdaemons "。

コンテナーの集中管理を回避するにはどうすればよいですか?単一のメインデーモン(ここでもdockerd)を削除して、コンテナーを個別に起動します(結局のところ、コンテナーは単なるプロセスなので、デーモンを起動する必要はありません)。

ただし、次の方法が必要です。

  • コンテナのログを収集する-誰かがコンテナを保持stdoutしなければなりstderrません。
  • コンテナの終了コードを収集します-誰かがwait(2)コンテナのPID 1を使用する必要があります。

この目的のために、各podmanコンテナーはconmon(「コンテナーモニター」から)呼び出される小さなデーモンによって引き続き監視されます。Dockerデーモンとの違いは、このデーモンはできるだけ小さく(ソースコードのサイズを確認する)、コンテナごとに生成されることです。場合はconmon一つの容器のクラッシュのために、システムの残りの部分が影響を受けたままになります。

次に、コンテナはどのように生成されますか?

Dockerのように、ユーザーがコンテナーをバックグラウンドで実行したい場合があることを考慮して、podman runプロセスは2回フォークしてから実行し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

中間処理podman runとは、conmon(すなわち、の直接の親conmon-それは、上記の例では、PID 8484で)終了するとconmonによりリペアレントされinit、したがって自己管理デーモンになって、。この後conmon、ランタイム(たとえばrunc)をフォークして、最後にランタイムがコンテナのエントリポイント(たとえば/bin/sh)を実行します。

コンテナの実行中podman runはは不要になり、終了する可能性がありますが、コンテナからの切り離しを要求しなかったため、ケースではオンラインのままです。

次に、podmancgroupを使用してコンテナーを制限します。これは、新しいコンテナー用の新しいcgroupを作成し、そこにプロセスを移動すること意味します。cgroupのルールにより、プロセスは一度に1つのcgroupのみのメンバーになることができ、プロセスを一部のcgroupに追加すると、同じ階層内の他のcgroup(以前の場所)からプロセスが削除されます。したがって、コンテナが起動すると、cgroupの最終的なレイアウトは次のようになります。によって作成されpodman runたのcgroupに残り、プロセスは独自のcgroupに配置され、コンテナ化されたプロセスは独自のcgroupに配置されます。baz.servicesystemdconmon

$ 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

注:上記のPID 13075は実際にはsleep 1プロセスであり、PID 13043の終了後に生成されます。

お役に立てれば。


1
「新しいコンテナー用の新しいcgroupを作成し、そこにプロセスを移動します」podmanがsystemdの代わりにその作業を行っている理由がわかりません。systemdではなくstdoutとstderrを保持するためにconmonを使用する理由について説明を追加できますか?systemdについて学ぶことから、systemdの目的はプロセスを管理し、stdout / stderrのキャプチャ、終了ステータスの把握、再起動の処理などのタスクを実行することであると考えました。
mbigras

2
ポッドマンはcgroupを管理します。これは、コンテナーを所有し、コンテナーが初期化システムに関係なく機能することを保証する必要があるためです。systemdはサービスを所有しているため、サービスのcgroupを管理します(そして、systemdはいくつかの種類の委任をサポートしますが、デフォルトではサービスはcgroupを管理することになっています-systemd.io/CGROUP_DELEGATIONを参照してください)。podmanがsystemdによって作成されたサービス用のcgroupを再利用するようにしたい場合は、podman側からのサポートが必要ですが、現在サポートされていません(エラーになる可能性があります)。
Danila Kiver

1
stdout/ stderrストリーム-再び、podmanコンテナおよびキャプチャコンテナプロセスの流れを所有しています。systemdサービスを所有し、サービスのメインプロセスのストリームをキャプチャします(この場合、systemd実際にはプロセスのstdout/ stderrをキャプチャしpodman runます)。これconmonは、コンテナのストリームをキャプチャし、にpodman runアタッチしconmonsystemdのストリームをキャプチャするpodman runので、正常に機能します。最後に、コンテナのすべてのログがによってキャプチャされsystemd、に表示されsystemctl status baz.serviceます。
Danila Kiver
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.