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
(我没有用java
和ubuntu
镜像来试用),你会发现你的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 ...
看到这个美好的博客文章