Ruby-on-Rails

使用 Upstart 管理 Unicorn w/ rbenv + bundler binstubs w/ ruby -local-exec shebang

  • August 17, 2013

好吧,這正在融化我的大腦。這可能與我不太了解 Upstart 的事實有關。提前抱歉這個長問題。

我正在嘗試使用 Upstart 來管理 Rails 應用程序的 Unicorn 主程序。這是我目前的/etc/init/app.conf

description "app"

start on runlevel [2]
stop on runlevel [016]

console owner

# expect daemon

script
 APP_ROOT=/home/deploy/app
 PATH=/home/deploy/.rbenv/shims:/home/deploy/.rbenv/bin:$PATH
 $APP_ROOT/bin/unicorn -c $APP_ROOT/config/unicorn.rb -E production # >> /tmp/upstart.log 2>&1
end script

# respawn

這很好用——獨角獸的起步很好。不好的是,檢測到的 PID 不是 Unicorn master 的,而是一個sh程序的。這本身也不是那麼糟糕——如果我沒有使用自動獨角獸零停機部署策略的話。因為在我發送給我的獨角獸主人後不久-USR2,一個新的主人產生了,而舊的主人死了……這個sh過程也是如此。所以 Upstart 認為我的工作已經死了,如果我願意,我不能再重新啟動它restart或停止它。stop

我玩弄了配置文件,試圖將 -D 添加到 Unicorn 行(像這樣$APP_ROOT/bin/unicorn -c $APP_ROOT/config/unicorn.rb -E production -D:)以守護 Unicorn,我添加了該expect daemon行,但這也不起作用。我也試過expect fork了。所有這些事情的各種組合都可能導致startstop掛起,然後 Upstart 對工作的狀態感到非常困惑。然後我必須重新啟動機器來修復它。

我認為 Upstart 在檢測 Unicorn 何時/是否分叉時遇到問題,因為我在腳本ruby-local-exec中使用了 rbenv + shebang 。$APP_ROOT/bin/unicorn這裡是:

#!/usr/bin/env ruby-local-exec
#
# This file was generated by Bundler.
#
# The application 'unicorn' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
 Pathname.new(__FILE__).realpath)

require 'rubygems'
require 'bundler/setup'

load Gem.bin_path('unicorn', 'unicorn')

此外,ruby-local-exec腳本如下所示:

#!/usr/bin/env bash
#
# `ruby-local-exec` is a drop-in replacement for the standard Ruby
# shebang line:
#
#    #!/usr/bin/env ruby-local-exec
#
# Use it for scripts inside a project with an `.rbenv-version`
# file. When you run the scripts, they'll use the project-specified
# Ruby version, regardless of what directory they're run from. Useful
# for e.g. running project tasks in cron scripts without needing to
# `cd` into the project first.

set -e
export RBENV_DIR="${1%/*}"
exec ruby "$@"

所以里面有一個exec讓我擔心的地方。它啟動了一個 Ruby 程序,它啟動了 Unicorn,它可能會或可能不會守護自己,這一切都首先發生在一個sh程序中……這讓我嚴重懷疑 Upstart 跟踪所有這些廢話的能力。

我想要做的甚至可能嗎?據我了解,expectUpstart 中的節只能被告知(通過daemonfork)期望最多兩個分叉。

確實,upstart 的一個限制是它無法跟踪執行 unicorn 正在做的事情的守護程序……即 fork/exec 並退出它們的主程序。信不信由你,sshd 在 SIGHUP 上做同樣的事情,如果你看,/etc/init/ssh.conf 確保 sshd 在前台執行。這也是 apache2 仍然使用 init.d 腳本的原因之一。

聽起來 gunicorn 在通過分叉然後退出接收 SIGUSR1 時實際上有點像守護程序。這對於任何試圖讓流程保持活力的流程管理器來說都是令人困惑的。

我認為你有兩個選擇。1 只是不使用 SIGUSR1 並在需要時停止/啟動 gunicorn。

另一種選擇是不使用 upstart 的 pid 跟踪,只需執行以下操作:

start on ..
stop on ..

pre-start exec gunicorn -D --pid-file=/run/gunicorn.pid
post-stop exec kill `cat /run/gunicorn.pid`

不像 pid 跟踪那麼性感,但至少您不必編寫整個 init.d 腳本。

(順便說一句,這與 shebangs/execs 無關。這兩件事都像執行正常執行檔一樣工作,因此它們不會導致任何額外的分叉)。

引用自:https://serverfault.com/questions/344989