Rails 服务器仍然 运行 在新打开的 docker 容器中

Rails server is still running in a new opened docker container

我想使用 Docker 部署我的 rails 项目。所以我使用 Docker-Compose。但是我收到一条奇怪的错误消息。当 运行 docker-compose up(这包含带有 postgresql 的 db-container,带有 rails 的 redis 和 web 容器)我得到一个

web_1 | => Booting Puma web_1 | => Rails 4.2.4 application starting in production on http://0.0.0.0:3000 web_1 | => Runrails 服务器-hfor more startup options web_1 | => Ctrl-C to shutdown server web_1 | A server is already running. Check /usr/src/app/tmp/pids/server.pid. web_1 | Exiting 所以我不明白为什么会收到此消息,因为每次我 运行 docker-compose 时,都会启动新容器,而不是以前的容器。即使想删除这些 server.pid 我也做不到,因为这个容器不是 运行ning。

我的docker-compose.yml文件

web:
  dockerfile: Dockerfile-rails
  build: .
  command: bundle exec rails s -p 3000 -b '0.0.0.0'
  ports:
    - "80:3000"
  links:
    - redis
    - db
  environment:
    - REDISTOGO_URL=redis://user@redis:6379/

redis:
  image: redis

db:
  dockerfile: Dockerfile-db
  build: .
  env_file: .env_db

Docker文件-rails

FROM rails:onbuild

ENV RAILS_ENV=production

我认为我不需要 post 我所有的 Docker 文件

更新:我自己修复了它:我刚刚删除了我所有的容器和 运行 docker-compose up 再一次

您使用的是 onbuild 映像,因此您的工作目录安装在容器映像中。这对开发非常有用,因为当您编辑代码时,您的应用程序会实时更新,并且您的主机系统也会更新,例如当您 运行 迁移时。

这也意味着每次服务器 运行ning 时,您的主机系统 tmp 目录将与 pid 文件一起写入,如果服务器未正确关闭,它将保留在那里。

只需 运行 来自主机系统的此命令:

sudo rm tmp/pids/server.pid 

例如,当您在 docker-compose 下使用 foreman 时,这可能是一个真正的痛苦,因为仅按 ctrl+c 不会删除 pid 文件。

对于那些在 tmp/pids/server.pid 实际不存在时遇到问题的人:

(Docker 版本 1.11.2,构建 b9f10c9)

  1. 对我有用的解决方案是将确切的命令添加到 docker-compose.yml,例如:

    command:
       rails s -b0
    

    有这个命令,实际上可能只是复制 Docker 文件的 CMD - 陈旧的问题 .pid 不会出现。

  2. 其他选项,当你需要使用Docker文件的CMD时,是运行用选项--build重建图像:

    docker-compose up --build
    

    虽然比较费时间,但第一种方案比较方便

我被同样的问题难住了一段时间,直到我弄清楚到底发生了什么。真正的答案在下面……首先,您可能想在 docker-compose.yml 文件中尝试类似以下命令:

command: /bin/sh -c "rm -f /rails/tmp/pids/server.pid && rails server puma"

(我使用 Alpine 和 busybox 来保持体积小,所以没有 bash!但是 -c 也可以与 bash 一起使用)这将删除文件(如果存在)以便您不会遇到容器不断退出并坐在那里无法执行 运行 命令的问题。

不幸的是,这不是一个好的解决方案,因为您在服务器之前添加了额外的 /bin/sh 层,这会阻止服务器获得停止命令。结果是 docker 停止命令不会正常退出,问题总是会发生。

您可以 运行 rm 命令使用 docker-compose 删除文件,然后将命令更改回服务器并继续。

然而,真正的答案是创建一个简单的 docker-entry.sh 文件并确保使用 exec 形式调用它 Entrypoint Documentation 以便信号(如停止)得到到服务器进程。

#!/bin/sh
set -e

if [ -f tmp/pids/server.pid ]; then
  rm tmp/pids/server.pid
fi

exec bundle exec "$@"

注意:我们在最后一行使用 exec 来确保 rails 将 运行 作为 pid 1(即没有额外的 shell),从而获得停止信号.然后在 Dockerfile(或 compose.yml)文件中添加入口点和命令

# Get stuff running
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["rails", "server", "puma"]

同样,您必须使用 [] 格式,以便执行它而不是 运行 as sh -c ""

我所做的,是继续 docker 的 bash shell:

docker-compose run web /bin/bash

然后删除以下文件

rm tmp/pids/server.pid

希望对您有所帮助!

如果您喜欢冒险,请随时在代码库中搜索 server.pid 并检查 pid 写入的位置。这样你就可以检查是否不允许它写入为你修复根本问题。因为看似 pid 创建有助于防止您 运行 在两个不同的 docker 容器中设置重复服务。但这应该在 docker 中按原样处理。如果出于某种原因,它没有,端口冲突方法肯定会处理并提醒您。注意:我还没有尝试过这种方法,因为它通常会移动系统:)

或者,您可以在 Makefile 中包含命令。任务执行此操作的位置:

任务:
docker-撰写停止service_name
docker-撰写 rm service_name
rm -f ./tmp/pids/server.pid(或您的 pid 文件的相对路径名)
docker-撰写service_name

然后在终端中输入 vrooom make task 并按回车键。 上述任务命令假定您要 运行 的服务位于名为 docker-compose.yml

的文件中

如果名称不同则命令

docker-compose stop service_name --> docker-compose -f your-compose-filename.yml stop service_name

等等等等。

==================== 回来更新这个。所以,我确实尝试注释掉我的 write_pid 方法功能。基本上保留方法定义,但不让它做任何事情。到目前为止它运作良好。它根本不写 pid。如果您 运行 在 docker 中使用您的服务,我相信这是完全安全的。

我的工作:

docker-compose run web bash

然后使用命令 cd 逐个文件夹(我使用的是 win 7 工具箱) 所以最后我在 bash 中使用 :

rm tmp/pids/server.pid

在您的 docker-compose.yml 文件中,在应用程序容器本身下,您可以使用:

command: ["rm /your-app-path/tmp/pids/server.pid && bundle exec bin/rails s -p 3000 -b '0.0.0.0'"]

command: ["rm /your-app-path/tmp/pids/server.pid; foreman start"]

“;”的原因或“&&”是如果rm找不到文件,后者将发送退出信号,迫使您的容器过早停止。之前的会继续执行。

首先为什么会这样?原因是如果服务器(puma/thin/whatever)没有干净退出,它会在导致退出错误的主机。

这是

改编的版本

Docker 编写解决方案

1。创建docker-entrypoint.sh

#!/bin/bash
set -e

if [ -f tmp/pids/server.pid ]; then
  rm tmp/pids/server.pid
fi

exec bundle exec "$@"

2。调整你的 docker-compose.yml

services:
  web:
    build: .
    entrypoint: /myapp/docker-entrypoint.sh
    command: ["rails", "server", "-b", "0.0.0.0"]
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"

请注意,您必须提供安装应用程序的路径,即:/myapp

2.5如果遇到权限错误

运行 在您的终端 before 运行 docker-compose up 或构建您的图像。谢谢sajadghawami.

chmod +x docker-entrypoint.sh

3。享受无需再次手动删除 server.pid

如果您的解决方案是使用 rm 删除入口点上的 pid 文件,我认为更好的解决方案是告诉 rails 将 pid 文件写入临时路径,例如:

web:
   command: bundle exec rails server -b '0.0.0.0' -p 3000 -P /tmp/rails.pid 

不过大多数时候是因为一个docker容器还是运行造成的,我用的是:

$ docker stop $(docker ps -aq)

这将停止所有 运行 容器。此 -a 用于所有 -q 安静(仅)容器 ids

我在尝试 运行 docker 一组容器时遇到了这个问题。

问题是我从中部署容器的目录有一个服务器 运行ning 被杀死,但它在被杀死时没有删除 tmp/pids/server.pid 文件。所以每次我部署时,它都在那里。

因此,如果这不是您的问题,@Brendon Whatley 和@davegson 的回答可能是必要的。但如果是的话,你也许可以为自己省去一些痛苦。