docker stopしたときにjavaのShutdownHookが呼び出されない

概要

以下の記事で作ったプログラムをdockerコンテナ上で実行して、docker stopしたときにShutdownHookが呼ばれない現象が発生した。

hkou.hatenablog.com

以下の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と同等の挙動にするには.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が呼び出されないのは以下の記事で確認している。

hkou.hatenablog.com

対策

#!/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