猿でも出来るECR + ECS自動化最強githubactionsを晒す

## はじめに

プロジェクトによってインフラ構成の違いはありますが、みなさんは快適なデプロイフロー組めてますか？
自分は今週にフルスクラッチでサービスをリリースする事が出来ました。
その際にインフラ構成にECSを採用しました。

前職でもECSを使っており、もうEC2には戻れない体になってしまいました。。

そしてgithub actionsが正式にリリースされてからその魅力に取り憑かれてしまい、前職の会社でも色んな物を無人化していました。
前職は大きな会社だった為、prdへのデプロイは最新の注意が図られていた為、approveも無いgithub actionsでprdへのデプロイは少し難しい環境でした。

codepipelineもapprove, blue/greenが魅力的ですが、体制が整っておらず速度を求められるスタートアップや、個人開発だとこのデプロイで事足りると思います！

## 前提
- cluster,service,taskは事前に用意して下さい(環境別に命名規則を決めておいて下さい)

今回の場合では下記の様に設定しています。(prdの場合)適宜読み直して下さい
- cluster -> prd-api
- ecs-task-definition -> prd-api
- container-name -> prd-api
- service -> prd-api


## さあこれが最強デプロイだ！

```yaml
on:
  push:
    branches:
      - master
      - deploy/production
env:
  INTERMEDIATE_TASK_DEFINITION: task-definition.json
  ECR_REPOSITORY: レポジトリ名入れてね
name: Deploy to ECS
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: Set variables
        id: variables
        run: |
          if [ "${{ github.ref }}" == "refs/heads/deploy/production" ]; then
            env="prd"
          else
            env="stg"
          fi
         // ここら辺に命名規則
         // 環境を切り替えて変数をセットしていきます。
          echo "::set-output name=env::$env"
          echo "::set-output name=ecs-task-definition::$env-api"
          echo "::set-output name=container-name::$env-api"
          echo "::set-output name=service::sw-$env-api"
          echo "::set-output name=cluster::sw-$env"
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          // githubのsecretにecrとecsのポリシーをアタッチしたIAMを同じ名前でセットして下さい
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1
      // loginします
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1
    
      - name: Set ECR repository name
        id: repository-name
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        run: |
          IMAGE_TAG=$(echo ${{ github.sha }} | cut -c 1-7)
          echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
      
      // dockerをbuildします。ここは各プロジェクトによって変わると思います。
      // 複数のコンテナの場合も下で説明します。
      - name: Build and push image to Amazon ECR
        id: build-image
        if: "steps.variables.outputs.env != 'prd'"
        run: |
          docker build -t ${{ steps.repository-name.outputs.image }} --build-arg version=$IMAGE_TAG .
          docker push ${{ steps.repository-name.outputs.image }}

      // 現在のtask-definitionを取得して、上で設定したtask-definition.jsonで書き込みます。
      - name: Fetch current task definition
        run: |
          aws ecs describe-task-definition --task-definition ${{ steps.variables.outputs.ecs-task-definition }} --query taskDefinition | \
          jq '(del(.revision, .requiresAttributes, .compatibilities, .taskDefinitionArn, .status))' > ${INTERMEDIATE_TASK_DEFINITION}

      // 新しいタスクでサービスを更新します
      - name: Fill in the new image ID in the Amazon ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: ${{ env.INTERMEDIATE_TASK_DEFINITION }}
          container-name: ${{ steps.variables.outputs.container-name }}
          image: ${{ steps.repository-name.outputs.image }}

      // デプロイ！
      - name: Deploy Amazon ECS task definition
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          service: ${{ steps.variables.outputs.service }}
          cluster: ${{ steps.variables.outputs.cluster }}
          wait-for-service-stability: false
```

## 終わり
まあawsのブログ見たら載ってるんだけどな。。

開発フローとしては
- prベースでmasterにマージ
- stg環境にデプロイされる
- prd環境デプロイする為には最新のimageからデプロイする為にローカルのmasterからoriginのdeploy/productionにpushする

この様なフローをとる必要があるので注意して下さい！