docker stopしたときにjavaのShutdownHookが呼び出されない
概要
以下の記事で作ったプログラムをdockerコンテナ上で実行して、docker stopしたときにShutdownHookが呼ばれない現象が発生した。
以下のDockerfileでイメージを作成, プログラムはシェルスクリプト経由で実行している。
FROM java:openjdk-8-alpine ADD ./SignalTest.class /work/ ADD ./entry.sh /work/ WORKDIR /work ENTRYPOINT ["./entry.sh"]
#!/bin/sh
java SignalTest
ホストマシンで確認
- docker stopした場合、メインプロセスにSIGTERMが投げられ、一定時間後にSIGKILLが投げられるらしい。
docker stopと同等の挙動にするには.shにSIGTERMを投げればよいということが分かった。
.shのPIDが分かるようにスクリプト内に「echo $$」を追加した。
シェルスクリプトを実行し、表示されたPIDに対してkill -15 5227
を実行したところ、シェルスクリプトの実行プロセスは終了したが子プロセスのjavaプログラムは起動したままの状態になっている。
$ ./entry.sh 5227 exec... exec... exec... Terminated $ exec... exec... exec... exec...
上記から、docker stopするとシェルスクリプトのプロセスにSIGTERMが投げられ終了したが、Javaプロセスは実行したまま経過し、一定時間後SIGKILLが投げられ強制終了したものと推測される。
SIGKILLではShutdownHookが呼び出されないのは以下の記事で確認している。
対策
#!/bin/sh echo $$ exec java SignalTest
ホストマシンで確認(対策後)
ホストマシンでシェルスクリプト実行し、kill -15 5276
したところShutdownHookが呼び出された。
$ ./entry.sh
5276
exec...
exec...
call shutdown hook
dockerコンテナで確認
docker stopでShutdownHookが呼び出されたことが確認できた。
# イメージ作成 sudo docker build -t signal-test . # コンテナ実行 $ sudo docker run -d -i -t signal-test 0ee5e6dc864076f07cd7e0508075474200d15edada5a81696dfa6ad0f1677de1 # ログ確認 sudo docker logs 0ee5e6dc864076f07cd7 1 exec... exec... exec... exec... # コンテナ停止 sudo docker stop 0ee5e6dc864076f07cd7 # ログ確認 $ sudo docker logs 0ee5e6dc864076f07cd7 1 exec... exec... exec... exec... exec... exec... call shutdown hook