読者です 読者をやめる 読者になる 読者になる

LCL Engineers' Blog

夜行バス比較なび・格安移動・高速バス比較を運営する 株式会社LCL開発者のブログ

GitHubへのpush時に、featureブランチ環境を自動作成する

弊社では、作業中ブランチの動作を誰でも確認できる仕組みを用意しています。今回の記事では、導入背景から運用方法までを紹介したいと思います。

解決したかった課題

弊社のWebサービス開発では、GitHub Flowを採用しています。 GitHub Flowでは、masterへマージ後にすぐプロダクション環境へデプロイするため、masterへのマージ後には問題が発見されないのが理想です。その為、他のメンバーにfeatureブランチの動作を早い段階で確認してもらう仕組みが必要でした。

開発者のローカル環境へアクセスすれば確認することはできるのですが、以下のような課題もあったためサーバ上にブランチ専用の環境を作成するようにしました。

  • 複数Issueの開発が並行で走るので、featureブランチ毎に独立した環境が必要
  • リモートワークをしているメンバーもいるため、インターネット上に環境が必要
  • 開発者の手間をかけず、自動での構築が必要

仕組みの概要

GitHubへfeatureブランチをpushすると、WebhookでJenkinsのJOBを実行し、EC2上のテストサーバにfeatureブランチ用のアプリをデプロイします。 アプリは、Nginx + Rails(Unicorn)で構成しています。デプロイ時には、baseとなるNginx/Unicornの設定ファイルをコピーし、featureブランチ用に一部を書き換えます。(DBは共通にしています)

f:id:lcl-engineer:20170326154533p:plain

2回目以降のPUSHは既に環境が作成されているため、新たに環境は作成されず、Gitからコードをpullし既存の環境を最新化するようにしています。

仕組みの構築にあたっては、以下の記事を参考にさせて頂きました。

URL

あらかじめ、AWS Route53に「 *.yyy.zzz 」というワイルドカード利用したドメインを割り当てておき、テストサーバのIPを設定しておきます。 ワイルドカード部分にブランチ名を設定し、ブランチ毎に以下のようなURLとなるルールにしています。

https:// branch-123.yyy.zzz/

なお、ドメインにアンダースコアは利用できないため、ブランチ名にアンダースコアが含まれている場合は、ハイフンなどの別の文字へ置換する必要があります。

Nginx設定ファイル

ベースとなる設定ファイルをコピーし、server_nameには各ブランチのドメインを設定します。

server_name  base.yyy.zzz;
↓
server_name  branch-123.yyy.zzz;

Nginx -> Unicornとのsocket通信のパスもブランチ毎に固有にするため書き換えます。

server unix:/tmp/base.sock
↓
server unix:/tmp/branch-123.sock

Unicorn設定ファイル

Unicornもベースとなる設定ファイルをコピーし、nginxとのソケットのパスを書き換えます。

listen "/tmp/base.sock", :backlog => 64
↓
listen "/tmp/branch-123.sock", :backlog => 64

Railsアプリ

該当のブランチからコードをcloneし、bundle install / assets precompileなどの通常のRailsアプリのデプロイ手順通りにデプロイします。

全ての環境が揃った段階で、Nginx/Unicornを起動すると環境へのアクセスが可能となり、ブランチ専用URLをチャットへ通知します。

環境作成のタイミング

当初は、hubotで任意に指定した場合のみ、環境を作成することも考えましたが、一手間かかってしまうためGitHubへのpushで環境を作成するようにしました。 GitHubへのpushで環境を作成すると、要不要問わず全てのブランチの環境が作成されてしまうので、後述する環境削除が重要となります。

環境削除のタイミング

この仕組みの場合は、環境がいくつかもできてしまうので、放置しているとサーバリソースをすぐに圧迫してしまいます。当初は、最大N個の環境のみ保持し、更新されていないものを自動削除するという運用にしていました。ただし、レビュー期間が長い案件の場合は「テストURLが見れなくなっている」とう状態になり、その都度もう一度環境を作り直す必要がありました。

現在では、該当ブランチがmasterへマージされたことをトリガーに、環境を削除するようにしています。masterへのマージ待ちブランチが多いと、リソースを圧迫してしまうため、N個を超えたらチャットへ通知し、人が不要な環境を判断して削除します。この運用も完璧ではないですが、人であればレビュー中のブランチは削除しないなど、精度の高い判断ができるので当初の問題は解消できました。

まとめ

現在の仕組みでうまく周っているため満足度は高いのですが、実装がシェルを駆使した泥臭い仕組みになってしまってまい柔軟性に欠けています。Docker等を利用すれば、もう少しシンプルな仕組みにできそうなので、今後取り組んでみたいと思っています。