SIGTERM不被java进程使用'docker stop'和官方的java映像接收

我正在使用基于debian/jessie的图像java:7u79在Docker容器中运行dropwizard Java应用程序。

我的Java应用程序处理SIGTERM信号以正常closures。 当我运行没有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 ... 

当你现在input容器并列出进程,例如通过docker exec -it <containerName> ps AHf (我没有用javaubuntu镜像来试用),你会发现你的Java进程不是根进程(不是使用PID进行处理1)而是/bin/sh进程的subprocess:

 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 ... 

所以基本上你有一个Linux shell,它是PID 1的主进程,它有一个带有PID 8的subprocess(Java)。

为了让信号处理正常工作,应该避免使用shell父进程。 这可以通过使用内置shell命令exec来完成。 这将使subprocess接pipe父进程。 所以最后的父母过程不再存在了。 并且subprocess成为PID的进程1.在Dockerfile尝试以下Dockerfile

 CMD exec java -jar ... 

stream程清单应该显示如下内容:

 UID PID PPID C STIME TTY TIME CMD root 1 0 0 18:30 ? 00:00:00 java -jar ... 

现在,您只有一个PID为1的进程。通常,一个好的做法是让docker容器只包含一个进程 – 具有PID 1的进程(或者如果您真的需要更多的进程,那么您应该使用例如supervisord作为PID 1,关心其subprocess的信号处理)。

使用该设置, SIGTERM将被Java进程直接处理。 在两者之间没有任何壳程可能会破坏信号处理。

编辑

同样的exec效果可以通过使用不同的CMD语法来实现(这要感谢Andy的评论):

 CMD ["java", "-jar", "..."] 

@ h3nrik答案是正确的,但有时你真的需要使用脚本来设置启动。 在大多数情况下,只需使用exec命令就可以实现:

 #!/bin/sh #--- Preparations exec java -jar ... 

看到这个美好的博客文章