LaravelアプリケーションをCodePipeline/CodeBuildでECSに自動デプロイする

## はじめに
`github`にソースをpushするだけで、自動的にアプリケーションがECS環境にデプロイされるように、`CodePipeline`を作成します。
尚、ECS環境の構築については、下記の記事を参照ください。

- [LaravelアプリケーションをローカルでもAWSでもDockerで動かす](https://qiita.com/imunew/items/1e4826030d725beb4710)

## パイプラインの作成
`CodePipeline`の`パイプラインの作成`ボタンからウィザードに従ってパイプラインを作成していきます。

### 名前

| 項目 | 値 |
| --- | --- |
| パイプライン名 | (任意) |

### ソース

| 項目 | 値 |
| --- | --- |
| ソースプロバイダ | github |
| リポジトリ | imunew/laravel-ecs-demo |
| ブランチ | master |
| ビルドプロバイダ | AWS CodeBuild |

### ビルド

| 項目 | 値 |
| --- | --- |
| プロジェクト名 | (任意) |
| 環境イメージ | AWS CodeBuild マネージド型イメージの使用 |
| OS | Ubuntu |
| ランタイム | Docker |
| バージョン | aws/codebuild/docker:17.09.0 |
| ビルド仕様 | ソースコードのルートディレクトリの buildspec.yml を使用 |
| VPC ID | 非 VPC |
| 環境変数 | AWS_ACCOUNT_ID <br /> PROJECT_NAMESPACE |

#### buildspec.yml
下記のドキュメントを参考に、`buildspec.yml`を作成しました。

- [CodePipeline で ECS にデプロイできるようになり、Docker 環境の継続的デリバリも簡単になりました ｜ Developers.IO](https://dev.classmethod.jp/cloud/aws/codepipeline-support-ecs-deploy/)

```
version: 0.2

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - pip install awscli --upgrade
      - aws --version
      - $(aws ecr get-login --no-include-email --region ${AWS_DEFAULT_REGION})
      - IMAGE_NAME_PHP_FPM=php-fpm
      - IMAGE_NAME_NGINX=nginx
      - REPOSITORY_URI_PHP_FPM=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${PROJECT_NAMESPACE}/${IMAGE_NAME_PHP_FPM}
      - REPOSITORY_URI_NGINX=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${PROJECT_NAMESPACE}/${IMAGE_NAME_NGINX}
      - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
      - IMAGE_TAG=${COMMIT_HASH:=latest}
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - docker build -t ${REPOSITORY_URI_PHP_FPM}:latest -f docker/php-fpm/Dockerfile .
      - docker build -t ${REPOSITORY_URI_NGINX}:latest docker/nginx
      - docker tag ${REPOSITORY_URI_PHP_FPM}:latest ${REPOSITORY_URI_PHP_FPM}:$IMAGE_TAG
      - docker tag ${REPOSITORY_URI_NGINX}:latest ${REPOSITORY_URI_NGINX}:$IMAGE_TAG
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker images...
      - docker push ${REPOSITORY_URI_PHP_FPM}:latest
      - docker push ${REPOSITORY_URI_PHP_FPM}:$IMAGE_TAG
      - docker push ${REPOSITORY_URI_NGINX}:latest
      - docker push ${REPOSITORY_URI_NGINX}:$IMAGE_TAG
      - echo Writing image definitions file...
      - IMAGE_DIFINITION_PHP_FPM="{\"name\":\"${IMAGE_NAME_PHP_FPM}\",\"imageUri\":\"${REPOSITORY_URI_PHP_FPM}:${IMAGE_TAG}\"}"
      - IMAGE_DIFINITION_NGINX="{\"name\":\"${IMAGE_NAME_NGINX}\",\"imageUri\":\"${REPOSITORY_URI_NGINX}:${IMAGE_TAG}\"}"
      - echo "[${IMAGE_DIFINITION_PHP_FPM},${IMAGE_DIFINITION_NGINX}]" > imagedefinitions.json
artifacts:
    files: imagedefinitions.json
```

### デプロイ

| 項目 | 値 |
| --- | --- |
| デプロイプロバイダ | Amazon ECS |
| クラスター名 | laravel-ecs-demo-cluster [^1] |
| サービス名 | laravel-ecs-demo [^1] |
| イメージのファイル名 | (空欄) |

[^1]: 『[LaravelアプリケーションをローカルでもAWSでもDockerで動かす](https://qiita.com/imunew/items/1e4826030d725beb4710)』にて作成したクラスターとサービスを指定します

### サービスロール
`CodePipeline`を実行するために必要なサービスロールを指定します。

#### 注意） `ECR(EC2 Container Registory)`へのアクセス許可
ECRへのログイン、プッシュなどが必要になるので、下記のアクションを許可します。

| 項目 | 値 |
| --- | --- |
| サービス | EC2 Container Registory |
| アクション（読み込み） | GetAuthorizationToken <br /> BatchCheckLayerAvailability |
| アクション（書き込み） | CompleteLayerUpload <br /> UploadLayerPart <br /> InitiateLayerUpload <br /> PutImag |

## パイプラインのイメージ
最終的に`master`ブランチにpushすると、自動的にデプロイされるようになりました。

![codepipeline.png](https://qiita-image-store.s3.amazonaws.com/0/26422/2e5f1e12-2962-82d4-f670-38ab8537f0c9.png)

## おわりに
`docker`で本番環境を作るのは、難しい印象を持っていましたが、AWSのサービスがどんどん充実していってるせいか、比較的簡単にできました。
コスト的には、ALB（Application Load Balancer）が、一番大きかったですが、起動しっぱなしにしなければもっと安くできます。
参考までに明細の一部を晒しておきます。

![ec2_billing.png](https://qiita-image-store.s3.amazonaws.com/0/26422/beb09e59-5da7-ddab-5bbe-553804235082.png)

ではでは。