Java:7u79
に基づくイメージdebian/jessie
を使用して、Dockerコンテナでdropwizard Javaアプリケーションを実行しています。
私のJavaアプリケーションはSIGTERM
信号を処理して正常にシャットダウンします。Dockerなしでアプリケーションを実行すると、SIGTERM
処理は完全に機能します。
Dockerコンテナで実行すると、SIGTERM
がdocker stop
コマンドを発行したときにJavaアプリケーションに到達しません。10秒後にプロセスが突然終了します。
私のDockerfile
:
FROM Java:7u79
COPY dropwizard-example-1.0.0.jar /opt/dropwizard/
COPY example.keystore /opt/dropwizard/
COPY example.yml /opt/dropwizard/
WORKDIR /opt/dropwizard
RUN Java -jar dropwizard-example-1.0.0.jar db migrate /opt/dropwizard/example.yml
CMD Java -jar dropwizard-example-1.0.0.jar server /opt/dropwizard/example.yml
EXPOSE 8080 8081
これDockerfile
の何が問題になっていますか?この問題に取り組む他の方法はありますか?
Dockerfile
に次のように定義して、Javaサービスを起動するとします。
CMD Java -jar ...
コンテナーに入ってプロセスをリストすると、次のようになります。 docker exec -it <containerName> ps AHf
(Java
ではなくubuntu
イメージで試した)によって、Javaプロセスがルートではないことがわかりますプロセス(PID 1のプロセスではない)ではなく、/bin/sh
プロセスの子プロセス:
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 18:27 ? 00:00:00 /bin/sh -c Java -jar ...
root 8 1 0 18:27 ? 00:00:00 Java -jar ...
したがって、基本的には、PID 1のメインプロセスであるLinuxシェルに、PID 8の子プロセス(Java)があります。
シグナル処理を適切に機能させるには、これらのシェルの親プロセスを回避する必要があります。これは、組み込みのシェルコマンドexec
を使用して実行できます。これにより、子プロセスが親プロセスを引き継ぎます。したがって、最終的には以前の親プロセスは存在しなくなります。子プロセスはPID 1のプロセスになります。Dockerfile
で以下を試してください。
CMD exec Java -jar ...
プロセスリストは次のようになります。
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 18:30 ? 00:00:00 Java -jar ...
これで、PID 1のプロセスは1つだけになります。一般的には、Dockerコンテナーに1つのプロセス(PID 1のプロセス)のみを含めることをお勧めします(または、さらに多くのプロセスが必要な場合は、例 supervisord
PID 1として。子プロセスのシグナル処理を処理します)。
この設定では、SIGTERM
はJavaプロセスによって直接処理されます。信号処理を中断する可能性のあるシェルプロセスはもうありません。
[〜#〜]編集[〜#〜]:
同じexec
効果は、暗黙的にそれを実行する別のCMD
構文を使用して達成できます(コメントの Andy に感謝):
CMD ["Java", "-jar", "..."]
@ h3nrikの答えは正しいですが、起動を設定するためにスクリプトを使用する必要がある場合があります。 execコマンドを使用して、ほとんどの場合にトリックを実行します。
#!/bin/sh
#--- Preparations
exec Java -jar ...
この素晴らしい ブログ投稿をご覧ください