実験

実験

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 ...いくつかのことが起こるだろう:

  1. dockerはコンテナのメインプロセスに送信しますSIGTERM。プロセスは をマスク/無視することができSIGTERM、そうした場合(または終了せずに処理した場合)は "何もない" 起こります。
  2. タイムアウト後 (デフォルトは 10 秒)、メイン プロセスに をdocker送信しますSIGKILL。このシグナルはプロセスによってマスクできないため、シャットダウン プロシージャを実行する機会がなく、すぐに終了します。

理想的には、内部で実行されるプロセスは、終了する前にハウスキーピングを処理しながら、タイムリーにdocker応答します。SIGTERM

プロセスに実行するハウスキーピングがない (例: sleep) か、プロセスが に適切に応答しないことがわかっている場合はSIGTERM、フラグを使用して、より短い (またはより長い) タイムアウトを指定できます-t

-t, --time=10
    Seconds to wait for stop before killing it

たとえば、あなたの場合は、 を実行するとよいでしょうdocker stop -t 0 ${CONTAINER}


この信号の動作が異なる理由は、sleepPID = 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。 のバックグラウンド化とwaitsleep、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 を通常の操作として使用することは一般的に推奨されません。

関連情報