我使用基于debian / jessie的图像
java:7u79在Docker容器中运行dropwizard
Java应用程序.
我的Java应用程序处理SIGTERM信号正常关闭.当我运行没有Docker的应用程序时,SIGTERM处理功能非常完美.
当我在Docker容器中运行它时,当我发出docker stop命令时,SIGTERM不会到达Java应用程序. 10秒钟后,它会突然死亡.
我的Docker文件:
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中定义以下内容来启动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 ...
所以基本上你有一个Linux shell,它是PID 1的主要过程,它具有带有PID 8的子进程(Java).
要使信号处理正常工作,您应该避免这些shell父进程.这可以通过使用内置shell命令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.一般来说,一个很好的做法是使docker容器只包含一个进程 – 一个PID 1(或者如果你真的需要更多的进程,那么你应该使用例如supervisord
作为PID 1,它本身采取照顾其子进程的信号处理).
使用该设置,SIGTERM将被Java进程直接处理.没有任何shell进程之间可能会中断信号处理.
编辑:
通过使用不同的CMD语法来隐含地实现同样的执行效果(感谢Andy的评论):
CMD ["java","-jar","..."]