【问题标题】:SIGTERM not received by java process using 'docker stop' and the official java image使用'docker stop'和官方java图像的java进程没有收到SIGTERM
【发布时间】:2015-08-05 15:18:29
【问题描述】:

我正在使用基于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 有什么问题?有没有其他方法可以解决这个问题?

【问题讨论】:

  • 您真的想在 docker build 期间(而不是在运行时)运行您的 DB 迁移吗?

标签: java docker dropwizard dockerfile


【解决方案1】:

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

CMD java -jar ...

当您现在进入容器并列出进程时,例如通过docker exec -it <containerName> ps AHf(我没有尝试使用java,而是使用ubuntu 图像)您看到您的Java 进程不是根进程(不是PID 1 的进程)而是@987654329 的子进程@进程:

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", "..."]

【讨论】:

  • 这是一个很好的答案,但如果他们使用具有 exec 格式的CMDENTRYPOINT 可能会更好,例如ENTRYPOINT ["java","-jar","..."] docs.docker.com/reference/builder/#entrypoint
  • 是的,感谢您指出这一点。我相应地更新了我的答案。
  • CMD ["java", "-jar", ...] 不适用于ENV 变量,但CMD exec java -jar 解决了我的问题:)
  • 我遇到了同样的问题,这个答案很有帮助。谢谢!
【解决方案2】:

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

#!/bin/sh

#--- Preparations

exec java -jar ...

看到这个精彩的blog post

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    • 2017-12-18
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 2011-02-26
    相关资源
    最近更新 更多