codepipelineでソース元をBitbucketにしてECSにデプロイする方法

## そもそも
ECSの継続的デリバリー(CD)をbitbucketとcodepipelineを使ってやりたい
⇒codepipelineはソース元としてbitbucketを選択することができない
⇒なんとかできたのでメモがてら記録に残すことにしました

2019/02月現在Codepipelineのソース元として選べるのは下記4つだけ

- AWS CodeCommit
- Amazon ECR
- Amazon S3
- GitHub

Github(あるいはCodeCommit)を使えば以下流れで簡単にできる。(Dockerfile更新)
※【codepipelineのステージ】

- Source : Github
- Build  : Codebuild
- Deploy : ECS

1. GithubにDockerfileをpush
2. Codepipelineが反応してパイプライン開始
3. buildが動いてECRにイメージがpushされる
4. deployが動いてECSでリリースが完了
bitbucketでは2.のところができない。

参考：
https://dev.classmethod.jp/cloud/aws/codepipeline-support-ecs-deploy/
※基本的なところはこの記事が大変参考になりました！

## 解決方法
ECRプッシュをトリガーにする

ECRにプッシュされたことをトリガーにしたら、実現できた。
CodebuildがBitbucketが選べるのでそれを利用する。

**※一時ファイル保存先(アーティファクト)としてS3が必要。適当なS3バケットを事前に用意しておく**

1. Bitbucketにイメージをプッシュ
2. CodebuildでECRにイメージをプッシュ
3. ECRをソース元にしたCodepipelineが動く(sourceステージ)
4. Codebuild(1のとは違うやつ)でECSでデプロイする用のイメージ定義ファイルを作成(buildステージ)
5. 3のイメージ定義ファイルを元にECSでデプロイ(deployステージ)
![Untitled Diagram.png](https://qiita-image-store.s3.amazonaws.com/0/218240/3181ab58-0a74-23e3-c6cf-2fec109860d5.png)

※【codepipelineのステージ】

- Source : ECR
- Build : Codebuild
- Deploy : ECS(fargate構成)


### 1. CodebuildでECRにイメージをプッシュするまで

Codebuildの設定(ECRプッシュ用)

- ソースプロバイダは「BitBucket」
- Webhook(コードの変更がこのレポジトリにプッシュされるたびに再構築する)の設定をON
- Buildspecファイル名はデフォルトの「buildspec.yml」
- 環境変数は下記を設定

| 名前       |           値        |    入力    |
|:-----------------|-------------------------:|:---------------------:|
| AWS_DEFAULT_REGION|ap-northeast-1|PLAINTEXT|
| IMAGE_REPO_NAME|codebuild|PLAINTEXT|       
| IMAGE_TAG|latest|PLAINTEXT|
| AWS_ACCOUNT_ID|***|PLAINTEXT|

- アーティファクトの設定で事前に作成したS3を設定する。

- Bitbucketのレポジトリ構成

```shell-session
$ tree .
.
├ buildspec.yml
└ Dockerfile
```

- buildspec.yml

```yml
version: 0.2

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION)
      - REPOSITORY_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
      - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $REPOSITORY_URI:$IMAGE_TAG
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - echo "[{\"name\":\"${IMAGE_REPO}\",\"imageUri\":\"${REPOSITORY_URI}:${IMAGE_TAG}\"}]" > imageDetail.json
artifacts:
  files:
    - imageDetail.json
```

※imageDetail.jsonが先ほど設定したS3に保存される。

- Dockerfile

```dockerfile
FROM centos:centos7
RUN yum install -y httpd && date >> /var/www/html/index.html
EXPOSE 80
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
```

この状態であとはgit pushをすればCodebuildが動いてECRにプッシュされる。

ここまでCodepipeline関係ない。

---

### 2. ECRをソース元にしたCodepipelineが動く(sourceステージ)

Codepipelineのアーティファクトストアは事前に作成したS3を選択しておく。

- ソースステージの設定

![image.png](https://qiita-image-store.s3.amazonaws.com/0/218240/08d54d54-75a5-cdb2-7996-662059146a77.png)


---

### 3. Codebuild(1のとは違うやつ)でECSでデプロイする用のイメージ定義ファイルを作成(buildステージ)

- ビルドステージの設定

![image.png](https://qiita-image-store.s3.amazonaws.com/0/218240/8ce27a64-ee14-9b0f-ee78-7a15728ad15f.png)

- Codebuildの設定(デプロイ用)

- ソースプロバイダはなし。設定なしでOKです。
- Buildspecは「ビルドコマンドの挿入」から直接入力
⇒Codepipelineのソース元がECRだとCodebuildで設定したソースが反応しません。そのためソースプロバイダも設定していません。
- 環境変数は下記を設定

| 名前       |           値        |    入力    |
|:-----------------|-------------------------:|:---------------------:|
| AWS_DEFAULT_REGION|ap-northeast-1|PLAINTEXT|
| SERVICE_NAME|test|PLAINTEXT|       
| IMAGE_TAG|latest|PLAINTEXT|
| AWS_ACCOUNT_ID|***|PLAINTEXT|

- アーティファクトの設定で事前に作成したS3を設定する。

- ビルドコマンド

```yml
version: 0.2

phases:
  build:
    commands:
       - sudo apt-get update -y
       - sudo apt-get install -y jq
       - REPOSITORY_URI=$(cat imageDetail.json | jq .ImageURI | sed 's/"//g' | sed -E 's/@.*//g')
       - echo $REPOSITORY_URI
       - IMAGE_TAG=$(cat imageDetail.json | jq .ImageTags[0] | sed 's/"//g')
       - echo $IMAGE_TAG
  post_build:
    commands:
       - printf '[{"name":"'$SERVICE_NAME'","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
artifacts:
    files: imagedefinitions.json
```

---

### 4. 3のイメージ定義ファイルを元にECSでデプロイ(deployステージ)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/218240/3c298edc-2a37-2399-f822-1fe77f930836.png)

---

以上で設定は完了。
あとはBitbucketにDockerfileをpushすれば自動で全部走る。

※ECR更新に反応してくれない場合はCloudTrailの証跡作成が必要。
https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/cloudtrail-create-a-trail-using-the-console-first-time.html

## 最後に

AWSサポート様いわく、CodepipelineでもBitbucketをサポートするよう動いてるみたいなので、
楽しみにしてます。
そしたら上記のような面倒くさいことをしなくて済みます。

おかしな点、不足点、不明点などがありましたらコメントいただけると嬉しいです。