昨年末に自身初のRailsアプリを見切り発車という名でローンチしましたが、その際デプロイで1か月以上もハマってましたので、ハマリポイントをピックアップしてまとめておきます。
Capistranoでssh-agentを使う
Capistrano3のタスクの中に、git clone
でレポジトリをダウンロードしてくる過程があるのだが、ここではもちろん、GitHub(他のサービス使ってる場合は他の)にアクセスするためのssh秘密鍵が必要になる。ここで利用する秘密鍵はssh先のサーバーに置いておいても良いのだが、Capistrano3ではssh agent forwardingを使えるようにするための設定箇所が存在するので、リモートに鍵をわざわざ転送しなくても、ローカルの鍵が使える。設定箇所はdeploy/(test|staging|production).rb
の中で、サーバー設定を書くときに以下のようにforward_agent
をtrue
で宣言すればいい。
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
の設定が必要になる。Railsがlink_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
ディレクティブを使う、とだけ覚えておけばなんとかなるはず。
参考
- nginx + unicorn + Railsの設定方法 - Qiita
- UnicornでRedmineをサブディレクトリにデプロイする方法 | ride on technology – 藝に游ぶ –
- Rails with Relative URL Root - Quickhack Diary
assetsに対するルーティング設定
assets:precompile
を使ってあらかじめassetsフォルダ内にcssとjsを展開していたのだが、ブラウザ経由でいざアプリにアクセスすると、CSSもJavaScriptも適用されていない(assets配下が読み込めていない)という事象が発生した。
原因はルーティングが正しくなかったから。前述の通りExhiBiでは/var/www/rails
にアプリを展開していたのだが、さらに細かく見るとrails
フォルダの中にはreleases
、current
、shared
という主に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
へ環境変数設定をいれこむことにした。これも何かしらベストプラクティスがありそうな気がする。。
参考
- Missing
secret_key_base
for 'production' environment が出たのをどうにかする件 - YKT68の日記 - Rails - secret_key_baseあたりのメモ - Qiita
gem 'pg'が入らない
入らない。なんか知らんが入らない。ググるとどうも入りづらいGemの筆頭である模様。いろいろ探って、therubyracerを先に入れるべきだと聴いてやってみたけど結局入らない。とにかくどうやっても、Capistranoのbundle install
でMake sure that gem install pg -v '0.17.1' succeeds before bundling.
と言われてしまう。仕方ないのでsshでサーバーに直に入ってbundle install
を手動実行してみるとなぜか入る。わからん。これだけは本当にわからん。さらにその後はtiltが入らないとか言われたりもした。ソースをrubygems.orgから変えたりしてなんとか入ったのだが、ちょっと腑に落ちない感。
参考
- Ruby - bundlerでpgをインストールする - Qiita
- Ruby - bundle installでつまずきやすいgem達 - Qiita
- (解決済み) gem install などができない問題の一時的な解決方法と根本的な解決 - this A moment
posgresqlのユーザー管理
SQLに関する基礎知識のなさを猛省した。とりあえずわかってなかったのこんなとこ。
- pg_hba.confで指定できる認証方式でmd5はパスワード認証、peerはOSにログイン中のユーザー名でログインしようとする
- よってsqlで使う予定のユーザー名がOS側に存在しない場合、peerを使おうとするとコケる
- psqlコマンドでログインしたとき、まずユーザー名と同名のDBにアクセスしようとするので、それが存在しないとエラーになる
- でもDB作成って
rake db:create
でやると思うんだけど、このコマンド打つときはどうやってアクセスするの?あれ?
- でもDB作成って
- DBに初期データを投入したい場合は
db/seeds.rb
に書いてrake db:seed
を打つ rake db:migrate
はテーブル生成だけでデータ登録までは賄ってくれない- 開発段階でmigrateファイルをやたらと作ってたりすると上手くdb:migrateできないこともあるので、整理した方がいいかも
参考
Rails、Capistranoのいずれも抽象度の高い技術で、これは何度かブログに書いてきてるけど、その内実をきちんと押さえてないとエラーが起きた場合に結構辛いことになる。READMEを読むこと、公式のWikiなどがあるならそっちも目を通すこと、エラーが起きたらログを見ること、あるいは前もってログを吐く設定にしておくこと。このあたりは改めて徹底したいところ。
あとここからは余談だが、Railsのデプロイ先としてherokuが好まれるのは、ある程度「間違いのない選択肢」ということなのだろうなと想像している。ここで自分がつまずいたサブディレクトリでのアプリ展開や、postgresqlのコンフィグなどは、herokuであれば必要がなくなる。一旦用意されている高速道路を全力で走ってみて、それが成功してから自分好みに変えていく方が近道なのかもしれない。なんとかしてposgresqlを使おうとこだわったり、サブディレクトリでの運用をさせたり、最初からいろいろ欲張りすぎた点も反省。