我有一个 Rails 5 应用程序,运行在 puma 3.12.1、MRI 2.6.2 和 Ubuntu 18.04 上。它曾经使用pumactl
自定义控制脚本运行,但我想使用 systemd 正确配置它,使用套接字激活来实现零停机部署。
问题是套接字持有端口并且 puma 想要绑定到同一个端口,因此出现此错误:
/opt/myapp/shared/vendor/ruby/2.6.0/gems/puma-3.12.1/lib/puma/binder.rb:273:in `initialize':
Address already in use - bind(2) for "0.0.0.0" port 3000 (Errno::EADDRINUSE)
我按照彪马文档和systemd 文档。
我当然重新加载了 systemd 配置,并尝试重新启动了几次。我不太了解 systemd 如何进行套接字激活,但对我来说,puma 的错误消息似乎是合理的 :/
也许 puma 不应该尝试绑定到该端口?但是我该如何与 puma 通信以不绑定到它而是使用 systemd 的转发流?
我的配置:
$ cat /etc/systemd/system/puma.socket
[Unit]
Description=Puma HTTP Server Accept Sockets
[Socket]
ListenStream=0.0.0.0:3000
# Socket options matching Puma defaults
NoDelay=true
ReusePort=true
Backlog=1024
[Install]
WantedBy=sockets.target
$ cat /etc/systemd/system/puma.service
[Unit]
Description=API with Puma server
After=network.target
Requires=puma.socket
[Service]
Type=simple
WorkingDirectory=/opt/myapp/current
ExecStart=/opt/myapp/current/script/bootup_puma
SyslogIdentifier=api-puma
PIDFile=/opt/myapp/current/tmp/pids/puma.pid
Restart=no
TimeoutSec=30
User=ubuntu
[Install]
WantedBy=multi-user.target
$ cat script/bootup_puma
#!/bin/bash
# [setting up some envvars here]
bundle exec puma -C config/puma.rb
$ cat config/puma.rb
# frozen_string_literal: true
app_dir = File.expand_path("..", __dir__)
workers ENV.fetch("API__PUMA_WORKERS", 4).to_i
threads 1, ENV.fetch("RAILS_MAX_THREADS", 8).to_i
bind "tcp://0.0.0.0:#{ENV.fetch('PORT', 3000)}"
pidfile "#{app_dir}/tmp/pids/puma.pid"
directory ENV.fetch("API__PUMA_DIRECTORY") unless ENV.fetch("RAILS_ENV", "development") == "development"
出于绝望的尝试,我还尝试使用 unix 套接字而不是 TCP,但尽管我小心不通过符号链接引用套接字,但最终仍然出现了类似的错误。
/opt/myapp/shared/vendor/ruby/2.6.0/gems/puma-3.12.1/lib/puma/binder.rb:367:in `add_unix_listener':
There is already a server bound to: /opt/myapp/shared/tmp/puma.sock (RuntimeError)
我已经浏览过的其他有用资源:
答案1
问题在于中间 shell 脚本,bootup_puma
正如 Micheal Hampton 在评论。
将服务更改为
ExecStart=/opt/myapp/current/bin/puma -C config/puma.rb
并为环境提供EnvironmentFile
指令解决了该问题。