chroju.dev/blog

the world as code

Capistrano3を最後にもう一度だけ懇切丁寧にまとめてみる

いろいろエントリーを上げながら苦しんでいたCapistranoだが、ようやっとそこそこ落ち着いてきた気がするのでそろそろ完結編といく。Capistranoの基本とかはすでにこちらのエントリーで書いたので、今回は各設定ファイルの書き方とか、その他ハマったポイントを中心に。

今回作成したファイル

以下4ファイルを作成した。

  • Capfile
  • config/deploy.rb
  • config/deploy/staging.rb
  • lib/capistrano/tasks/unicorn.cap

基本的にCapistranoを使う場合「必須」なのは上2つのファイル。deploy/hoge.rbも確実に必要にはなるが、デプロイ先の環境が本番なのかステージングなのかでproduction.rbとstaging.rbを使い分けることになる。もちろん、ステージング環境を用意していない場合はstaging.rbは不要。また4つ目のファイルだが、自分の場合はunicornをデプロイ先で使っているので、デプロイ後にunicornを再起動する目的で独自タスクを作成している。説明が遅れたが、今回デプロイ先となる環境は大雑把に以下の通り。

  • Vagrant 1.4.3
  • CentOS 6.4
  • Postgresql 9.1
  • Ruby 1.9.3(rbenv)
  • Nginx + unicorn
  • 位置付けはステージング環境

Capfile

ここはだいたい環境を問わず同じになってくる箇所。まずcapistrano/setupcapistrano/deployrequireが必須。RailsをCapistranoで扱う場合は、capistrano/bundlerからcapistrano/rails/assetsまでも必須となる。rbenvを使っている場合はcapistrano/rbenvが必要。rbenvをどこにインストールしたのかにより、set :rbenv_typeを指定する。あとはデプロイするアプリケーションで使うRubyのバージョンも指定してやる。rvmを使う場合も似たようなcapistrano/rvmを使うみたいだが、そちらはよくわからんので割愛。

で、ここまでがrequireということなので、デプロイ元サーバーにGemfile書いてインストールしておくことを忘れずに。

group :development do
  gem 'capistrano', '~> 3.1.0', :require => false
  gem 'capistrano-rails', '~> 1.0.0', :require => false
    gem 'capistrano-rbenv', '~> 2.0', :require => false
  gem 'capistrano-bundler', '~> 1.1.2', :require => false
end

最終行は独自カスタムタスクを読み込むための行。デフォルトで入っているのでそのままにしておけばよい。先のunicorn.capのように、何か独自タスクを作った場合はこのパスに入れれば読み込むよーということでもある。

なお、以前書いたエントリーではcapistrano3/unicornrequireしていたのだが、これは撤回した。詳細はunicorn.capについて説明するときに後述。

staging.rb

ステージング環境、というかデプロイ先環境の設定を書く。vagrantを使う場合はだいたいこれと同じように書いておけば通るんじゃないかと思う。Vagrantはデフォルトではvagrantユーザーによるsshが可能になっているので、それをそのまま使わせてもらっている。何か他のユーザーで入りたい場合などは頑張るしかない。

一点だけ注意すべきは、RAILS_ENVがstagingに設定されるということ。Capistrano3ではcap installを叩くとデフォルトでstaging.rbとproduction.rbが作られ、RAILS_ENVもこのファイル名に倣うことになるのだが、Railsの動作環境は通常test, development, productionの3種類であり、stagingは存在していない。従ってこのままデプロイを始めてもうまくはいかない。面倒であればstaging.rbは使わず、production.rbだけを使っていてもいいかもしれない。

staging.rbを使う場合は、Rails側で環境の準備が必要になる。やることは大きく3つ。

1. database.ymlにstagingを作成する

rake db:migrateなどのDB系のコマンドはiRAILS_ENVを指定して実行される。ここで指定されたRAILS_ENVをdatabase.ymlに見に行くので、設定を入れておく必要がある。ステージング環境の本来の意味を考えると、production用の記述をそのままコピーするだけで良いはず。

2. config/environments/staging.rbを作成する

動作環境設定ファイルとして、デフォルトではproduction.rbとdevelopment.rbだけが用意されているので、これもproduction.rbをコピーしてstaging.rbを作る。

3. Gemfileにgroup :stagingを作成する

これはRAILS_ENVと直結するわけではないが、GemfileのグループもRails環境ごとに作られているのでstagingを設けてやった方が良さそう。これもここまでと同様の話で、group :staging, :production doとしてやるだけで良い。

deploy.rb

いよいよデプロイ用の設定。面倒なので説明は省くが、だいたいはコメント読めば設定できるはず。

linked_fileslinked_dirs前回のエントリーで書いた通り、shared配下に置いているファイルやフォルダのうち、currentに必要となるものを指定することでシンボリックリンクを張ってくれるというものなのだが、ではshared配下にこれらファイルやフォルダはいつ作られるのか?というのがかねてから疑問だった。

結論を言えば、linked_filesは勝手には作成されない。というより、ここに指定したファイルがshared下に存在しない場合、Capistranoはデプロイ時にエラーを吐いてくる。正確に言えばdeploy:check:linked_filesというタスクがあり、ここで存在確認を行っている(参照)。したがってこのタスクが投げられる前にファイルは別でアップロードしなくてはならない。ここではdetabase.ymlを指定しているので、アップロードタスクを独自で組み込んでいる。詳細は後述。

一方のlinked_dirsは、shared配下に存在しない場合はdeploy:check:make_linked_dirsで空っぽのフォルダとして作成してくれる。逆に言えば、元々ファイルが入っているようなフォルダをここで指定することはあまりないということ。例えばbundleなり、logやtmpなり、アプリが動作する中で必要とされるフォルダ(従ってGitHubで静的に管理はしていないフォルダ)がここに来ている。なお、shared/bundleはcapistrano/bundlebundle install --pathで指定するデフォルトのフォルダなんだそうだが、古いバージョンのcapistrano/bundleではshared/vendor/bundleにインストールするらしいので要確認。

後半では独自タスクを3つ追加している。

1つ目はdatabase.ymlをアップロードするタスク。デプロイ先にshared/configフォルダを作成した上で、ローカルのconfig/database.ymlをアップロードしている。2つ目はbundle exec rake db:createを発動するタスク。Capistranoやcapistrano/railsにはDB作成用のタスクは一切含まれていないので、自力であらかじめ作っておく必要がある。手動で作成したり、Chefなんかで仕込んでおく手もあるのだろうが、ここではCapistranoのタスクとして書いている。必要になるのはもちろん初回1回限りなので、デプロイのルーチンの中には組み込んでいない。

3つ目はunicornを再起動するタスク。これはunicorn.capの中で作成したunicorn:restartというタスクを呼んでいる。

最後の2行は独自タスクのルーチンへの組み込み。database.ymlのアップロードは真っ先にやらなくてはならないので、deploy:startingというデフォルトで言えば最初のタスクのさらに前に組み入れている。一方のunicorn再起動はdeploy:publishingの後、ほぼすべてのタスクが終わったタイミング。

unicorn.cap

ほぼほぼ以下エントリーの中身をそのまま使わせてもらいました。

異なる箇所はstart_unicornの内部処理。元エントリーではbundle exec unicornを叩いているのだが、自分としてはbundle exec unicorn_railsを叩く認識だったので書き換えている。ここの書き換えが必要なのかどうかはちょっと自信がない。またコマンドのオプションとして--path hogeを指定しているのだが、これはサブディレクトリでRailsアプリを動作させたいため。予定としてhttp://www.chroju.net/は静的なサイト、www.chroju.net/hogeでアプリごとにフォルダ作って管理としたかったもので。まー、こういう要らんチューニングを最初からやろうとするから迷走するわけなのだが。はじめはマニュアル通りにまず写経すべきだと思います。はい。サブディレクトリ云々の件はまた別途エントリー書きます。

ちなみにパスの指定やら何やらやらないのであれば、capistrano3-unicornを使うのも手だと思う。

その他トラブルなど

以上、ここまでの設定にはそれなりに自信がある。とりあえずbundle exec cap staging deployを叩いてエラーが出ないことも確認はした。が、現状アプリは動いてない。。。いや、正確に言うと一度動いたのだが、その後Vagrant落として、セキュリティアップデートのためにiMacも再起動してもう一度やってみたところ、ダメダメになってしまったのだ。何が原因なのやらさっぱりだ。。。トラブルは3つほど遭遇している。

1. Gitが通らない

git ls-remotePermission denid(publickey)のエラーが出るという事象が発生、その先に進めなくなった。これについてはドンピシャなエントリーを探し当てたので、そのまま解決策を適用したらなんとかなった。なぜこのエラーが起きたのかまではまだ深堀りできてない。

2. 404が返される

Nginxは動いている。unicornもプロセスは上がっているのだが、アプリを配置したフォルダを見に行くとThe page you were looking for doesn't exist.というメッセージが返される状態。他の有りもしないフォルダを見に行こうとするとNginxがBad Gatewayを返してくるし、unicorn.stderr.rbにログが残っているのでアクセスはできているようなのだが、なぜ表示に至らないのかわからない。

ちなみにstaging.logにはActionController::RoutingErrorが出ている。???

3. Assets周りが不具合起こしている模様

Vagrantを落とす前はアプリ自体つながりはしたのだが、jsとcssが反映されていない状態だった。ソースから探ってjsとcssをブラウザ上で開いてみたのだが、真っ白になっていた。アセットコンパイルのエラーなのかと思い、サーバー上でもコンパイル後のファイルを開いたりしてみたが、こっちは中身がきちんと書かれていた。なんなんだ一体。

以上。だいたい整ったはずなのだが、まだまだ先が長そうでいい加減ゲンナリしている。自分、この手のこと向いてないのかもしれんと思い始めた。。。