AWS Fargate, Github Actionsを利用したアプリケーションの開発から配布まで

# 入る前に
本記事で話そうとしてる主な内容は「こんなことを利用したら、こんなに簡単アプリの開発からDeployまでの環境が作れるんだ！」みたいの感じを紹介する記事であります。AWS、Dockerなどの技術の細かい設定や使い方、Goのアプリについて深い話は書いてないのでこの点認識してください。
各細かい内容については今後順次に書いて行く予定であります。

# 登場人物
- AWS IAM
- AWS ECR
- AWS ECS
- AWS ALB, EC2
- AWS Parameter Store
- Github Actions
- Docker
- Go

本記事では上記の内容似ていての設定方法などを細かくは案内しません。
躯体的な使い方についてはDocumentや、Hands Onなどを参考してください。
もし、Github Actionsについてお気になる方は自分が書いた[この記事](https://qiita.com/KIMSeongJoo/items/286097f5a8c9cf1520e5)を参考してください。

本日作業結果の予想図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76353/b9565727-1dfc-0c22-ef6d-557e599e44b8.png)


# 作業の流れ
1. Dockerを利用したContainer環境構築
2. Goを利用したアプリ作成
3. Local環境起動確認・テスト
4. AWS設定
5. Github Actions設定
6. テスト

の流れになります。じゃぁ始めましょうか！

### 1. Dockerを利用したContainer環境構築
- goが設定されてるAlphineLinuxを使う予定です。
- TimeZone設定を行います。
- ModuleをInstallします。
- Buildします。

```Dockerfile
## go lang install
FROM golang:1.14.2-alpine3.11

## pakcage update & install
RUN apk add --update curl git pkgconfig curl-dev  &&  \
    go get github.com/cespare/reflex

## timezone update
RUN apk add tzdata
ENV TZ=Asia/Tokyo

## setting enviroment variables
ENV GO111MODULE "on"
ENV ENV "prod"

## source code copy
WORKDIR /go
COPY . /go/src

## module install
WORKDIR /go/src
RUN go install

## go build
RUN go build ./main.go

## container listen port
EXPOSE 8080

## command
## start
CMD ["./main"]
```
このようになります。

### 2. Goを利用したアプリ作成
- [go json-rest](https://github.com/ant0ine/go-json-rest)このModuleを利用する予定です。
    - この記事で扱うアプリの元もこのModuleの例文になります。
- Go moduleを利用するため、環境変数``GO111MODULE=on``を設定します。
- ``go mod init {{mod name}}``を利用し ``go.mod``を作成します。
    - この記事でのmodは``exmaple.com/m``で設定してます。

[参考コード](https://github.com/ant0ine/go-json-rest#countries)

### 3. Local環境起動確認・テスト
- docker build
- postman, curlなどを利用してテスト

```shell
docker build -t qiita_test .
docker run -p 8080:8080 qiita_test:latest
```
postman でリクエストを投げて見ましょう！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76353/d108c908-8ea0-b194-dfe2-878b0cbfe6ad.png)
おぉ！ Accessログ出ますね　やった！
![Screenshot at Sep 06 13-05-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76353/89982f30-2556-1ce0-b797-1518cf30676d.png)
### 4. AWS設定
- IAM 設定
    - Github Actionが利用するDeployユーザーを作成
        - 権限はECR,ECS,Parameter Store権限を付与します。
        - 作成時　AccesToken、Keyを保存しましょう。
        ![Screenshot at Sep 06 13-44-24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76353/1db64bd4-8aa7-72ba-542d-770b837db18e.png)
    - FargateのTaskが使うRoleを設定します。
        - ecsTaskExecutionRole　この名がDefaultです。
        ![Screenshot at Sep 06 13-51-39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76353/898a9d3b-6f8b-3b67-9ebc-2323d9bd8dc4.png)

- Parameter Store 設定
    - Dockerを利用するときに、環境変数設定が必要な場合は利用します。
        - SystemManater > Parameter Storeでkey-valueで設定します。
- Security Group 作成
    - 利用するポートを許可します。　この例では8080をOpenします。
- ALB 作成
    - Public Subetを設定します。
    - Public DNSが使える状態もしくはHTTPS設定を利用して使えるDNS設定を行います。
- ECR 作成
    - repositoryを作成します。
- ECS 設定
    - task作成
        - Containerを設定するときに環境変数でvalueFromで、値を設定します。
    - cluster作成
    - service作成

### 5. Github, Github Actions設定
- Trigger
    - push
- Target Branch
    - master
- doing
    - docker build
    - ECR push
    - task-definitionを利用したデプロイ作業

```yaml
### main.yml
name: test workflow for qiita
on:
  push:                             # event trigger on push
    branches: master

jobs:
  build:                             # job id
    name: sjkim action               # job name
    runs-on: ubuntu-latest           # virtual os
    steps:
      - name: set up go 1.14
        uses: actions/setup-go@v1
        with:
          go-version: 1.14

      - name: Checkout branch go module directory
        uses: actions/checkout@v2

      - name: package install
        uses: actions/cache@v2
        with:
          path: ~/go/pkg/mod
          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
          restore-keys: |
            ${{ runner.os }}-go-

      - 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: ap-northeast-1

      - 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 }}
          ECR_REPOSITORY: qiita-test
          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"

      - 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: task-definition.json
          container-name: qiita-container
          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: qiita-service
          cluster: qiita-test-cluster
          wait-for-service-stability: true
```
Github Actions marketplaceにある[ECS Deploy](https://github.com/marketplace/actions/ecs-deploy)を元に作成してます。

#### Github Secrets Point
- {{ secrets.AWS_SECRET_ACCESS_KEY }} などで利用可能
- setting > secrets > new secrets
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76353/70a8c958-dd11-d4d0-b1a4-57c3415f171f.png)


task-definition.json

```json
{
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "inferenceAccelerators": [],
  "containerDefinitions": [
    {
      "name": "qiita-container",
      "image": "***/qiita-test",
      "resourceRequirements": null,
      "essential": true,
      "portMappings": [
        {
          "hostPort": 8080,
          "containerPort": "8080",
          "protocol": "tcp"
        }
      ],
      "secrets": [
        {
          "name": "ENV",
          "valueFrom": "dev"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/qiita-test",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "qiita"
        }
      }
    }
  ],
  "volumes": [],
  "networkMode": "awsvpc",
  "memory": "512",
  "cpu": "256",
  "executionRoleArn": "****/ecsTaskExecutionRole",
  "family": "qiita-task",
  "taskRoleArn": "",
  "placementConstraints": []
}

```

#### task-definition point
- ECS-task設定
- container 情報
- Log出力先設定
- AWS Parameter Store設定（Docker起動時に設定する感じ）

### 6. テスト
じゃぁここまで来たらほぼ準備は終わってます。
実装をしてみましょう！

- GithubのMasterブランチへPushしたら、Github Actionsが起動されます。
- その流れによって、ECSにデプロイ作業が開始されます。
- 作業が終わったら、AWS管理ページを確認し、EC2＞ターゲットグループチェックします。
- Public DNSや、利用してるDNSを利用してAPIが叩けるのか確認します！


# 結論
今回私も初めてこのような構成でアプリケーションの開発を行ってみました。
AWSの知識が浅かったのでかなり苦労した記憶が残ってますが、かなりいい方法の構成かな…と思ってるのでこれを利用してPJをどんどん拡張していきたいなと思います。
Firelensなどを利用したLog設定や、GithubActions、AWS SNSを利用したアラーム設定、などもどんどん入れてみたいなと思ってます。

おそらくこの記事である情報だけではアプリがそこまで簡単には作られないかもしれません、
でも、この記事の内容を元にし、皆さんのPJや、悩みに小さいHINTになったら嬉しいです。

本日案内したコードは[ここ](https://github.com/KIMSeongJoo/qiita_test)を参考してください。