読者です 読者をやめる 読者になる 読者になる

UUUM攻殻機動隊

UUUMのエンジニアによる技術ブログです

RailsアプリをUnicornサーバー&Symlink切り替えデプロイ環境下で安定運用する

nazoです。

Railsアプリを本番で運用する際、アプリケーションサーバーは現在ではUnicornかPumaを使うことが多いと思います。特にPumaを使う方が多いと思いますが、現在のプロジェクトではUnicornで構築しております。

Webサーバーを安定運用させるには無停止で再起動するGraceful Restartは必須ですが、いくつか注意すべき点があったので、運用例と共に紹介したいと思います。

基本

Unicornの設定ファイルはこれをベースに行うことが多いと思いますので、その前提で説明します。

普通にGraceful Restartできるようにする

上記設定ファイルの、以下の部分を有効にすると、SIGHUPを受け取った際に緩やかに終了しながら再起動するようになります。

  # old_pid = "#{server.config[:pid]}.oldbin"
  # if old_pid != server.pid
  #   begin
  #     sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
  #     Process.kill(sig, File.read(old_pid).to_i)
  #   rescue Errno::ENOENT, Errno::ESRCH
  #   end
  # end

Dotenvが再読込されない問題

dotenvを使っている場合は、起動前にデータの再読込が必要です。

before_exec do |server|
  Dotenv.overload
end

ただし、古い環境変数が消えるわけではないので、環境変数を削除した場合でも残ってしまいます。削除するような運用はしないように注意が必要です。

systemdでPIDを見失う問題

systemdで起動している場合、PIDFileの指定をしておかないと、再起動してPIDが変わった時にPIDを検出できなくなって終了してしまいます。必ず指定しましょう。

PIDFile=/path/to/rails_root/tmp/pids/unicorn.pid

symlinkパスで古いパスを読み続ける問題

symlinkの切り替えでデプロイを行っている場合、Bundlerがsymlinkを展開したパスを常に保持してしまうため、いくらrestartしても古いパスを読み続けるようです。そのため、symlinkのパスをUnicornに教えてあげる必要があります。

以下の例では、環境変数 RAILS_ROOT に、symlinkでのパスを指定してある想定での設定例です。

rails_root = ENV["RAILS_ROOT"] || File.expand_path("../../", __FILE__)

working_directory rails_root
Unicorn::HttpServer::START_CTX[0] = File.join(rails_root, Bundler.settings.path, "bin/unicorn")

symlink切り替えデプロイは、Capistranoが有名ですが、私はstretcherのpost actionで自作のシェルスクリプトを流して実行しています。

まとめ

Webアプリケーションの安定運用にはGraceful Restartが必須ですが、サーバーの実装をちゃんと知っておかないと思ったように動かない可能性があります。必ず動作検証を行い、適切に再起動されているかを確認しましょう。