gpt4 book ai didi

java - 使用 'docker stop' 和官方 java 镜像的 java 进程未收到 SIGTERM

转载 作者:IT老高 更新时间:2023-10-28 12:37:48 34 4
gpt4 key购买 nike

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

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

当我在 Docker 容器中运行它时,当我发出 docker stop 命令时,SIGTERM 不会到达 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 ...

所以基本上你有一个 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 进程可以中断信号处理。

编辑:

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

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

关于java - 使用 'docker stop' 和官方 java 镜像的 java 进程未收到 SIGTERM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31836498/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com