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 | => Run
rails 服务器-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)
对我有用的解决方案是将确切的命令添加到 docker-compose.yml
,例如:
command:
rails s -b0
有这个命令,实际上可能只是复制 Docker 文件的 CMD - 陈旧的问题 .pid
不会出现。
其他选项,当你需要使用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 的回答可能是必要的。但如果是的话,你也许可以为自己省去一些痛苦。
我想使用 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 | => Run
rails 服务器-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)
对我有用的解决方案是将确切的命令添加到
docker-compose.yml
,例如:command: rails s -b0
有这个命令,实际上可能只是复制 Docker 文件的 CMD - 陈旧的问题
.pid
不会出现。其他选项,当你需要使用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 的回答可能是必要的。但如果是的话,你也许可以为自己省去一些痛苦。