CircleCIとAWS（CodeDeploy/S3）で作るCI環境

GithubにCommitしたら、テストを実行して、EC2のWebサーバに自動的にdeployしてほしいよねーとかねがね思っている方用の手順です。EC2以外はそんなにお金かけたくないなという人もCircleCIならとっつきやすいかもしれません。
継続的イテレーションを導入すべくCIの中でも有名で1コンテナまで無料のCircleCIを導入。
以下作業メモ。

継続的イテレーション（CI）で開発したいよねって思ったら注意点ですが

- **サーバインスタンスは作り直しになる**
- **Githubから直接EC2に上げる方法もあるけど意外と情報ないのでS3とCodeDeployも使う**
- **CircleCIはCIのツールでプログラムのdeployはCodeDeployが担当するという理屈を理解**

というのがあります。私そもそもの理屈がよくわかってなかったです。

※何か作業中におかしな挙動があった場合はこちらを使って調査してみよう！
　http://qiita.com/hardreggaecafe/items/6abf9d4c6a82fcf61589

## 0.大前提

 - Githubにソースがあること
 - 本番（Production）と最終確認（Staging)など環境が分かれていること
 - 既にローカルにWebアプリ動く環境があり、本番や最終確認環境に手でファイル上げしているというケース
 - Migration使えるフレームワーク使っていて、Migrationファイルを上げてコマンド起動だけでDB修正できるようになっている
 
## 1.AWSログイン

## 2.IAMユーザ作成

![IAM Management Console0708(1).png](https://qiita-image-store.s3.amazonaws.com/0/1593/7fa975d3-dd69-7bec-1ab4-22e81ebe0414.png)

![IAM Management Console0708 2（２）.png](https://qiita-image-store.s3.amazonaws.com/0/1593/a941a211-7a21-02d3-98ae-0cb0be0d0d36.png)


 - Circleci用に新規に作成すること
 - PermissionはS3FullaccessとCodeDeployFullaccess

## 3.ServiceRoleとInstanceProfile作成

 - IAMのRoleは2種類必要（2.も参照のこと）
 - まず２つのポリシー作成（Policiesのメニューから）

``` aws:EC2
    {
    "Version": "2012-10-17",
    "Statement": [
    {
        "Action": [
        "s3:Get*",
        "s3:List*"
      ],
      "Effect": "Allow",
      "Resource": "*"
     }
     ]
    }
```

``` aws:CodeDeploy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:Get*",
        "s3:List*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
```

 - ServiceRole用にRoleを作成し以下のPermissionを追加
   - AmazonEC2FullAccess
   - AmazonS3ReadOnlyAccess
   - AWSCodeDeployRole
   - 上記CodeDeployポリシー
 - ServiceRole用のTrustRelationshipは

``` aws:ServiceRole-TrustRelationship
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "codedeploy.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

 - InstanceProfile用にRoleを作成し以下のPermissionを追加
   - 上記EC2ポリシー
 - InstanceProfile用のTrustRelationshipは

``` aws:InstanceProfile-TrustRelationship
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

## 4.EC2インスタンス作成

![EC2 Management Console0708  1 .png](https://qiita-image-store.s3.amazonaws.com/0/1593/07d9effb-e211-3742-72dc-6b24d8664ea2.png)

 - instanceはAmazonLinuxがオススメ
 - IAM Roleは新規インスタンスにしかつけられないという事情により必ず新規作成する（2017/4/17追記：AWSで後から追加できるようになったとのこと。情報提供頂きました。）
 - IAM Role はInstanceProfileを使用すること
 - ElasticIPを付与すること
 - Tagは何も入力しなければインスタンス名になるはず
 - インスタンスに名前をつけること
 - SecurityGroupはインスタンス作成時のデフォルトのものでOKで特別なものは不要
 - ElasticIPとec2-userのIDと作ったキーペアでinstanceにSSHログインする
 - 以下のコマンドを実行して内部にCodeDeployのエージェントを作成する

``` bash
sudo yum update
cd /home/ec2-user
aws s3 cp s3://aws-codedeploy-ap-northeast-1/latest/install . --region ap-northeast-1
chmod +x ./install
sudo ./install auto
```

## 5.S3バケット作成
　名前はメモっておくこと

![S3 Management Console0708(1).png](https://qiita-image-store.s3.amazonaws.com/0/1593/4f4f769a-84d1-89c5-bcba-7ccc82cfd166.png)


## 6.CodeDeployアプリ作成

![AWS CodeDeploy Management0708 2.png](https://qiita-image-store.s3.amazonaws.com/0/1593/a857d820-d1bd-35ef-a975-a6d1c71246de.png)


 - Application NameとDeployment Group Nameはcircleci.ymlに書くものなので控える
 - Add InstanceのSearch by Tags のところはEC2 instanceに付いているタグを付ける
 - Deployment Configurationはすべてのサーバを一度にデプロイか、半分だけか、一台ずつかによって設定する（AllAtOnce,HalfAtATime、OneAtATime）
 - ServiceRoleは3.で設定したServiceRoleの方の名前を指定
 
## 7.CircleCI設定

![CircleCI 0708(1).png](https://qiita-image-store.s3.amazonaws.com/0/1593/b10387ab-3f64-ed66-de83-b2b8f7ae20e2.png)

![CircleCI 0708(2).png](https://qiita-image-store.s3.amazonaws.com/0/1593/3ac04159-1507-7ee9-2362-70c943d4ad5b.png)


 - CircleCI開くとGithubでログインを求められるのでそれに従う
 - デプロイしたいプロジェクトを指定
 - あとは自動に紐付けしてくれる
 - CodeDeploy設定を探し、IAMのユーザ情報を登録する
 - この時点では絶対circle.yml（後述）をリポジトリ直下に置かないこと（処理を始めてしまう恐れあり）

## 8.デプロイ用シェル作成

 - リポジトリ直下にScriptsディレクトリを作成する
 - 配下にAppSpec.ymlからキックする予定のシェルを作成（ファイル展開の前後とかタイミングに関係している。詳細はこちら→ http://dev.classmethod.jp/cloud/aws/code-deploy-appspec/ ）
    - Scripts/BeforeInstall.sh
    - Scripts/AfterInstall.sh
    - Scripts/ApplicationStart.sh
    - Scripts/ValidateService.sh

## 9.２つのYAML（circle.yml/appspec.yml）

 - どちらもリポジトリ直下に置くこと。Githubにコミットした瞬間に起動してしまうので注意
 - YAMLは書式が間違っていないかyamllint.com などで検証すること
 - circle.yml はCircleCIの挙動を決めるもの（S3へのアップロードやCodeDeploy起動、テストなど）

``` yaml:circle.yml
test: # テストに関する記述
  override:
    - exit 0
deployment: # デプロイ詳細
  staging: # （確認環境）
    branch: staging # Githubはここのブランチ名見てプッシュと同時に動作開始
    codedeploy: # CodeDeployの設定
      wonder: # アプリ名
        application_root: /
        region: ap-northeast-1
        revision_location:
          revision_type: S3
          s3_location: # S3の設定
            bucket: xxxx-xx-dev # bucket名
            key_pattern: xxxx-{BRANCH}-{SHORT_COMMIT}
        deployment_group: xxxx-st-deploy # CodeDeployのデプロイグループ名
        deployment_config: CodeDeployDefault.AllAtOnce
  production: # （本番）
    branch: master # Githubはここのブランチ名見てプッシュと同時に動作開始
    codedeploy: # CodeDeployの設定
      wonder: # アプリ名
        application_root: /
        region: ap-northeast-1
        revision_location:
          revision_type: S3
          s3_location: # S3の設定
            bucket: xxxx-xx-dev # bucket名
            key_pattern: xxxx-{BRANCH}-{SHORT_COMMIT}
        deployment_group: xxxx-ms-deploy # CodeDeployのデプロイグループ名
        deployment_config: CodeDeployDefault.AllAtOnce
```

 - appspec.yml はCodeDeployの挙動を決める（S3のBucketからデータ取ってどの順番に作業するのかなど）

``` yaml:appspec.yml
version: 0.0
os: linux # このあたりはお約束なのでそのまま記述すること
 
files: 
# You can specify one or more mappings in the files section.
  - source: /
    destination: /home/ec2-user # 他が良ければ事前にユーザ名、ディレクトリは作成すること
hooks:
  BeforeInstall:
    - location: Scripts/BeforeInstall.sh # このシェルを作成して中にMigrationなどの処理を記入
  AfterInstall:
    - location: Scripts/AfterInstall.sh
      timeout: 60
  ApplicationStart:
    - location: Scripts/ApplicationStart.sh
      timeout: 60
  ValidateService:
    - location: Scripts/ValidateService.sh
      timeout: 60
```

以上、設定完了と同時にデプロイが起動するので、ファイルがEC２に上がって、CircleCIがOKと表示されるのをCircleCIのコンソールから確認すること。Slack連動していれば結果を送信することも可能。