
sleep
もちろん、ほとんどの複雑なプロセスの代わりとなります。
この Dockerfile では (exec 形式を使用すると、実行中のプロセスが 1 つだけになり、子プロセスがなくなることがわかりますbash
)、
FROM busybox
CMD ["/bin/sleep", "100000"]
中断不可能なコンテナを作成します:
docker build -t kill-sleep .
docker run --rm --name kill-sleep kill-sleep
それを止めようとすると:
time docker stop kill-sleep
kill-sleep
real 0m10.449s
user 0m0.021s
sys 0m0.027s
コマンドはコンテナが強制終了される 10 秒前にタイムアウトします。
問題はsleep
シグナルを処理しないことではありません。ホスト上で実行すると次のようになります。
sleep 100000
# in another shell
ps faxww | grep sleep
kill -TERM 31333 # the PID
プロセスは直ちに停止します。
この問題は、コンテナ内で PID 1 として実行されていることに関係している可能性がありますが、そのことに関するリファレンス ドキュメントはまだ見ていません。
答え1
実行するとdocker stop ...
、いくつかのことが起こるだろう:
docker
はコンテナのメインプロセスに送信しますSIGTERM
。プロセスは をマスク/無視することができSIGTERM
、そうした場合(または終了せずに処理した場合)は "何もない" 起こります。- タイムアウト後 (デフォルトは 10 秒)、メイン プロセスに を
docker
送信しますSIGKILL
。このシグナルはプロセスによってマスクできないため、シャットダウン プロシージャを実行する機会がなく、すぐに終了します。
理想的には、内部で実行されるプロセスは、終了する前にハウスキーピングを処理しながら、タイムリーにdocker
応答します。SIGTERM
プロセスに実行するハウスキーピングがない (例: sleep
) か、プロセスが に適切に応答しないことがわかっている場合はSIGTERM
、フラグを使用して、より短い (またはより長い) タイムアウトを指定できます-t
。
-t, --time=10 Seconds to wait for stop before killing it
たとえば、あなたの場合は、 を実行するとよいでしょうdocker stop -t 0 ${CONTAINER}
。
この信号の動作が異なる理由は、sleep
PID = 1 で実行されているためです。
通常 (例: PID != 1 で実行)、プロセスが明示的に処理しないシグナルは、プロセスの終了につながります。 a を送信してみてsleep
くださいSIGUSR1
。
ただし、PID = 1 で実行する場合、未処理のシグナルは無視されます。そうしないと、カーネル パニックが発生します。
Kernel panic - not syncing: Attempted to kill init!
たとえば、docker ツールを使用して、docker コンテナにシグナルを送信できます。
docker kill -s TERM kill-sleep
ご覧のとおり、これは望ましい効果をもたらしませんが、次の場合は望み通りの効果が得られます。
docker kill -s KILL kill-sleep
実験
Dockerファイル
FROM busybox
COPY run.sh /run.sh
RUN chmod +x /run.sh
CMD "/run.sh"
実行.sh
#!/bin/sh
echo "sleeping"
sleep 100000
さあ、走れ
docker build -t kill-sleep .
docker run --rm --name kill-sleep kill-sleep
別のターミナルでは次のようになります:
docker stop kill-sleep
同じ 10 秒の遅延 / タイムアウトが観察されます。
解決策
さて、 を扱いましょうSIGTERM
。 のバックグラウンド化とwait
はsleep
、POSIXシェルがシグナルを処理する方法によるものです(これ多くのための)。
実行.sh
#!/bin/sh
die_func() {
echo "oh no"
sleep 2
exit 1
}
trap die_func TERM
echo "sleeping"
sleep 100000 &
wait
コマンドをもう一度実行すると、目的がわかります。
$ time docker stop kill-sleep
kill-sleep
real 0m2.515s
user 0m0.008s
sys 0m0.044s
答え2
その他のオプション:
- コンテナの実行コマンドにスイッチを追加します
--init
。これにより、sleep は PID 1 ではなくなり、init は TERM で適切な処理を実行します。 - コンテナの実行コマンドに を追加します
--stop-signal=KILL
。ただし、KILL を通常の操作として使用することは一般的に推奨されません。