SIGTERM未被使用“docker stop”和官方java映像的java进程接收

2022-09-01 01:29:02

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

我的 Java 应用程序处理正常关闭的信号。当我在没有 Docker 的情况下运行应用程序时,处理工作非常完美。SIGTERMSIGTERM

当我在 Docker 容器中运行它时,当我发出命令时,它不会到达 Java 应用程序。它会在10秒后突然杀死该过程。SIGTERMdocker stop

我: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


答案 1

假设您通过在 中定义以下内容来启动 Java 服务:Dockerfile

CMD java -jar ...

当您现在进入容器并列出进程时,例如通过(我没有尝试使用但带有图像),您会看到您的Java进程不是根进程(不是PID 1的进程),而是进程的子进程:docker exec -it <containerName> ps AHfjavaubuntu/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命令 来完成。这将使子进程接管父进程。因此,在最后,以前的父进程不再存在。子进程成为 PID 1 的进程。请在 您的 中尝试以下操作:execDockerfile

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 的进程(或者如果你真的需要更多进程,那么你应该使用例如,监督作为 PID 1,它本身负责其子进程的信号处理)。

通过该设置,Java进程将直接处理。两者之间没有更多的shell过程可能会破坏信号处理。SIGTERM

编辑

通过使用隐式执行的不同语法可以实现相同的效果(感谢Andy的评论):execCMD

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

答案 2

@h3nrik答案是正确的,但有时你真的需要使用脚本来设置启动。在大多数情况下,只需使用exec命令即可完成该操作:

#!/bin/sh

#--- Preparations

exec java -jar ...

查看这篇精彩的博客文章


推荐