ElasticBeanstalk & Rails & CircleCI構成で爆速デプロイ！

皆さまこんにちは。[しくみ製作所](https://sikmi.com/)の@taru-mです。

この記事は [Docker2 Advent Calendar 2016](http://qiita.com/advent-calendar/2016/docker2) の24日目として予定していましたが、[Docker](http://qiita.com/advent-calendar/2016/docker)の１７日目が投稿されていなかったため、代わりに投稿します。
（正直、あまりこういう事は言いたくないのですが期限を守れない方は業務ではどうしているんでしょう。。@koki_cheeseさん24日目キャンセルしてしまいました。ごめんなさいm(_ _)m）


さて、本題です。

弊社では2016年に入ってから8割の案件でDockerを利用するようになってきました。
そこで、効率的に運用するために幾つかのサービスを検討した結果、AWSのElasticBeanstalkというサービスに辿り着きました。

# ElasticBeanstalkとは何か？
簡単にいうと、AWSの各サービスをまとめてコントロールするためのサービスです。ElasticBeanstalkを利用することで、EC2, ECS, RDS, ELB, Auto Scaling, プロビジョニング、モニタリングなどをウィザードに従い数ステップで作成・管理することが出来ます。
また、簡易的なバージョン管理機能も備えておりアプリのロールバックも容易です。

さらには、ElasticBeanstalkはDockerだけではなく、Java, .NET, PHP, Node.js, Python, Ruby, GoなどのアプリケーションもサポートされているのでDockerはちょっと．．．という人でも安心です。

Amazon様すごすぎぃ！

# CircleCIを使って本番運用する上でのデメリット

さて、ここまでElasticBeanstalkの凄さばがりに触れてましたがデメリットもあります。
ElasticBeanstalkのと言うよりはDockerのデメリットなんですが、何と言ってもデプロイに時間が掛かり過ぎるんです！！

たとえばRailsの場合、precompile次第ではありますが数分でデプロイが終わるところを、

```bash:railsを素で運用する場合
git pull
bundle exec rails db:migrate
bundle exec rails assets:precompile
bundle exec pumactl -F config/puma.rb phased-restart
```

Docker環境だと、弊社[ブログ](http://sikmi.com/blog/sikmi_kaizen/elasticbeanstalk-with-multi-container-docker%E3%81%ABcircleci%E3%81%A7%E8%87%AA%E5%8B%95%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4)にある通り場合によっては数十分掛かってしまいます。

このままでは本番で緊急対応したいバグなどがある場合に、非常に困る．．．


# CircleCIでの高速化を可能な限りやってみる
最近だとCIは[Wercker](http://www.wercker.com/)や[AWS CodeBuild](https://aws.amazon.com/jp/codebuild/)など、気になるサービスが続々と出てきていますが、CircleCIでも工夫次第ではかなり高速化出来ます。

## 1. awsebcliのインストール
CircleCIでBeanstalkのデプロイを行うにはawsebcliが必要ですが、利用にはPython2.7.9または3.4以上が必要です。
CircleCIでは現時点(2016/12/24)でOSバージョンが2つ用意されています。

```
Ubuntu 12.04
Ubuntu 14.04
```

Ubuntu 12.04を選択している場合、バージョンが古いためデプロイ時にPython2.7.9以上をインストールしなければならず、この作業に約2分掛かってしまいます。Ubuntu 14.04はPython2.7.11が乗っているため、OSを変更するだけで2分短縮できます。
この短縮は大きいですね！

- Ubuntu 12.04
<img width="1340" alt="スクリーンショット 2016-12-18 17.12.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/106116/3440725b-3559-71b5-0bfe-3567a21f22d7.png">

- Ubuntu 14.04
<img width="1336" alt="スクリーンショット 2016-12-18 17.12.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/106116/9f886572-746f-1b75-7181-dc79f07606b2.png">


*注）2016年7月以降に新規でAdd ProjectsしたプロジェクトではデフォルトでUbuntu 14.04になっています。*

## 2. cache_directoriesを利用してprecompileをキャッシュする
CircleCIではデプロイするたびにデプロイ用コンテナを新規に作成しているので毎回フルでprecompileが走ってしまいます。これは非常に無駄。キャッシュしましょう。

```yaml:circle.yml
(略)

dependencies:
  pre:
    - pip install awsebcli
  post:
    - | # precompileしたものをcacheしたいのでここでprecompile
      if [ $CIRCLE_BRANCH = 'master' ]; then
        RAILS_ENV=production bundle exec rails assets:precompile assets:clean
      elif [ $CIRCLE_BRANCH = 'staging' ]; then
        RAILS_ENV=staging bundle exec rails assets:precompile assets:clean
      fi
  cache_directories:
    - public/production/assets
    - public/staging/assets
    - tmp/cache/assets


```

これで2回目以降のデプロイでキャッシュが読み込まれてprecompileが高速化されます。弊社の環境ではプロジェクトによっては10分以上もの短縮が図れました。
これはもう、キャッシュ！せずにはいられないッ！

## 3. cache_directoriesを利用してbundle installをキャッシュする
さあ、ここまで来るとキャッシュ出来るところは全部したくなります。bundle installもキャッシュしちゃいましょう！

```yaml:circle.yml
(略)

dependencies:
  pre:
    - docker run -v `pwd`:/root -v ~/gem_cache:/root/vendor ruby:2.3.3 bash -c "cd /root && bundle install --path=vendor/bundle --without development test && rm -rf ./.bundle"
    - rm -rf ./vendor/bundle
    - cp -r ~/gem_cache/bundle ./vendor/bundle
  cache_directories:
    - ~/gem_cache

```
これでさらに数分短縮です！
しくみ製作所の技術力は世界一ぃ！！（すみません、ほんと言い過ぎました．．．申し訳ございませんm(__)m）

# 最後に
弊社では、これらを実施することで20分ほど掛かっていたデプロイが6分ほどに短縮されたプロジェクトもあります。

他にも、皆さまが実施している短縮方法などあれば是非教えてください
Dockerのデプロイ時間短縮を図ってみんなで一緒にしあわせになっていきましょう！