Unicornの設定ファイルを読み解く(Part1)

【結論】

Unicornを導入する際、設定ファイルの内容を
 コピペするだけだと、エラーが発生した際に
 対処しきれない場面が多々ある

・ riコマンドとは、Ruby のクラスやメソッドの
 ドキュメントを、コマンドラインで確認できる機能
 メソッドの仕様を読み解く際に重宝する


【目次】


【本題】

Unicornの設定ファイルの内容を理解したい

AWS(EC2)+Nginx+Unicorn+MySQL+Capistranoという構成で、
何度かアプリのデプロイを行っているのですが、
設定ファイルは毎度コピペなので、イマイチ理解ができていません。

それが原因で、デプロイ時のエラーに何度も躓いたことがありました。
unicornが起動しない(記述内容の誤り)
・エラーログの出力先が分からない などなど・・・

なので今回は設定ファイルの内容を読み解いていきたいと思います。

参考にする設定ファイル

今回は、何度かお世話になっている
下記の内容を読み解いていきたいと思います。

app_path = File.expand_path('../../../', __FILE__)

worker_processes 1

working_directory "#{app_path}/current"
listen "#{app_path}/shared/tmp/sockets/unicorn.sock"
pid "#{app_path}/shared/tmp/pids/unicorn.pid"
stderr_path "#{app_path}/shared/log/unicorn.stderr.log"
stdout_path "#{app_path}/shared/log/unicorn.stdout.log"

listen 3000
timeout 60

preload_app true
GC.respond_to?(:copy_on_write_friendly=) && GC.copy_on_write_friendly = true

check_client_connection false

run_once = true

before_fork do |server, worker|
  defined?(ActiveRecord::Base) &&
    ActiveRecord::Base.connection.disconnect!

  if run_once
    run_once = false # prevent from firing again
  end

  old_pid = "#{server.config[:pid]}.oldbin"
  if File.exist?(old_pid) && server.pid != old_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 => e
      logger.error e
    end
  end
end

after_fork do |_server, _worker|
  defined?(ActiveRecord::Base) && ActiveRecord::Base.establish_connection
end

riコマンドとは

今回、設定ファイルの内容を読み解くにあたり、
「riコマンド」を多用しました。

riコマンドとは、
Ruby がインストールされているとターミナルで実行可能になるコマンドです。
Ruby Interactive」の略で、Ruby のクラスやメソッドのドキュメントを
ターミナル上で確認できるという便利機能です。

アプリのパス指定

では、設定ファイルの一番上から順に読み解いていきます。
最初の一行はこちらです。

app_path = File.expand_path('../../../', __FILE__)


「File.expand_path('../../../', __FILE__)」を、「app_path」に代入していますが、
「File.expand_path('../../../', __FILE__)」が何をしているのか分かりません。

riコマンドで調べると、下記の様な内容でした。

= File.expand_path

(from ruby core)

File.expand_path(file_name [, dir_string] ) -> abs_file_name



Converts a pathname to an absolute pathname. Relative paths are
referenced from the current working directory of the process unless
dir_string is given, in which case it will be used as the starting
point. The given pathname may start with a ``~'', which expands to the
process owner's home directory (the environment variable HOME must be
set correctly). ``~user'' expands to the named user's home
directory.

File.expand_path("~oracle/bin") #=> "/home/oracle/bin"

A simple example of using dir_string is as follows.
File.expand_path("ruby", "/usr/bin") #=> "/usr/bin/ruby"

A more complex example which also resolves parent directory is as
follows. Suppose we are in bin/mygem and want the absolute path of
lib/mygem.rb.

File.expand_path("../../lib/mygem.rb", __FILE__)
#=> ".../path/to/project/lib/mygem.rb"

So first it resolves the parent of __FILE__, that is bin/, then go to
the parent, the root of the project and appends lib/mygem.rb.


上記から、簡単にメソッドの仕様をまとめました
相対パス絶対パスにして文字列で返す
・第二引数を指定した場合、第二引数で指定したディレクトリを相対パスの基準にする
・「__FILE__」は、コードが実行されたディレクトリを取得する

「__FILE__」で取得されるディレクト

まず、「__FILE__」で取得されるディレクトリを確認します。

Capistranoは自動デプロイの度に「releases」というディレクトリの中に
デプロイした日時のディレクトリを作成して、アプリケーションのファイルを配置します。
(前の状態に簡単に戻せる様に、上書きはしていない)

その配置したディレクトリの一番新しい日時のディレクトリに対して、
「current」ディレクトリからシンボリックリンクが張られます。

そしてアプリケーション起動時には、この「current」ディレクトリが実行されるので、
「__FILE__」で取得されるディレクトリは、「current」という事になります。

「../../../」で指定した相対パス

そして、第一引数で指定されている「../../../」についてですが、
「.../」は一つの上のディレクトリを指定する記述です。
「../../../」だと三階層上になるので、「current」ディレクトリだと
「var/www/アプリ名」が相対パスになります。

「app_path」の内容

そして「var/www/アプリ名」の絶対パスの文字列が「app_path」に代入されるので、
「app_path」の値は、「/var/www/アプリ名」になります。


長くなったので、続きは次回に回します。