AWS CLI を使った Sinatra アプリケーションの AWS Elastic Beanstalk へのデプロイ

ElasticBeanstalk の公式ドキュメントが日本語／英語ともに eb コマンド使ったガイドしか出してないので、AWS CLIを使った場合の手順を書いていきます。ちょっとトリッキーだけど、eb コマンドなくてもデプロイできるよってことを説明したかった。

参考: 公式ドキュメント
http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_Ruby_sinatra.html
http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/create_deploy_Ruby_sinatra.html

## Step 1: Git リポジトリの設定

ほぼ同じ。作業用ディレクトリを作成して、

```bash
$ cd WORKING_DIR
$ git init .
```

## Step 2: AWS CLI の設定

既に終わっている人は飛ばしましょう。

### インストール

```bash
$ pip install awscli
```

### 設定

```bash
$ aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: us-west-2
Default output format [None]: json
```

引用: http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html

## Step 3: アプリケーションの作成

### アプリの作成

```bash
$ aws elasticbeanstalk create-application --application-name sinatraapp
```

### Environment の作成

Environment の名前はアカウントでユニークでないといけない（アプリをまたいでも同じものを指定できない）ので、アプリ名を先頭に付けておくのがわかりやすいと思う。（例: appname-staging, appname-production）

```bash
$ aws elasticbeanstalk create-environment \
    --application-name sinatraapp \
    --environment-name sinatraapp-env \
    --solution-stack-name "64bit Amazon Linux running Ruby 1.9.3"
```

## Step 4: アプリケーションの確認

`aws elasticbeanstalk describe-environments` コマンドでアプリケーションのURLを確認。
戻ってきた JSON の `CNAME` に Environment に対応する URL が入っているので、コピペしてブラウザで結果を確認。

```
$ aws elasticbeanstalk describe-environments --application-name sinatraapp --environment-name sinatraapp-env | grep CNAME
    "CNAME": "sinatraapp-env-xyz.elasticbeanstalk.com",
```

こういう画面が表示されれば、とりあえずの Environment 構築は完了。

![スクリーンショット 2014-02-24 15.48.05.png](https://qiita-image-store.s3.amazonaws.com/0/25774/4414ca50-3bf1-3850-f470-fa2b5d6659c9.png)

## Step 5: アプリケーションの更新

1. 作業用ディレクトリに `config.ru` を以下の内容で作成。

```rb
require './helloworld'
run Sinatra::Application
```

2. `helloworld.rb` の作成

```rb
require 'sinatra'
get '/' do
  "Hello World!"
end
```

3. `Gemfile` の作成

```rb
source 'http://rubygems.org'
gem 'sinatra'
```

4. `bundle install` してから、git にコミット

```rb
$ bundle install
$ git add .
$ git commit -m "update Sinatra app"
```

5. `git aws.push` でデプロイ

ここが一番の悩みどころだと思います。`eb init` せずにどうやって、`git aws.push` コマンド（or 同等のコマンド）を実行するかということです。これを理解するには ElasticBeanstalk のアプリケーションのバージョン管理についての理解が必要ですが、長くなるので、結論だけ書きます。良くわからない人はおとなしく `eb` コマンドを使いましょう。

まずは、アプリケーションのデプロイ用に適当なS3バケットを作ります。わかりやすくかつ、他のユーザと重複しないように `elasticbeanstalk-[region]-[account-id]` とかしておきます。ここでは、`elasticbeanstalk-us-east-1-XXX` というバケットを作ったとして話を進めます。

```bash
$ aws s3api create-bucket --bucket elasticbeanstalk-us-east-1-XXX
```

次にアプリケーションをzipでアーカイブし、上で作ったS3バケットにアップロードします。

```bash
$ TREE_ISH=`git rev-parse master` # ブランチ名はリリースしたいブランチ名を指定する。ここでは master
$ TIME=`date +%s`
$ S3_BUCKET='elasticbeanstalk-us-east-1-XXX'
$ VERSION="$TREE_ISH-$TIME"
$ git archive --format zip --output "git-$VERSION.zip" "$TREE_ISH"
$ aws s3api put-object --bucket "$S3_BUCKET" --key "git-$VERSION.zip" --body "git-$VERSION.zip"  
```

次にアップロードしたアプリに対応するアプリケーションバージョンを作成します。

```bash
$ aws elasticbeanstalk create-application-version \
    --application-name sinatraapp \
    --version-label "$VERSION" \
    --source-bundle S3Bucket="$S3_BUCKET",S3Key="git-$VERSION.zip"
```

最後にこれを指定した Environment に反映します。

```bash
$ aws elasticbeanstalk update-environment \
    --environment-name sinatraapp-env \
    --version-label "$VERSION"
```

URLをリロードして、`Hello World!` と表示されれば完了です。

![スクリーンショット 2014-02-24 18.11.51.png](https://qiita-image-store.s3.amazonaws.com/0/25774/f7efcc96-c378-96af-7e37-d8cc76a9d4ec.png)


## Step 6: クリーンアップ

1. Environment の停止
le
```bash
$ aws elasticbeanstalk terminate-environment --environment-name sinatraapp-env
```

2. アプリケーションの削除

```bash
$ aws elasticbeanstalk delete-application --application-name sinatraapp
```

## おまけ

さすがに Step 5 の手順は煩雑なので、スクリプト化しておきましょう。`eb-push` という名前で PATH の通ったところに置いておきましょう。

```bash
#!/bin/sh
#
# Usage: eb-push [application-name] [environment-name] [branch-name]
#

if [ $# -ne 3 ]; then
  echo "Usage: eb-push [application-name] [environment-name] [branch-name]"
  exit 1
fi

TREE_ISH=`git rev-parse $3`
TIME=`date +%s`
S3_BUCKET="elasticbeanstalk-us-east-1-XXX" # TODO: Change this to use your own bucket
VERSION="$TREE_ISH-$TIME"

echo "push $3 to $1:$2"

echo "Create archive: git-$VERSION.zip"
git archive --format zip --output "git-$VERSION.zip" "$TREE_ISH"

echo "Upload archive git-$VERSION.zip to $S3_BUCKET"
aws s3api put-object --bucket "$S3_BUCKET" --key "git-$VERSION.zip" --body "git-$VERSION.zip"

echo "Create application version: $1 : $VERSION"
aws elasticbeanstalk create-application-version \
    --application-name "$1" \
    --version-label "$VERSION" \
    --source-bundle S3Bucket="$S3_BUCKET",S3Key="git-$VERSION.zip"

echo "Update environment: $1:$2 to $VERSION"
aws elasticbeanstalk update-environment \
    --environment-name "$2" \
    --version-label "$VERSION"

echo "Cleanup"
rm "git-$VERSION.zip"

echo "Done"
```