【问题标题】:Restarting Play application Docker container results in 'This application is already running' - RUNNING_PID is not deleted重新启动 Play 应用程序 Docker 容器导致“此应用程序已在运行” - RUNNING_PID 未被删除
【发布时间】:2015-04-05 17:56:13
【问题描述】:

编辑:有一个相关问题是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 改为 /var/run/play.pid 和 -Dpidfile.path=/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

【问题讨论】:

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


    【解决方案1】:

    我对 docker 了解不多,但据我测试,Play 不会在停止服务器时删除 RUNNING_PID。当我在prod 模式下部署我的应用程序并尝试通过Ctrl+DCtrl+C 停止它时,它不会从项目目录中删除 RUNNING_PID 文件,因此我必须手动删除它。来自Play docs

    通常这个(RUNNING_PID) 文件放在你play的根目录下 项目,但是建议您将其放在合适的位置 重启时自动清除,如/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

    也许这会有所帮助

    Source1Source2Source3

    【讨论】:

    • 你好 singhakash,谢谢你的回答。我已经通过外部脚本开发了一种解决方法,该脚本在重新启动时杀死容器并重新启动它。但这对我来说并不令人满意。此外,正如您在我的问题中看到的那样,我已经更改了 RUNNING_PID 文件的位置。正如我在期望中指出的那样,我希望有一个重新启动的 Docker 容器,而不是杀死它然后再次运行它。它是更大基础设施的一部分,其他组件依赖于它的存在。
    【解决方案2】:

    我遇到了完全相同的问题,并通过每次容器运行时手动删除文件来解决它。 为了做到这一点,我在配套文件start.bash 中添加了我用来从 SBT dist 任务的结果开始播放过程的以下行:

    find . -type f -name RUNNING_PID -exec rm -f {} \;
    

    希望对你有帮助。

    【讨论】:

    • 嗨,朱利安,谢谢。实际上,我确实使用 star.sh 脚本来杀死和运行容器(应用程序是无状态的,所以这在数据方面不是问题)。但这有点脏。你知道有没有办法在每次重启时自动在容器内运行这条线?
    • 嗯...实际上这就是我打算用那条线做的。我的应用程序也是无状态的,所以每次容器启动时,都会删除这个 RUNNING_PID 文件并创建一个具有不同标识符的新文件。我知道这不是世界上最优雅的东西。到目前为止,我不知道有任何其他方式可以使用 docker 以更自然的方式完成同样的任务。
    • 但我们一致认为这不是 Docker 的不当行为,而是 Play 的不当行为,对吧?
    • 是的,我们肯定会这样做:)
    【解决方案3】:

    我根据答案和我在这个问题上的进一步工作整理了一个可行的解决方法。如果我按如下方式启动容器,它们将在(未)预期的停止/重新启动后启动。冲突的 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 的文件,该文件在每次运行二进制文件之前使用一个选项放置在特定位置。

    【讨论】:

      【解决方案4】:

      我刚刚对 Play 进行了 docker 化!应用程序并且也遇到了这个问题 - 重新启动主机导致播放!应用程序无法在其容器中启动,因为 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 这个解决方案对我有用。或者,在更新本机打包程序后,您可以添加一个 application.ini 文件,而不是在构建脚本中包含它。我选择了那个选项。
      • +1 我真的不明白为什么他们不能在每个新版本上都打破 Upstart 的情况下跟上。
      • 检查一下,在reference.conf/application.conf中设置pidfile.path=/dev/null就够了吗?
      • 我刚刚对其进行了测试,并且可以确认它在运行具有此类配置的容器时不会在 /opt/docker/RUNNING_PID 创建 RUNNING_PID 文件。但是,不同之处在于,像这样将其设置为 .conf 将使其适用于所有运行/部署模式(即使是那些需要 PID 文件的模式),而在 build.sbt 中执行此操作,由 in Universal 限定意味着它仅适用于 sbt-native-packager 部署。
      • 看来application.conf中也可以设置play.server.pidfile.path=/dev/null
      【解决方案5】:

      我在 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 <all|local>`
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-04
        • 1970-01-01
        • 2019-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-25
        • 1970-01-01
        相关资源
        最近更新 更多