開発ブランチをデプロイする

みんなのウェディングの高井です。

気軽に開発サーバーにデプロイできると便利なことがあります。

たとえば、開発中のブランチをデザイナーやディレクターに確認してもらいたいときがあります。また、プルリクエストのためのブランチが大きくなってしまったから動作をみながらコードレビューしたいときもあるでしょう。

もちろん、手元のマシンでアプリケーションサーバーを起動させ、そのサーバーで動作確認してもらうこともできます。とはいえ、タイミングをあわせてサーバーを起動させるというのも手間です。

そこで、みんなのウェディングでは、開発ブランチを簡単にデプロイして確認できるようにする仕組みを用意しています。

Capistrano

開発サーバーへのデプロイには Capistrano を利用しています。プロダクションサーバーやステージングサーバーに対するデプロイでは AWS CodeDeploy を使っているのですが、複数サーバーへのデプロイでないときには、 Capistrano の方が効率的で小回りが効きます。ですから、開発サーバーとその他の環境へのデプロイとで方法を分けています。

開発用のブランチは、フォークされたリポジトリに存在しています。 Capistrano で、フォークされたリポジトリの特定ブランチからデプロイをするために、環境変数をつかって切り替えられるようにしています。

set :branch, ENV["BRANCH"]
set :github_user, ENV["GITHUB_USER"]
set :repo_url, "git@github.com:#{fetch(:github_user)}/app.git"

set :deploy_to, "/var/www/apps/#{fetch(:branch)}"

Capistrano は Hubot から起動されるようにして、いわゆる ChatOps を実現しています。

DNSワイルドカード

特定のブランチを開発サーバーにデプロイしたら、そのブランチ用の URL で動作確認をおこなえるようにします。たとえば、 newfeatrue ブランチをデプロイすると、そのブランチ名をホスト名に含んだ http://newfeatrue.devel.example.com という URL でアプリケーションが起動します。

これを実現するために、DNSワイルドカードを利用しています。みんなのウェディングでは、AWS Route 53を利用しています。 Roadworker の DSL で次のようにワイルドカードを定義しています。

hosted_zone "example.com." do
...
  rrset "*.devel.example.com.", "A" do
    ttl 300
    resource_records('10.0.0.10')
  end

DNS ワイルドカードを利用するときのポイントは、ネガティブキャッシュのTTLを短かくすることです。DNS クライアントは、ドメインが存在しないという情報もキャッシュします。この情報の保存期間を短かくしないと、何かと不便なことが多くなってしまいます。

ネガティブキャッシュのTTLは、SOA レコードの定義で設定することができます。十分に短かければ問題ないのですが、開発用のドメインでは Google の設定に倣って 60 秒に設定しています。

Nginxの設定

ワイルドカードによる名前解決ができたら、そのサーバーで待ち受けている nginx が名前ベースバーチャルホストで、リクエストをアプリケーションサーバーへと転送します。

アプリケーションサーバーには puma を利用していて、 nginx とは UNIX ドメインソケットで通信しています。 TCP/IP ではなく UNIX ドメインソケットを利用することで、 port 番号の衝突について考えなくても済むようになります。

デプロイされたブランチ毎に nginx の設定を切り替えるため、設定ファイルを生成する必要があります。そこで、Capistrano を利用して、デプロイのたびに erb コマンドで設定ファイルを動的に生成しています。

execute "erb branch=#{fetch(:branch)} #{fetch(:config_files)}/nginx.conf.erb > #{fetch(:release_path)}/config/nginx.conf"

nginx の設定ファイルのための erb テンプレートは次のようになっています。外部から与えられた branch 変数を利用して server_name や upstream などの設定を変更しています。

upstream app_<%= branch %> {
    server unix:/var/www/apps/<%= branch %>/shared/tmp/sockets/puma.sock;
}
server {
    listen 80;
    server_name <%= branch.tr('_', '-') %>.devel.example.com;
    location / {
        proxy_pass http://app_<%= branch %>;
    }
}

また、生成された nginx の設定ファイルは、 /etc/nginx.conf で一括して読み込まれるように設定をします。

include /var/www/apps/*/current/config/nginx.conf;

サーバーの再起動・クリーンアップ

Capistrano によるデプロイの最後で、ちょっとしたスクリプトを起動し puma の再起動を行なっています。

同時にブランチの削除を行なっています。そのときに、最新の 10 デプロイ分だけを残して、それ以外は削除するようにしています。これは、サーバーリソースが限られているため、割り切って削除を行なうようにしないと、いつかメモリやディスクスペースが枯渇してしまうためです。

開発ブランチのデプロイにもライフサイクルの考え方を持ち込んでおくと、後々のメンテナンスコストが下げられるので、おすすめします。

まとめ

今回は、みんなのウェディングで行なっている開発ブランチのデプロイについて説明しました。個々の要素は、それほど難しいというわけではないのですが、いくつかの要素を組み合わせる必要がありますので、仕組みとしては少し複雑になっています。

このような仕組みをつくっておくと、 Slack でボットにデプロイを依頼するだけで、開発ブランチの動作確認をできるようになります。気軽に動作確認ができる環境をつくると、他のチームメンバーとの連携がスムーズにできるようになります。


みんなのウェディングは、サービス開発に真摯に取り組みたいソフトウェアエンジニアを募集中です。興味のある方は、Wantedlyからご連絡ください。