既存のCapistranoでのデプロイでの不満
最近、Railsアプリのインフラを管理しているが、既存のデプロイシステムで以下の様な不満があった。
全てのアプリケーションサーバーにsshしてgit cloneしている
全てのサーバーに、sshでログインする必要があり、全てのサーバーでgit pull出来るようにdeploy keyを設定しておく必要がある。
特に、Circle CIからdeployする様な場合には、Circle CIから全てのサーバーにssh出来るように設定を加える必要もあって結構面倒。
デプロイ時にいちいちCircleCIのIPを開けてたりする。
全てのアプリケーションサーバーでassets:precompileしている
assets:precompileは重い処理なので、一回やったらそれを全サーバーにコピーする方が賢い。
そもそもアプリケーションが動いている時にやっちゃうと貧弱なサーバーだとCPUが100%にはりつく。
アプリケーションサーバー上でdb:migrateが走っている
これもassets:precompileと同様にアプリケーションサーバーでやったらまずい。
全てのアプリケーションサーバーでbundle installしている
gemに更新があるとbundle installも結構重い。
複数のプロジェクトに大体同じ様なCapistranoの設定が入っている
最近流行のマイクロサービスに乗っかっているので、アプリケーションはどんどん増える。その度に、殆ど同じ様なcapistranoの設定を入れている。
unicornの起動方法をちょっと変えたりする。 => 全サービスのCapistranoの設定を変更する。
delayed_jobの起動方法をちょっと変えたりする. => 全サービスのCapistranoの設定を変更する。
心が折れる。
理想型
という事でこんな形にしたい。
- デプロイサーバーを一つ立てて、全てのアプリケーションをそこから配布したい。アプリケーション側にはCapistranoの設定は書きたくない
- アプリケーションサーバー上からgitにアクセスしなくても良いようにする。
- assets:precompileはデプロイサーバー上で一回だけ行って、アプリケーションサーバーにはそれらをコピーするだけにする
- db:migrateやdb:seed、db:seed_fuなどもデプロイサーバー上で行う
- bundle installもデプロイサーバーで行って必要なファイルだけアプリケーションサーバーに配布したい
capistrano-bundle_rsyncというgemが全て解決してくれた
色々と試行錯誤していたら、capistrano-bundle_rsyncという便利なgemを発見した。
https://github.com/sonots/capistrano-bundle_rsync
設定はものすごく簡単なのでREADMEを見るだけで簡単に設定出来た。
How it worksだけ転載。
Capistrano::BundleRsync works as followings:
1. Do git clone --mirror URL .local_repo/mirror on a deploy (local) machine.
2. Extract a branch by git archive {branch} to .local_repo/releases/{datetime}
3 .Do bundle --without development test --path .local_repo/bundle on a deploy (local) machine.
4. Deploy the release directory to remote machines by rsync.
5. Deploy the bundle directory to remote machines by rsync.
要するに、自分の指定したディレクトリにソースを持って来て、諸々処理した後に、そのディレクトリをrsyncで各サーバーに配布している。
本家のcapistranoと同様にhookでassets:precompileやunicorn起動などの処理を追加していけばok。
Q&Aにも書いてあるけど、capistrano-rsync (https://github.com/moll/capistrano-rsync) と違って、bundle installもデプロイサーバーで行えるのが良い。capistrano-rsyncは本家がメンテしてないようにも見えた。
あと、当たり前だが、OSのバージョンなど環境を揃える必要がある。
こんな点も良かった
デプロイサーバーのスペックを上げる
全サーバーで処理をしていた時には、いくらassets:precompileが遅かろうとbundle installに時間がかかろうと、全サーバーのスペックを上げるという選択は無かった。
お金かかるから。
でも、デプロイサーバー一台なら多少は金額の投資も出来るので、十分なスペックのサーバーを用意出来る。
結果的にdeployは早くなる。
サーバー追加が楽
デプロイサーバー上にある諸々をrsyncしたらサーバーが完成する(もちろんrubyの設定などは事前にしてあるとして)。
サーバーが増えた時に多分嬉しい
rsyncを並列で走らせる事が出来るので、帯域が許す限りは並列で一気に配布出来る。
まとめ
という事で、capistrano-bundle_rsyncを使って、各Railsアプリケーションをデプロイ出来るような小さなrubyアプリケーションを書いて、デプロイを一任する様な形に出来ました。