話題の記事

AWS CodeDeploy を使って Rails アプリケーションをデプロイしてみた

2014.11.14

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Rails アプリケーションをデプロイしてみよう

昨日の re:Invent で発表された AWS CodeDeploy (以下 CodeDeploy) を使って GitHub リポジトリで管理している Rails アプリケーションを EC2 インスタンスにデプロイしてみました。いままでは Capistrano を利用してデプロイを行うのが主流でしたが、果たして CodeDeploy はこれに変わるサービスなのか!?と思いながら試してみることにしました。

なお、サンプルサイトのデプロイ手順は以下で紹介していますので、こちらもあわせてご覧ください!

EC2 インスタンスの環境構築

今回の要件を達成するために、EC2 インスタンスには以下の環境構築が必要です。この手順については今回は割愛させていただきます。ちなみに私は Chef を利用して行いました。

  • Ruby (rbenv または rvm を推奨)
  • Nginx (Rails アプリの動作確認用)
  • AWS CodeDeploy Agent

特に AWS CodeDeploy Agent が真新しいですが、これは CodeDeploy の対象となるインスタンスには必須になります。インストール実行ファイルを S3 からダウンロードする操作が発生するため s3:Gets3:List の実行が許可されている IAM Role を指定して起動している必要があります。

AWS CodeDeploy Agent のインストールコマンドは以下の通りです(us-east-1 の場合)。

$ sudo yum update
$ sudo yum install aws-cli
$ cd /home/ec2-user
$ aws s3 cp s3://aws-codedeploy-us-east-1/latest/install . --region us-east-1
$ chmod +x ./install
$ sudo ./install auto

AppSpec ファイルの追加

ソースコードでは、CodeDeploy がデプロイ設定を読み込むための appspec.yml ファイルを作成しておく必要があります。YAML で書きます。また BeforeInstallAfterInstall といった設定を追加すると、デプロイのライフサイクルをフックして処理を追加することができます。処理自体はシェルスクリプトファイルで作ります。

version: 0.0
os: linux
files:
  - source: /
    destination: /var/www/sample-app
permissions:
   - object: /var/www/
     pattern: "**"
     mode: 775
hooks:
  ApplicationStop:
    - location: scripts/stop_server.sh
      timeout: 300
      runas: root
  BeforeInstall:
    - location: scripts/clean.sh
      timeout: 300
      runas: root
  AfterInstall:
    - location: scripts/bundle_install.sh
      timeout: 300
      runas: root
  ApplicationStart:
    - location: scripts/start_server.sh
      timeout: 300
      runas: root

今回は、デプロイ済みのソースのクリーン、Bundler を使った Gem ファイルのインストール、Unicorn サーバーを起動するコマンドを追加します。

stop_server.sh

#!/bin/bash
su -l deploy -c 'kill -KILL -s QUIT `cat /var/www/sample-app/tmp/pids/unicorn.pid`'

clean.sh

#!/bin/bash
sudo rm -rf /var/www/sample-app

bundle_install.sh

#!/bin/bash
su -l deploy -c 'cd /var/www/sample-app && bundle install --path vendor/bundle'

start_server.sh

#!/bin/bash
su -l deploy -c 'cd /var/www/sample-app && bundle exec unicorn -D -E production -c config/unicorn.rb'

2014/11/18 一部修正しました。

Application の作成

事前準備が済んだところで、CodeDeploy の Application を作成しましょう。まずはこちらにアクセスし「Get Started Now」をクリックします。

code-deploy01

今回は「Custom Deployment」を選択します。

code-deploy02

新規アプリーケーションの設定を行っていきます。Application Name は「sample-app」、Deployment Group Nameは「sample-app-deplpoyment-group」にしました。

code-deploy03

Add Amazon EC2 Instances

デプロイ対象の EC2 インスタンスを指定します。今回は既存の EC2 インスタンスを指定していますが、Auto Scaling Group を指定することもできます。

code-deploy04

Deployment Configuration

どのようにデプロイを実行するか、またデプロイの成功/失敗をどのように扱うかという設定項目です。

code-deploy05

デフォルトで用意されている設定は次の通りです。なお、自分で作成することもできます。

CodeDeployDefault.AllAtOnce 一度にすべてのインスタンスにデプロイする。最低1つのインスタンスにデプロイが成功した場合、全体のデプロイが成功したものとする。すべてのインスタンスへのデプロイが失敗した場合、全体のデプロイが失敗したものとする。
CodeDeployDefault.OneAtTime インスタンス1つずつにデプロイする。全てのインスタンスにデプロイが成功した場合、全体のデプロイが成功したものとする。デプロイが失敗した時点で失敗と扱われるが、既にデプロイが成功したインスタンスはそのまま。
CodeDeployDefault.HalfAtTime 一度に総インスタンス数の半分までデプロイする。総インスタンス数の半分までデプロイが成功した場合、全体のデプロイが成功したものとする。全体のデプロイが失敗した場合でも、既にデプロイが成功したインスタンスはそのまま。

CodeDeployDefault.HalfAtTime はちょっと特殊ですね。ちなみにデプロイ対象が複数のインスタンスのときだけ効果があるようなので、デプロイ対象が1つのインスタンスだけの場合、どれを選んでも同じです。デフォルトは CodeDeployDefault.OneAtTime が設定されています。

Service Role

CodeDeploy が EC2 インスタンスにアクセスするときに使用するロールの設定項目です。

code-deploy06

サンプルのロールと同様のロールを作成して使うだけで良いと思います。

{
    "Statement": [
        {
            "Action": [
                "ec2:Describe*"
            ], 
            "Effect": "Allow", 
            "Resource": [
                "*"
            ]
        }, 
        {
            "Action": [
                "autoscaling:CompleteLifecycleAction", 
                "autoscaling:DeleteLifecycleHook", 
                "autoscaling:DescribeLifecycleHooks", 
                "autoscaling:DescribeAutoScalingGroups", 
                "autoscaling:PutLifecycleHook", 
                "autoscaling:RecordLifecycleActionHeartbeat"
            ], 
            "Effect": "Allow", 
            "Resource": [
                "*"
            ]
        }
    ]
}

Trusted Entities は次のような感じです。

{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "1",
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "codedeploy.us-west-2.amazonaws.com",
          "codedeploy.us-east-1.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

デプロイを実行する

さて、いよいよデプロイです!「Deploy New Revision」をクリックします。

code-deploy07

今回は GitHub リポジトリで管理しているアプリケーションをデプロイしたいので、Revision Type は「My application is stored in GitHub」を選択します。

code-deploy08

「Connect with GitHub」をクリックすると、ポップアップで GitHub の OAuth 認証画面が表示されます。

code-deploy09

認証後、Repository Name と Commit ID を指定します。Repository Name はアカウント名または Organization 名から指定します。

code-deploy10

準備完了!「Deploy Now」をクリックしてデプロイを実行します。「Succeed」と表示されれば成功です!

code-deploy11

まとめ

とりあえず Rails アプリケーションをデプロイするところまで、ひと通り行ってみました。AppSpec はまだまだ調整の余地はありますし、Capistrano と比べると一番の優位点である Auto Scaling Group を対象としたデプロイという方法もあります。引き続き調査していきたいと思います!

参考