CircleCIとCodeDeployの連携による開発自動化の実践（続）

[こちら](http://qiita.com/c-cho/items/f0d4ee933232dde64ae0)の記事ではCircleCIとCodeDeployの、基本的な連携しかたを紹介しました。この記事では、ステージング環境と本番環境のデプロイを分離する手順を紹介したいと思います。

#考え方
作成しやすさとセキュリティのバランスを配慮した結果、最初の記事で作成した以下を使いまわします。  

- IAMロール 
- CodeDeployのアプリケーション 
- CircleCIがデプロイを行うためのIAMユーザ 

一方、以下は新しく作成します。  

- リビジョン保存用のS3バケット
- CodeDeployのアプリケーション内のデプロイグループ（deploy_group）

また、インスタンスとブランチの関係は以下。  

- 本番環境 → 今まで使用したインスタンスを使いまわす
- ステージング用の環境 → 新しく作成
- GitHubのproductionブランチ → 本番環境用ブランチ 
- GitHubのmasterブランチ → ステージングのブランチ

#EC2インスタンスを作成
今までのインスタンス作成との違いはあんまりありません。但し、IAMロールの付与を忘れないでください。
今回は前回のロールを使いまわすので、既に作った「CodeDeploy-CHO-EC2」を選びます。
また、今までタグの方は「CodeDeploy/CircleCI」と設定していましたが、同じ設定にしてしまうと、ステージング環境と本番環境の区別が無くなり、両環境へ当時にデプロイされますので、タグを変える必要があります。
それぞれを「CodeDeployType/Staging」と「CodeDeployType/Production」にすればいいかと思います。

#S3バケットを追加
ステージング環境用のS3バケットを作成します。「dummy-staging」とします。今後、masterブランチのコミットによって作成されるリビジョンはdummyではなく、この「dummy-staging」に保存されるはずです。

#CodeDeployアプリケーションのデプロイグループを追加
DummyApplicationの元に、「CircleCI-Staging-Deploy-Group」という新しいデプロイグループを追加します。EC2タグを「CodeDeployType/Staging」に設定します。サービスロールを使いまわすので、「CircleCI-Deploy-Group」と同じく、「CodeDeploy_DummyApplication」に設定します。
同時に、「CircleCI-Deploy-Group」のEC2タグを「CodeDeployType/Production」に変えます。

#サービスロールにステージングのリソースを追加
今までの「CodeDeploy-CHO-EC2-Permissions」のリソースには``"arn:aws:s3:::dummy/*"``しかありませんでしたので、
ステージングリビジョンの保存先(dummy-staging)を入れます。そうしなければ、リビジョンをダウンロードする権限がないので、CodeDeployのDownloadBundleステップでAccess Deniedエラーが出ます。

```json:CodeDeploy-CHO-EC2-Permissions
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": [
                "arn:aws:s3:::dummy/*",
                ↓↓↓↓↓↓NEW↓↓↓↓↓↓
                "arn:aws:s3:::dummy-staging/*"
            ]
        }
    ]
}
```

#CircleCI専用ユーザの権限を修正
同じ理屈で、IAM内からCircleCI専用ユーザの権限を変えます。修正後のデータはこんな感じです。

```json:CircleCI-deployment-S3-IAM-policy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1XXXXXXXXX000",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::dummy/*",
                ↓↓↓↓↓↓NEW↓↓↓↓↓↓
                "arn:aws:s3:::dummy-staging/*"
            ]
        }
    ]
}
```

#CircleCIの設定ファイルを変更
最後に、circle.ymlを変えなければいけません。
CircleCIはステージング環境と本番環境のデプロイを分離することをサポートしています。というか、そもそもデプロイメントに名前をつける必要があります。今回、「staging」と指定した部分はステージング環境のデプロイの設定情報で、「production」と指定した部分は本番環境に関する設定情報にします。
こんな感じになると思います。

```yaml:circle.yml
deployment:
    staging:
        branch: master
        codedeploy:
            DummyApplication:
                application_root: /
                revision_location:
                    revision_type: S3
                    s3_location:
                            bucket: dummy-staging
                            key_pattern: dummy-{BRANCH}-{SHORT_COMMIT}
                region: ap-northeast-1
                deployment_group: CircleCI-Staging-Deploy-Group
                deployment_config: CodeDeployDefault.AllAtOnce
    production:
        branch: production
        codedeploy:
            DummyApplication:
                application_root: /
                revision_location:
                    revision_type: S3
                    s3_location:
                        bucket: dummy
                        key_pattern: dummy-{BRANCH}-{SHORT_COMMIT}
                region: ap-northeast-1
                deployment_group: CircleCI-Deploy-Group
                deployment_config: CodeDeployDefault.AllAtOnce
```

#注意点
##環境違い
前回の記事の中でも書かれていますが、appspec.ymlを通して、CodeDeployに「どのファイルをどのフォルダに置くか」を教える必要があります。全く同じ環境であれば問題ありませんが、例えば、Javaのウェブアプリをデプロイする場合、ステージング環境でしたら、Tomcatのディレクトリはtomcat8で、本番環境はtomcatとなると、destinationにどういうディレクトリ名を書けばいいでしょうか？
その場合、appspec.ymlで用意してくれたhookを使用し、tomcatのディレクトリを見つけてくれるスクリプトを実行してくれるように設定すべきだと思います。

##使いまわし
さらに、IAMロールとCodeDeployのアプリケーションの使いまわしによって、セキュリティ上がまずければ、分けることも可能です。しかし、IAMユーザは１つのCircleCIプロジェクトあたりに１つしか使えない（「CONTINUOUS DEPLOYMENT」の「AWS CodeDeploy」に入れられるキーペアは１つしかない）ため、IAMロールは使いまわすしかありません。

![image](https://qiita-image-store.s3.amazonaws.com/0/129176/fa70d3b3-77d7-7154-713f-43275244d6f3.png)

これで、GitHubのmasterブランチのコミットがステージングのインスタンスへ反映され、productionブランチのコミットが本番インスタンスへ反映されるはずです。

#参考
1. [AWS CodeDeploy AppSpec File Reference](http://docs.aws.amazon.com/codedeploy/latest/userguide/app-spec-ref.html)