GitHub Actions を利用して ECS on Fargate にデプロイ

# 実施する内容

https://docs.github.com/ja/actions/deployment/deploying-to-your-cloud-provider/deploying-to-amazon-elastic-container-service

- 上記ドキュメントを参考に、GitHub Actions を使用してコンテナ化されたアプリケーションを構築し、ECR に push し、push をトリガーがに ECS(Fargate) にデプロイする。
- Workflow file を理解する。

なお、ドキュメントの Workflow file では、`Unsupported deployment controller: ECS` となり、Fargate では実行できませんでした。
そのため、下記の通りサンプルとして用意されているものを利用していこうと思います。

![スクリーンショット 2022-11-14 22.44.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/0cc750ea-81c0-2848-9c1a-981247eb2b4c.png)

# 準備

## 1.ECRリポジトリ の準備

AWS CLI を利用して、ECRリポジトリ を作成します。

```
aws ecr create-repository \
    --repository-name my_ecr_repository \
    --region ap-northeast-1
```

## 2.Amazon ECS タスク定義、クラスター、サービスの作成の準備

今回は以下のリンクから サンプルを作成しますが、既存で動いているコンテナを利用しても構いません。

https://ap-northeast-1.console.aws.amazon.com/ecs/home?region=ap-northeast-1#/firstRun

## 3.Amazon ECS タスク定義を GitHub リポジトリに保存

Amazon ECS タスク定義を JSON ファイルとして GitHub リポジトリに保存します。

```
aws ecs describe-task-definition --task-definition first-run-task-definition > task-definition.json
```

ここで重要なのはドキュメントに以下の通り記載がありました。

**The format should follow the output of `aws ecs register-task-definition --generate-cli-skeleton`.**

describe-task-definition で取得した JSON はそのままでは register-task-definition で登録できないため、次のページを参考に修正しておきます。

https://dev.classmethod.jp/articles/describe-task-definition-to-register-task-definition/

## 4.IAMアクセスキーをGitHub Actions Secrets に保存

AWSのIAMでアクセスキーを作成し、`アクセスキー` と　`シークレットキー` を控えておきます。

```
aws iam create-access-key --user-name MyUser
```

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-services-iam-create-creds.html

なお、IAMポリシーにおいては、次の二つのポリシーが付与されていれば良いですが、A WSのベストプラクティスに沿って、必要最小限の権限で作成しましょう。

**AmazonEC2ContainerRegistryPowerUser**
**AmazonECS_FullAccess**

画面右上の「Setings」から「Secrets」の「Actions」を開き、「New repositiry secret」をクリックします。
![スクリーンショット 2022-11-14 23.21.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/e79bfd03-8d79-9dae-696a-ed991b9cbb26.png)

Name に `AWS_ACCESS_KEY_ID` 、Secret に先程控えた IAM の`アクセスキー`をコピペし、「Add secret」をクリックします。
![スクリーンショット 2022-11-14 23.22.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/a4a0e720-3fa8-84c4-cba1-27752f818b25.png)

`AWS_SECRET_ACCESS_KEY` も同様に作成します。

# ワークフロー

## 1. GitHub Actions ワークフローの追加

「Action」 から、`Deploy to Amazon ECS` を「Configure」。
![スクリーンショット 2022-11-14 22.44.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/4d641080-3531-b741-d553-4fd42d42888b.png)

`.github/workflows/` 配下に yaml 形式で作成されます。

## 2.ワークフローファイルの修正

`env:`の環境変数をご自身の環境に変更します。

### name

ワークフローの名前です。

```yaml:
name: Deploy to Amazon ECS
```

### on

トリガーを指定します。
ここでは、main ブランチに、push されたときに、GitHub Actions が動作します。

```yaml:
on:
  push:
    branches: [ "main" ]
```

https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows

### env

環境変数を定義します。

```yaml:
env:
  AWS_REGION: ap-northeast-1                   # set this to your preferred AWS region, e.g. us-west-1
  ECR_REPOSITORY: githubactions          # set this to your Amazon ECR repository name
  ECS_SERVICE: sample-app-service                 # set this to your Amazon ECS service name
  ECS_CLUSTER: default                 # set this to your Amazon ECS cluster name
  ECS_TASK_DEFINITION: task-definition.json # set this to the path to your Amazon ECS task definition
                                               # file, e.g. .aws/task-definition.json
  CONTAINER_NAME: sample-app           # set this to the name of the container in the
                                               # containerDefinitions section of your task definition
```

https://docs.github.com/ja/actions/using-workflows/workflow-syntax-for-github-actions#env

### permissions

デフォルトでは[`GITHUB_TOKEN`](https://docs.github.com/ja/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) に付与された多くのアクセス権限を持ちます。
必要に応じて必要最小限のアクセスのみを許可することができます。

```yaml:
permissions:
  contents: read
```

https://docs.github.com/ja/actions/using-workflows/workflow-syntax-for-github-actions#permissions

### jobs

実際に何を実行するかを定義していきます。いくつかの階層に分けて詳しく確認していきます。

ジョブを定義します。ここでは、deploy ジョブで、GitHub がホストする仮想マシン、ubuntu-latest で実行するように、`runs-on` で、指定しています。
利用可能なホストは次のドキュメントにある通りです。

https://docs.github.com/ja/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on

```yaml:
jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
```

ジョブで実行されるすべてのステップを定義します。まず、最初の Checkout アクションでは、`uses` で、actions/checkout@v3 を利用しリポジトリへのチェックアウトが行われます。

このアクションは、以下で公開されています。

https://github.com/actions

https://github.com/marketplace

```yaml:
    steps:
    - name: Checkout
      uses: actions/checkout@v3
```

`with` で環境変数として指定した情報を利用して、受け渡しています。
なお、環境変数の種類やルールについてはまた別の機会にでも書こうと思います。

```yaml:
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ${{ env.AWS_REGION }}
```

`id` は各アクションidを定義します。
Login to Amazon ECR で、login-ecr を定義し、次の Build, tag, and push image to Amazon ECR で、steps.login-ecr 〜 で指定されていることがわかります。

```yaml:
    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1

    - name: Build, tag, and push image to Amazon ECR
      id: build-image
      env:
        ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        IMAGE_TAG: ${{ github.sha }}
      run: |
        # Build a docker container and
        # push it to ECR so that it can
        # be deployed to ECS.
        docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
        docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
        echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
```

以下これまでの機能を利用して、アクションが実行されます。

```yaml:
    - 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.ECS_TASK_DEFINITION }}
        container-name: ${{ env.CONTAINER_NAME }}
        image: ${{ steps.build-image.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: ${{ env.ECS_SERVICE }}
        cluster: ${{ env.ECS_CLUSTER }}
        wait-for-service-stability: true
```

# 動作確認

ディレクトリ階層は、シンプルにこんな感じです。

```
.
├── .github/workflows
│   ├── aws.yml
├── conf
│   ├── my-httpd.conf
├── Dockerfile
├── task-definition.json
```

`conf/my-httpd.conf ` と `Dockerfile` は適当に作成します。

```conf:conf/my-httpd.conf
ServerName localhost:80

Header add DUMMY_HEADER DUMMY_VALUE
```

```Dockerfile:Dockerfile
FROM httpd:2.4

RUN mkdir /usr/local/apache2/conf/include/ &&  echo 'Include conf/include/*.conf ' >> /usr/local/apache2/conf/httpd.conf

COPY ./conf/*.conf   /usr/local/apache2/conf/include/
```

GitHub へ反映します。

```git:
git add .
git commit -m "first github actions"
git push
```

「Action」から、実行されたワークフローをクリックします。
![スクリーンショット 2022-11-16 19.50.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/6ad4b678-45cc-1f56-e93c-f6046f88beff.png)

次の通り、実行されたジョブの内容を確認できるようになっています。
![スクリーンショット 2022-11-16 19.50.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/e274bca3-c347-cee0-bf95-5584474c8f24.png)

今回のケースにおいては、Code兄弟を利用する方が良いでしょうが、GitHub Actionsの学習のために試してみました。