🛩️

Passenger の CLI がたまにこける問題と正しい解決方法

2023/04/30に公開

環境

  • macOS Ventura
  • Apache 2.4.56
  • Passenger 6.0.17
  • Capistrano 3.17.2

目的

deploy ユーザーで localhost に対して Capistrano でデプロイする。

問題点

passenger-config コマンドがエラーになって Passenger を再起動できない。

エラー内容

ERROR: Phusion Passenger(R) doesn't seem to be running. If you are sure that it is running, then the causes of this problem could be:

1. You customized the instance registry directory using Apache's PassengerInstanceRegistryDir option, Nginx's passenger_instance_registry_dir option, or Phusion Passenger(R) Standalone's --instance-registry-dir command line argument. If so, please set the environment variable PASSENGER_INSTANCE_REGISTRY_DIR to that directory and run passenger-status again.
2. The instance directory has been removed by an operating system background service. Please set a different instance registry directory using Apache's PassengerInstanceRegistryDir option, Nginx's passenger_instance_registry_dir option, or Phusion Passenger(R) Standalone's --instance-registry-dir command line argument.

ChatGPT の翻訳:

エラー:Phusion Passenger(R) が実行されていないようです。実行されていることが確認できている場合、この問題の原因は以下のとおりである可能性があります:

  1. Apache の PassengerInstanceRegistryDir オプション、Nginx の passenger_instance_registry_dir オプション、または Phusion Passenger(R) Standalone の --instance-registry-dir コマンドライン引数を使用して、インスタンスレジストリディレクトリをカスタマイズしました。それがそうである場合、環境変数 PASSENGER_INSTANCE_REGISTRY_DIR をそのディレクトリに設定して、再度 passenger-status を実行してください。
  2. 操作システムのバックグラウンドサービスによってインスタンスディレクトリが削除されました。別のインスタンスレジストリディレクトリを Apache の PassengerInstanceRegistryDir オプション、Nginx の passenger_instance_registry_dir オプション、または Phusion Passenger(R) Standalone の --instance-registry-dir コマンドライン引数を使用して設定してください。

原因

Passenger の情報があるディレクトリを passenger-config が見つけられないため。

詳細

  • 自分ユーザーでは passenger-status や passenger-config (以降 CLI と呼ぶ) は動く
  • Passenger の情報は ${TMPDIR}passenger.* のなかにある
  • deploy ユーザーに切り替えると CLI が動かなくなる
  • sudu -u 自分ユーザー passenger-status でも動かない

対策

/usr/local/etc/httpd/other/passenger.conf
  LoadModule passenger_module /opt/rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/passenger-6.0.17/buildout/apache2/mod_passenger.so
  <IfModule mod_passenger.c>
    PassengerRoot /opt/rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/passenger-6.0.17
    PassengerDefaultRuby /opt/rbenv/versions/3.2.2/bin/ruby
+   PassengerInstanceRegistryDir /tmp
  </IfModule>
apachectl restart
  • Apache 側で PassengerInstanceRegistryDir を指定する
  • 任意のディレクトリではなく必ず /tmp にする
    • 理由は後述
  • /tmp/passenger.* が作成されたのを確認したら次へ進む

CLI 動作確認

passenger-status
sudo -u deploy passenger-status

自分と deploy ユーザーの両方でエラーにならないのを確認する。これが通れば passenger-config restart-app /var/www/xxx-app --ignore-app-not-running も通る。

PASSENGER_INSTANCE_REGISTRY_DIR は定義しなくてよい

~/.zshenv
export PASSENGER_INSTANCE_REGISTRY_DIR=/tmp

や、

deploy.rb
set :default_env, {
  "PASSENGER_INSTANCE_REGISTRY_DIR" => "/tmp",
}

は必要ない。昔は必要だったのかもしれないけど今は CLI が /tmp を探す。

CLI はどこを探しているのか?

https://github.com/phusion/passenger/blob/213c9a0669ada9defd045151feaf96fe6027de59/src/ruby_supportlib/phusion_passenger/admin_tools/instance_registry.rb#L94-L110

  1. PASSENGER_INSTANCE_REGISTRY_DIR
  2. TMPDIR
  3. /tmp
  4. /var/run/passenger-instreg
  5. /tmp/systemd-private-*-{httpd,nginx,apache2}.service-*/tmp

の順に探している。

だから任意の場所にするよりCLIが想定している場所を使った方がシンプルになる。

何もしなくても動く場合がある理由

PassengerInstanceRegistryDir を指定しなくても動く場合がある。その理由は PassengerInstanceRegistryDir の指定がないとき TMPDIR の指すディレクトリが指定されているものとして Passenger が動作するから。

$ echo $TMPDIR
/var/folders/9c/_62dfc8502g_d5r05zyfwlxh0000gp/T/

であれば、

/var/folders/9c/_62dfc8502g_d5r05zyfwlxh0000gp/T/passenger.*

に書き込まれている。そして CLI も TMPDIR を探すから動く。ただし TMPDIR に依存する方法は脆い (続く)

deploy ユーザーに変更すると動かない理由

何もしなくても動いていたのに deploy ユーザーに変更すると動かなくなる場合がある。こうなると自分ユーザーではコマンドラインから Passenger を再起動できるのに Capistrano でデプロイすると失敗するという状況になる。

この原因は deploy ユーザーに切り替えたとき TMPDIR が消えているから。sudo -u deploy env | grep TMPDIR で何も出なければ消えている。つまり動いたり動かなかったりするのは deploy ユーザーというよりは TMPDIR の有無に関係している。

この場合 visudo で、

Defaults env_keep += "TMPDIR"

を追加する。これで deploy ユーザーに切り替えても TMPDIR は維持されるので CLI は動く。

ただし TMPDIR の有無が Passenger 再起動の鍵を握っているとは想像つかないし、移行アシスタントで Mac をまるごとコピーすると /etc/sudoers は新しい Mac に転送されず、またハマることになるため、この TMPDIR に依存して /etc/sudoers をいじる方法は推奨しない。

/tmp のかわりに /var/run/passenger-instreg を使うと面倒なことになる

/var/run/passenger-instreg を使う場合は、

sudo mkdir /var/run/passenger-instreg

として、

/usr/local/etc/httpd/other/passenger.conf
  LoadModule passenger_module /opt/rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/passenger-6.0.17/buildout/apache2/mod_passenger.so
  <IfModule mod_passenger.c>
    PassengerRoot /opt/rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/passenger-6.0.17
    PassengerDefaultRuby /opt/rbenv/versions/3.2.2/bin/ruby
+   PassengerInstanceRegistryDir /var/run/passenger-instreg
  </IfModule>

としてから、

apachectl stop
sleep 1
apachectl start

とする。

  • 設定の反映はなぜか apachectl restart ではダメ
    • stop 直後に start すると /var/run/passenger-instreg/passenger.* が作成されない
    • stop 後に1秒ぐらい待ってから start すれば作成される
  • /var/run/passenger-instreg/passenger.* があるのを確認する

core_api にアクセスできない場合

$ passenger-status
/opt/rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/passenger-6.0.17/src/ruby_supportlib/phusion_passenger/admin_tools/instance.rb:94:in `initialize': Permission denied - connect(2) for /var/run/passenger-instreg/passenger.8OqbnUO/agents.s/core_api (Errno::EACCES)

となる場合はオーナーや権限が次のようになっているか確認する。

$ ls -al /var/run/passenger-instreg
drwxr-xr-x  3 root daemon   96  4 30 12:20 .
drwxrwxr-x 38 root daemon 1.2K  4 30 12:19 ..
drwxr-xr-x 12 root wheel   384  4 30 12:20 passenger.G80V8W5
$ ls -al /var/run/passenger-instreg/passenger.G80V8W5/agents.s
total used in directory 0 available 478.2 GiB
srw-rw-rw-  1 root wheel   0  4 30 12:20 core
srw-rw-rw-  1 root wheel   0  4 30 12:20 core_api
srw-rw-rw-  1 root wheel   0  4 30 12:20 watchdog_api

その原因は?

Apache を再起動すると /var/run/passenger-instreg の中が自分のオーナーで作成されていて、それに影響してなのか core_api も参照できない権限になっていて、これで CLI がアクセスできなくなることがあった。

その後 /var/run/passenger-instreg を作り直したり Apache を apachectl stopapachectl start しているうちに直ってしまった。

結局、何が原因でおかしくなったのかはわからない。

PCを再起動すると動かなくなる

  • PCを再起動すると /var/run/* は消える
  • なので /var/run/passenger-instreg も消えている
  • Passenger は /var/run/passenger-instreg を自動的に作らない
    • PassengerInstanceRegistryDir で指定しているのだからそのくらいやってほしい(小声)
  • 起動時に /var/run/passenger-instreg を作る方法は /Library/LaunchDaemons 以下にその処理を書いた plist を用意して sudo launchctl load なんとか.plist すればよさそうだけど、そんな面倒なことをするぐらいなら /var/run/passenger-instreg を使わず /tmp にしておけばいい

この問題が顕著になった過程

  1. 当初はアプリ内に tmp/restart.txt を置くだけで再起動していた
  2. つまり CLI と Passenger の結び付きがなくても再起動に関しては何も問題なかった
  3. ところが2014年ごろのバージョン 5 ぐらいから状況は一変した
  4. tmp/restart.txt を置くのではなく CLI から指示する方法が推奨となった
  5. となると CLI と Passenger が結び付かないと再起動できなくなった
  6. そこで CLI と Passenger が結び付いていない場合の問題が顕著になった

まとめ

  • ひとことで言えば
    PassengerInstanceRegistryDir /tmp だけを追加せよ
  • /var/run/passenger-instreg は使うな
    • 理由: 再起動するとディレクトリが消えるから
  • デフォルトのまま使うな
    • 理由: ユーザーを切り替えると TMPDIR がなくなるから
  • PASSENGER_INSTANCE_REGISTRY_DIR は定義するな
    • 理由: CLI が想定の場所を探し回ってくれるから

Discussion