ElasticBeanstalkのCNAME Swapを使ってBlueGreenDeploymentをしてみる

現在、AWSではELBとオートスケールでのBlueGreenDeploymentが非常に簡単にできるようになりました。

[Auto Scaling環境でのBlue-Green Deploymentの切替がAWS ELBでできるようになりました](http://dev.classmethod.jp/cloud/aws/bluegreen-devployment-by-elb/)

上記に記載されているようにオートスケールに紐づくELBを変えれるようになったことでCLIやAPIを使って簡単にBlueGreenDeploymentを行う事ができるようになっています。

話は変わって、最近ElasticBeanstalkを使ってみようという話があり、ElasticBeanstalkでBlueGreenDeploymentを行う方法を調べた所、CNAME Swapという機能があり、この機能を使う事でBlueGreenDeploymentができそうでした。(上記のELBの向き先を変えるのではなく、CNAMEを変える方式)

+ [ダウンタイムなしで新しいアプリケーションバージョンをデプロイする（CNAME スワップ）](https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/using-features.CNAMESwap.html)
+ [Elastic BeanstalkのCNAME Swapを試してみる](http://dev.classmethod.jp/cloud/aws/beanstalk-cname-swap/)

上記を実際に確認してみたのでその時のメモ。

# やること

+ ElasticBeanstalkを操作するebコマンドの設定をしたEC2を起動（ローカル環境でも良いと思います）
+ Blue環境(本番環境)にデプロイ
+ Green環境(テスト環境)にデプロイ
+ CNAME Swapを使ってGreen環境をBlue環境のURLでも確認できるようにする

# 準備

新規に作成したAmazonLinuxのEC2上でebコマンドを使ってやってみます。

IAMの設定を実施後、EC2を起動します。
ElasticBeanstalkで利用するIAMの詳細については以下に記載があります。

[サービスロール、インスタンスプロファイル、ユーザーポリシー](https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/concepts-roles.html?console_help=true)

## IAMロールの作成(ebを操作するEC2用)

EC2からebコマンドを実行するのでその権限を持ったIAMロールを作成します。

+ Roles->Create New Role
+ 任意のロール名を設定
+ Select Role TypedではAmazonEC2を選択
+ Attach PolicyではAWSElasticBeanstalkFullAccessを設定
+ Create role

上記にはIAMロールを作成する権限はないので次の項で利用するロールをあらかじめ作成しておきます。

## ElasticBeanstalkで利用されるサービスロールとIAMロールの作成

ElasticBeanstalkで利用されるサービスロールとIAMロールを予め作成します。

IAMの画面から頑張ってやる方法もあると思うのですが、マネージメントコンソールからElasticBenastalkを作成する途中で作成できる機能を利用します。

マネージメントコンソールでElasticBeanstalkの画面を表示します。

![Screen Shot 2015-09-19 at 2.14.45 PM.png](https://qiita-image-store.s3.amazonaws.com/0/20193/ced98dac-baf7-423f-b924-6c8dac0fa6d2.png "Screen Shot 2015-09-19 at 2.14.45 PM.png")

まだ一つもElasticBeanstalkでアプリを作成していない場合、上記のような画面になっているので画面右上の「Create Appliction」を選択して任意のアプリケーションを作成します。

+ Create New Application
+ 任意のアプリケーション名を入力
+ Create web serverを選択
+ 以降、Permissionという下記画面までは適当に入力（どうせ作成をキャンセルするので）

![Screen Shot 2015-09-19 at 2.01.26 PM.png](https://qiita-image-store.s3.amazonaws.com/0/20193/86a0a2d9-241e-a318-20d6-4f432ae9127e.png "Screen Shot 2015-09-19 at 2.01.26 PM.png")


上記でまだInstanceProfileとService roleが作成されていない場合には新規作成する旨が記載されているので作成します。

作成が終われれば、CancelでElasticBeanstalkの操作をキャンセルします。

上記操作ではアプリケーションが削除がされていないのでAction->Delete Applicationでアプリも削除しておきます。


## EC2の起動

ebを操作できるEC2を起動します。
セットアップはUserDataでやってしまいます。

+ OS->Amazon Linux AMI 2015.03.1
+ IAM Role->「IAMロールの作成(ebを操作するEC2用)」で作成したIAMロールを設定
+ UserData->以下の通り

```
#!/bin/bash

EC2_HOME="/home/ec2-user/"

# install packages
yum install lynx git -y

# set AWS SDK and CLI configuration
mkdir $EC2_HOME.aws
cat > $EC2_HOME.aws/config << EOS
[default]
output = json
region = ap-northeast-1
EOS
chown -R ec2-user:ec2-user $EC2_HOME.aws

# install eb command
pip install --upgrade pip
/usr/local/bin/pip install awsebcli

# completion eb command(for Bash)
echo "source /usr/local/bin/eb_completion.bash" >> $EC2_HOME.bashrc
```

# Blue環境にデプロイする

[ebコマンドを使ってElasticBeanstalkでデプロイしてみる](http://qiita.com/toshihirock/items/593e17d42a8d1d533a49)

以前書いた以下の項を実施します。

+ Webアプリの作成
+ アプリケーションの設定

ざっくり記載。詳細は記事を参照。

```
$mkdir -p git/elastic-beanstalk
$cd git/elastic-beanstalk
$git init .
$vi index.php
```

```lang:index.php
<html>
 <head>
  <title>PHP Test</title>
 </head>
 <body>
 <?php echo '<p>Hello World!</p>'; ?> 
 </body>
</html> 
```

```
$git add index.php
$git commit -m "initial check-in"
$eb init
```


上記でデプロイするアプリが作成できました。
ElasticBenstalkでは一つのアプリケーションに複数の環境を紐づけることができます。（検証、本番など）

今回は上記の環境という概念でBlueとGreenを作成して切り替えを行います。

`eb create`コマンドを使ってBlue環境の作成とデプロイを行います。デプロイ時にELBやインスタンスの起動など複数のリソースを利用するため、利用できるまで少し時間がかかります。

```
$eb create
Enter Environment Name
(default is elastic-beanstalk-dev): elastic-beanstalk-blue
Enter DNS CNAME prefix
(default is elastic-beanstalk-blue):

...以降設定のログ


INFO: Successfully launched environment: elastic-beanstalk-blue
```

完了したらeb openコマンドでアクセスして確認してみます。

```
$eb open
```

上記でHelloWorld!という表示が確認できればOKです。

実際にアクセスする際のURLも確認できます。

```
$eb status
Environment details for: elastic-beanstalk-blue
  Application name: elastic-beanstalk
  Region: ap-northeast-1
  Deployed Version: bc92
  Environment ID: e-87itv3u3d3
  Platform: 64bit Amazon Linux 2015.03 v2.0.1 running PHP 5.6
  Tier: WebServer-Standard
  CNAME: elastic-beanstalk-blue.elasticbeanstalk.com
  Updated: 2015-09-19 06:04:31.352000+00:00
  Status: Ready
  Health: Green
```

上記のCNAMEとなっている部分でのアクセスも可能です。

# Green環境にデプロイする

次にGreen環境を作成し、こちらに新しいアプリをデプロイします。

まず、Green環境の構築およびデプロイを行います。

```
$eb create  elastic-beanstalk-green
```

これでBlue環境と同じ環境となっているGreen環境の構築とアプリのデプロイを行いました。

次にCLIで現在設定されている操作対象の環境を確認します。

```
$ eb list
* elastic-beanstalk-blue
elastic-beanstalk-green
```

現在はBlue環境を操作する形になっているのですが、今後はGreen環境で操作をメインにしたいので設定を変更します。

```
$eb use elastic-beanstalk-green

$eb list
elastic-beanstalk-blue
* elastic-beanstalk-green
```

設定が変わったのでGreen環境の状態を確認します。

```
$eb open
```

現在はBlue環境と同じ情報が表示されるかと思います。
なお、デフォルトの環境を変えなくても以下のよう引数に環境を指定することでも指定環境の操作が可能です。

```
$eb open elastic-beanstalk-blue
```

# Green環境に最新のアプリをデプロイする

ソースコードを変更して最新状態にし、デプロイします。

```lang:index.php
<html>
 <head>
  <title>PHP Test</title>
 </head>
 <body>
 <?php echo '<p>Hello World!!!!!<</p>'; ?> 
 </body>
</html>
```

```
$git add .
$git commit -m "hoge fuga"
$eb deploy

eb deploy
Creating application version archive "2a32".
Uploading elastic-beanstalk/2a32.zip to S3. This may take a while.
Upload Complete.
INFO: Environment update is starting.
INFO: Deploying new version to instance(s).
INFO: New application version was deployed to running EC2 instances.
INFO: Environment update completed successfully.
```

デプロイ後、`eb open`でHello World!!!!!と表示されればOKです。

今回の例ではGreen環境はテスト環境なので、開発の都度deployし、開発者のみアクセスしてテストを行うような開発スタイルが可能です。その間もBlue環境では本番環境が問題なく動作しています。

# CNAME SwapでBlue環境のURLでGreen環境にアクセスする

Green環境のアプリのテストも終わったので、本番環境(Blue環境)へ投入するぞ!というタイミングでCNAME Swapを使ってBlue環境へのアクセスURLでGreen環境へ向くようにします。

まず、Blue環境の状態を再度、ブラウザなどで確認します。(アクセスURLはeb statusコマンドのCNAME)問題なければ「Hello World!」と表示されるはずです。今回の例ではそれぞれのCNAMEは以下のようになっているとします。

+ Blue->http://elastic-beanstalk-blue.elasticbeanstalk.com/
+ Green->http://elastic-beanstalk-green-kqzyhtmmze.elasticbeanstalk.com/

では`eb swap`コマンドを使ってBlueとGreenのCNAMEを変更します。

```
$ eb list
elastic-beanstalk-blue
* elastic-beanstalk-green

$eb swap elastic-beanstalk-blue
ERROR: InvalidShapeReferenceError :: Invalid model, missing shape reference: OrderedDict([(u'type', u'structure'), (u'members', OrderedDict([(u'User', OrderedDict([(u'shape', u'Double')])), (u'Nice', OrderedDict([(u'shape', u'Double')])), (u'System', OrderedDict([(u'shape', u'Double')])), (u'Idle', OrderedDict([(u'shape', u'Double')])), (u'IOWait', OrderedDict([(u'shape', u'Double')])), (u'IRQ', OrderedDict([(u'shape', u'Double')])), (u'SoftIRQ', OrderedDict([(u'shape', u'Double')]))]))])
```

まさかの内部エラー。。。ぐぬぬぬ・・・他の方も同様の事象が発生しているようなのでebの問題なのかもしれません。。

AWS CLIでもできるようなのでそちらでやってみます。

```
$aws elasticbeanstalk swap-environment-cnames --source-environment-name elastic-beanstalk-green --destination-environment-name elastic-beanstalk-blue
```

これで切り替わったはずなので確認します。

```
$eb status
Environment details for: elastic-beanstalk-green
  Application name: elastic-beanstalk
  Region: ap-northeast-1
  Deployed Version: 2a32
  Environment ID: e-z5u9efeudu
  Platform: 64bit Amazon Linux 2015.03 v2.0.1 running PHP 5.6
  Tier: WebServer-Standard
  CNAME: elastic-beanstalk-blue.elasticbeanstalk.com
  Updated: 2015-09-19 08:39:53.378000+00:00
  Status: Ready
  Health: Green
  
$eb status elastic-beanstalk-blue
Environment details for: elastic-beanstalk-blue
  Application name: elastic-beanstalk
  Region: ap-northeast-1
  Deployed Version: bc92
  Environment ID: e-87itv3u3d3
  Platform: 64bit Amazon Linux 2015.03 v2.0.1 running PHP 5.6
  Tier: WebServer-Standard
  CNAME: elastic-beanstalk-green-kqzyhtmmze.elasticbeanstalk.com
  Updated: 2015-09-19 08:39:53.378000+00:00
  Status: Ready
  Health: Green
```

Green環境とBlue環境のCNAMEが変わっているのが確認できます。

また、Blue環境（本番）のURL

http://elastic-beanstalk-blue.elasticbeanstalk.com/

にアクセスすることで「Hello World!!!!!!」という表示がされます。なお、内部的にRoute53のCNAMEの付け替えとなっているようで、切り替え後すぐに表示が変わらない場合もありますが、少し時間が経てば表示ができるはずです。

最新環境で動作が問題ないよであればBlue環境は破棄し、新規に新環境を作ってテスト、リリース時にCNAME Swapにより切り替えとすれば最初に割り当てたURLでの運用が可能です。(実際はRoute53でドメインを割り当てると思いますが。。）

また、仮に最新版で動作に不具合がある場合もCNAME Swapを再度行うことで旧環境に戻すことも簡単にでき、安心に運用ができます。

# 掃除

以下で今回作成したそれぞれの環境とアプリケーションを削除します。

```
$eb terminate elastic-beanstalk-blue

$eb terminate elastic-beanstalk-green

# 上記が消えてからアプリケーションは削除
$aws elasticbeanstalk delete-application --application-name elastic-beanstalk

```

# 最後に

+ CLIによる操作(ebコマンドとAWS CLI)のみでアプリのデプロイが簡単にできるのは面白い
+ CNAME Swapで簡単にBlueGreenDeploymentができる
+ DockerやECSもElasticBeanstalkはサポートしているのでDockerのBlueGreenDeploymentも簡単にできる？
+ 今ならELBの付け替えができるのでElasticBeanstalkでも簡単にやれる仕組みが欲しい（やろうと思えばできるような気もしますが。。。）