web-dev-qa-db-ja.com

podmanをsystemdで起動したときに、別のcgroupでよく見られるのはなぜですか?

与えられた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を実行した場合、私のshsleepプロセスはpodmanの子であり、元のpodmanプロセスと同じcgroupにないのではないでしょうか?

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

psの出力を見ると、shsleepが実際には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クライアントサーバーモデルとどう違うのですか?
  • Podmanのconmonはdockerのcontainerdとどう違うのですか?

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

だから多分ドッカーは次のようなものです:

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

そして、ポッドマンは次のようなものです:

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

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

戸惑う。

10
mbigras

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

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

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

  • コンテナーのログを収集する-誰かがコンテナーのstdoutstderrを保持する必要があります。
  • コンテナの終了コードを収集する-誰かがコンテナのPID 1でwait(2)を実行する必要があります。

この目的のために、各podmanコンテナーは、conmon(「コンテナーモニター」から)と呼ばれる小さなデーモンによって引き続き監視されます。 Dockerデーモンとの違いは、このデーモンは可能な限り小さい(チェック ソースコードのサイズ をチェックする)ことであり、コンテナーごとに生成されます。 1つのコンテナーのconmonがクラッシュしても、システムの残りの部分は影響を受けません。

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

Dockerのように、ユーザーがコンテナーをバックグラウンドで実行したい場合があることを考慮して、podman runプロセスはtwiceをフォークしてから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 runconmonの間の中間プロセス(つまり、conmonの直接の親-上記の例ではPID 8484)は終了し、conmoninitによって親が変更され、自己管理デーモンになります。この後、conmonもランタイム(たとえば、runc)から分岐し、最後に、ランタイムがコンテナのエントリポイント(たとえば、/bin/sh)を実行します。

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

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

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

お役に立てれば。

7
Danila Kiver