重新启动Play应用程序Docker容器导致“此应用程序已在运行' - 不删除RUNNING_PID

时间:2015-02-05 18:29:26

标签: java playframework playframework-2.0 docker playframework-2.3

编辑:相关问题是discussed on Github,但在另一种部署模式下(Typesafe Activator UI而不是Docker)。

我试图模拟系统重启以验证Docker重启策略,该策略声明能够以正确的顺序重新运行容器。

我有一个用Java编写的Play框架应用程序。

Dockerfile如下所示:

FROM ubuntu:14.04
#
#  [Java8, ...]
#
RUN chmod +x /opt/bin/playapp
CMD ["/bin/bash"]

我使用$ docker run --restart=always -d --name playappcontainer "./opt/bin/playapp"启动它。

当我$ service docker stop && service docker restart时 然后$ docker attach playappcontainer控制台告诉我:

Play server process ID is 7
This application is already running (Or delete /opt/RUNNING_PID file)

修改:当我按照Play文档的建议将change the location of the file推荐给带有-Dpidfile.path=/var/run/play.pid的/var/run/play.pid时,结果相同。

Play server process ID is 7
This application is already running (Or delete /var/run/play.pid file).

所以:为什么当docker守护程序停止时,包含RUNNING_PID的文件没有被删除,重新启动并重新启动以前运行的容器?


当我$ docker inspect playappcontainer时,它会告诉我:

"State": {
    "ExitCode": 255,
    "FinishedAt": "2015-02-05T17:52:39.150013995Z",
    "Paused": false,
    "Pid": 0,
    "Restarting": true,
    "Running": true,
    "StartedAt": "2015-02-05T17:52:38.479446993Z"
},

虽然:

  

容器内的主进程将接收SIGTERM,之后   宽限期,SIGKILL。

来自Docker reference on $ docker stop

  

要杀死正在运行的Play服务器,只需将SIGTERM发送给   正确关闭应用程序的过程。

来自Play Framework documentation on stopping a Play application

5 个答案:

答案 0 :(得分:27)

我刚刚玩了一个Play!应用程序也遇到了这个问题 - 重启主机引起了Play!应用程序无法在其容器中启动,因为RUNNING_PID尚未删除。

在我身上发生了戏剧! application是其容器中唯一的进程,总是具有相同的PID,并由Docker处理,RUNNING_PID文件(据我所知)实际上并不需要。

因此,我通过放置

pidfile.path改为/dev/null
javaOptions in Universal ++= Seq(
  "-Dpidfile.path=/dev/null"
)

在我的项目的build.sbt中。它的工作原理 - 我可以重启主机(和容器)和我的Play!申请开始很好。

这种方法的吸引力在于它不需要改变sbt-native-packager生成图像本身的方式,只需要改变应用程序在其中运行的方式。

这适用于sbt-native-packager 1.0.0-RC2及更高版本(因为该版本包含https://github.com/sbt/sbt-native-packager/pull/510)。

答案 1 :(得分:5)

我根据答案和我在这个问题上的进一步工作,找出了一个可行的解决方法。如果我按如下方式启动容器,它们会在(非)预期停止/重启后启动。冲突的RUNNING_PID文件不会阻止容器重新启动。

$ sudo docker run --restart=on-failure:5 -d \
--name container my_/container:latest \
sh -c "rm -f /var/run/play.pid && ./opt/bin/start \
-Dpidfile.path=/var/run/play.pid"

它的作用是在运行二进制文件之前每次使用选项删除包含进程ID的文件,该文件放在特定的位置。

答案 2 :(得分:4)

我对码头工作者了解不多,但就我测试的情况而言,Play不会在停止服务器时删除RUNNING_PID。当我以prod模式部署我的应用并尝试通过Ctrl+DCtrl+C停止它时,它不会从项目目录中删除RUNNING_PID文件,因此我不得不手动将其删除。来自Play docs

  

通常这个(RUNNING_PID)文件放在你游戏的根目录中   项目,但建议你把它放在一个可能的地方   在重新启动时自动清除,例如/var/run

所以 - 除了手动删除 - 解决方法是更改​​RUNNING_PID的路径,并在每次服务器通过某个脚本启动时删除它。

$ /path/to/bin/<project-name> -Dpidfile.path=/var/run/play.pid

确保目录存在,并且运行Play应用程序的用户具有写入权限。

使用此文件,您可以使用kill命令停止应用程序,例如:

$ kill $(cat /var/run/play.pid)

您还可以尝试使用docker命令$ sudo docker rm --force redis

也许这可以帮助

Source1 Source2 Source3

答案 3 :(得分:4)

我遇到了完全相同的问题,并且每次容器运行时手动删除文件都会绕过它。 为了做到这一点,我在伴随文件“start.bash”中添加了我用来从SBT dist任务的结果开始播放过程,如下所示:

找到。 -type f -name RUNNING_PID -exec rm -f {} \;

希望它有所帮助。

答案 4 :(得分:0)

ctrl + c失败后,我遇到了同样的问题。我通过运行docker-compose down -v,然后当然运行docker-compose up解决了这个问题。 -v选项用于指示您要删除与容器关联的卷。也许docker-compose down就足够了。

以下是一些down选项的摘要: `

仅停止服务

docker-compose stop

停止并删除容器,网络。

docker-compose down

关闭并删除卷

docker-compose down --volumes

向下并删除图像

docker-compose down --rmi`