与えられた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ステータスでsh
とsleep
の子が表示されることを期待していました。
Podmanがforkとexecを実行した場合、私のsh
とsleep
プロセスはpodmanの子であり、元のpodmanプロセスと同じcgroupにないのではないでしょうか?
子供が別の親に出向き、baz.service ssystemdユニットから脱出することなく、systemdとpodmanを使用してコンテナーを管理できることを期待していました。
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チェーンを管理していないことは明らかです。
おそらくそれらは両方ともコンテナーランタイムであり、dockerd
デーモンは人々が取り除きたいものです。
だから多分ドッカーは次のようなものです:
そして、ポッドマンは次のようなものです:
つまり、podmanは従来のfork execモデルを使用しているかもしれませんが、フォークして実行するのはpodman cliではなく、共通のプロセスです。
戸惑う。
podman
の背後にある全体的なアイデアは、集中型デーモンが単一障害点である超強力な監視機能(たとえば、dockerd
)を使用して、集中型アーキテクチャから離れることです。これについてのハッシュタグもあります-「#nobigfatdaemons」。
コンテナーの集中管理を回避する方法は?単一のメインデーモン(ここでもdockerd
)を削除し、コンテナーを個別に起動します(結局のところ、コンテナーは単なるプロセスなので、デーモンを起動する必要はありません)。
ただし、次の方法が必要です。
stdout
とstderr
を保持する必要があります。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 run
とconmon
の間の中間プロセス(つまり、conmon
の直接の親-上記の例ではPID 8484)は終了し、conmon
はinit
によって親が変更され、自己管理デーモンになります。この後、conmon
もランタイム(たとえば、runc
)から分岐し、最後に、ランタイムがコンテナのエントリポイント(たとえば、/bin/sh
)を実行します。
コンテナーの実行中はpodman run
は不要になり、終了する可能性がありますが、コンテナーからの切り離しを要求しなかったため、オンラインのままです。
次に、podman
はcgroupを使用してコンテナーを制限します。これは、新しいコンテナーの新しいcgroupを作成し、そこにプロセスを移動することを意味します。 cgroupのルールにより、プロセスは一度に1つのcgroupのみのメンバーになることができ、プロセスを一部のcgroupに追加すると、同じ階層内の他のcgroup(以前の場所)から削除されます。したがって、コンテナが開始されると、cgroupの最終レイアウトは次のようになります。podman run
は、systemd
によって作成されたbaz.service
のcgroupに残り、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の終了後に生成されます。
お役に立てれば。