そのねこが学ぶとき

ブログ移行しました→ http://chroju.github.io

Railsのデプロイでハマった点まとめ

昨年末に自身初のRailsアプリを見切り発車という名でローンチしましたが、その際デプロイで1か月以上もハマってましたので、ハマリポイントをピックアップしてまとめておきます。

Capistranossh-agentを使う

Capistrano3のタスクの中に、git cloneレポジトリをダウンロードしてくる過程があるのだが、ここではもちろん、GitHub(他のサービス使ってる場合は他の)にアクセスするためのssh秘密鍵が必要になる。ここで利用する秘密鍵ssh先のサーバーに置いておいても良いのだが、Capistrano3ではssh agent forwardingを使えるようにするための設定箇所が存在するので、リモートに鍵をわざわざ転送しなくても、ローカルの鍵が使える。設定箇所はdeploy/(test|staging|production).rbの中で、サーバー設定を書くときに以下のようにforward_agenttrueで宣言すればいい。

server '192.168.1.1', port: 2222, user: 'develop', roles: %w{web app db}, ssh_options: {
  keys: %w(~/.ssh/id_rsa),
  forward_agent: true,
  auth_methods: %w(publickey)
}

サブディレクトリでアプリを展開する場合の環境変数設定

例えば/var/wwwがnginxの見に行くルートディレクトリになっていて、Railsのアプリは/var/www/railsで展開しているというように、サブディレクトリを使う場合はRails側に環境変数RAILS_RELATIVE_URL_ROOTの設定が必要になる。Railslink_toなどを展開してパスを埋め込むときは、このroot設定が元になるので、サブディレクトリを使っていることを環境変数上で明記してやらなければ、本来http://example.com/rails/hogeへのリンクを展開してほしいはずが、http://example.com/hogeが展開される、といったことになってしまう。設定箇所としてはconfig.ruになる。

ENV["RAILS_RELATIVE_URL_ROOT"] = "/rails"

if ENV['RAILS_RELATIVE_URL_ROOT']
  map ENV['RAILS_RELATIVE_URL_ROOT'] do
    run Rails.application
  end
else
  run Rails.application
end

はっきり言ってconfig.ruが何者なのかよくわかってはいないのだが、Rackサーバーを起動するrackupコマンドに起動オプションを渡したりするもの、らしい。そのことについてはconfig.ruの先頭行にコメントでも入っているのでなんとなくわかると思う。が、Rackが理解できてないので結局のところわからない。コマンドは意味から考えれば、Railsを起動するときにパスのマッピングとしてRAILS_RELATIVE_URL_ROOTを渡してやっているように見える。ただ、この書き方だと環境変数の宣言をconfig.ruの中で行った上で、その環境変数の存在をifで確認するというちょっとマヌケなロジックになってしまっているので、おそらくは環境変数を別のところで宣言するのがベターなのだと思う。

なお、サブディレクトリでRailsアプリを立ち上げるには、ウェブサーバー(nginx + unicorn)に対しても設定が必要だが、ここでは割愛。nginxのlocationディレクティブを使う、とだけ覚えておけばなんとかなるはず。

参考

assetsに対するルーティング設定

assets:precompileを使ってあらかじめassetsフォルダ内にcssとjsを展開していたのだが、ブラウザ経由でいざアプリにアクセスすると、CSSJavaScriptも適用されていない(assets配下が読み込めていない)という事象が発生した。

原因はルーティングが正しくなかったから。前述の通りExhiBiでは/var/www/railsにアプリを展開していたのだが、さらに細かく見るとrailsフォルダの中にはreleasescurrentsharedという主に3種類のフォルダが配置される。releasesは要するにgit cloneの対象フォルダで、ソースコードCapistranoで宣言した数だけバージョン管理している。sharedはbundleやlogといった、リリースバージョンに左右されず不変のファイルを格納する場所で、Capistranoで言えばlinked_dirsにあたる。この2つのフォルダをcurrent配下にシンボリックリンクすることにより、currentが実際のアプリ配置場所として機能する。従ってnginxのlocationディレクティブはこんな感じになる。

location /rails {
  alias /var/www/rails/current;
}

ここでassetsへのルーティングを考えてみると、assetsに対するパスはhttp://example.com/rails/assets/hogehogeになるため、/var/www/rails/current/assetsを見に行くことになる。しかし実際にはassetsはshared/public/assetsであり、シンボリックリンクcurrent/public/assetsに貼られている。そのため先のlocatonだけではassetsに到達することはできないため、assets用のlocationディレクトリが別途必要になる。

location ~ ^/rails/assets/(.*) {
  alias /var/www/rails/current/public/assets/$1;
}

参考

SECRET_KEY_BASEの環境変数設定

ブラウザ経由でアプリにアクセスしたら、404ではないのだが画面が真っ白になってしまう事象。ぐぐってみるとドンピシャすぎる記事があって大変助かった。

SECRET_KEY_BASEという環境変数を設定してやらねばならんらしい。なんじゃそりゃ。環境変数の設定なので方法は下記のURLのようにいくつかあるみたいだが、自分は取りあえずChefレシピの中で、.bash_profile環境変数設定をいれこむことにした。これも何かしらベストプラクティスがありそうな気がする。。

参考

gem 'pg'が入らない

入らない。なんか知らんが入らない。ググるとどうも入りづらいGemの筆頭である模様。いろいろ探って、therubyracerを先に入れるべきだと聴いてやってみたけど結局入らない。とにかくどうやっても、Capistranobundle installMake sure that gem install pg -v '0.17.1' succeeds before bundling.と言われてしまう。仕方ないのでsshでサーバーに直に入ってbundle installを手動実行してみるとなぜか入る。わからん。これだけは本当にわからん。さらにその後はtiltが入らないとか言われたりもした。ソースをrubygems.orgから変えたりしてなんとか入ったのだが、ちょっと腑に落ちない感。

参考

posgresqlのユーザー管理

SQLに関する基礎知識のなさを猛省した。とりあえずわかってなかったのこんなとこ。

  • pg_hba.confで指定できる認証方式でmd5はパスワード認証、peerはOSにログイン中のユーザー名でログインしようとする
    • よってsqlで使う予定のユーザー名がOS側に存在しない場合、peerを使おうとするとコケる
  • psqlコマンドでログインしたとき、まずユーザー名と同名のDBにアクセスしようとするので、それが存在しないとエラーになる
    • でもDB作成ってrake db:createでやると思うんだけど、このコマンド打つときはどうやってアクセスするの?あれ?
  • DBに初期データを投入したい場合はdb/seeds.rbに書いてrake db:seedを打つ
  • rake db:migrateはテーブル生成だけでデータ登録までは賄ってくれない
  • 開発段階でmigrateファイルをやたらと作ってたりすると上手くdb:migrateできないこともあるので、整理した方がいいかも

参考

RailsCapistranoのいずれも抽象度の高い技術で、これは何度かブログに書いてきてるけど、その内実をきちんと押さえてないとエラーが起きた場合に結構辛いことになる。READMEを読むこと、公式のWikiなどがあるならそっちも目を通すこと、エラーが起きたらログを見ること、あるいは前もってログを吐く設定にしておくこと。このあたりは改めて徹底したいところ。

あとここからは余談だが、Railsのデプロイ先としてherokuが好まれるのは、ある程度「間違いのない選択肢」ということなのだろうなと想像している。ここで自分がつまずいたサブディレクトリでのアプリ展開や、postgresqlのコンフィグなどは、herokuであれば必要がなくなる。一旦用意されている高速道路を全力で走ってみて、それが成功してから自分好みに変えていく方が近道なのかもしれない。なんとかしてposgresqlを使おうとこだわったり、サブディレクトリでの運用をさせたり、最初からいろいろ欲張りすぎた点も反省。