GItHub Actionsを使ったCI/CDの構築について

## 初めに
エンジニアとして働き始めて2年目であり、極力気をつけましたが誤った情報を発信しているかもしれません。
その際はぜひコメントにてご指摘いただければ幸いです。

## CI/CDとは
CI/CDとは「Continuos Integration(CI)」と「Continuous Delivery/Deployment(CD)」の略称となります。

### CIについて
複数の開発者がコード変更を頻繁にリポジトリに統合（インテグレーション）し、各統合で自動化されたビルドやテストで検証します。

- エラーの早期発見
  - 新しいコードが既存のコードと統合される度に、自動的にビルドとテストが実行されるため、失敗した場合バグやエラーの早期発見につながる
- 共同開発の促進
  - 様々な開発者が各々ローカルでIDEを使用し、コードを変更を加えるとマージした際、多くの競合（コンフリクト）が発生し得る。コード変更がリポジトリに頻繁にプッシュされることにより、コードの競合を減らす事ができます。
- 自動化されたテストとビルドによるフィードバック
  - 自動化されたテストやビルドにより、開発者自身が変更の影響をすぐに知る事ができます。また必要な対応も迅速に行う事ができます。


### CDについて
CDは「継続的デリバリー」又は「継続的デプロイメント」を指します。
CIで自動化されたテスト、及びビルドされた検証済みコードを自動的にリリースする事です。

- 継続的デリバリー
  - 新しい機能や修正を開発、検証、本番などの環境にデプロイする準備を整える役割を持ちます。
  - 開発者によるアプリケーションへの変更に対して、バグがないかを自動的にテストし、リポジトリにアップデートします。

- 継続的デプロイメント
  - リポジトリから開発、検証、本番などの環境への開発者による変更のリリースを自動化し、クライアントが利用できるようするというものです。

### CI/CDに利用できるツール一覧

#### 1. Jenkins
- **概要:** オープンソースの自動化サーバーで、多くのプラグインを利用して自分のニーズに合わせてカスタマイズ可能です。
- **公式サイト:** [https://www.jenkins.io](https://www.jenkins.io)

#### 2. GitLab CI/CD
- **概要:** GitLabリポジトリにネイティブに組み込まれたCI/CDツールで、シンプルな統合と強力な機能を提供します。
- **公式サイト:** [https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/](https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/)

#### 3. CircleCI
- **概要:** 高性能かつスケーラブルなCI/CDツールで、Dockerサポートや多様な環境へのデプロイが可能です。
- **公式サイト:** [https://circleci.com](https://circleci.com)

#### 4. GitHub Actions
- **概要:** GitHubリポジトリと直接統合可能なCI/CDツールで、コードのすべての段階を自動化するためのワークフローを作成できます。
- **公式サイト:** [https://github.com/features/actions](https://github.com/features/actions)

#### 5. Travis CI
- **概要:** GitHubリポジトリと連携して自動ビルドとテストを行うクラウドベースのCIツールです。オープンソースプロジェクトに特に人気があります。
- **公式サイト:** [https://travis-ci.org](https://travis-ci.org)

今回はネットや弊社のナレッジが多く、ランキングサイトにも上位にランク付けされていた**Github Actions**を使用して、CI/CD環境構築していきます。

### GitHub Actionsの流れ

1.開発者が VSCode でコードを変更し、GitHub に push する。
2.GitHub Actions が push をトリガーにビルド・テストを実行し、Docker を使ってコンテナイメージを作成する。
3.GitHub Actions が作成したイメージを AWS ECR にプッシュ（アップロード）する。
4.AWS ECS が ECR に保存されたイメージをプル（取得）してコンテナを起動しデプロイが完了する。

### CI/CDの必要性

こちら自分なりに書いてたら長くなったので別記事にまとめてみました。
https://qiita.com/goat_2130/items/e7c3697949eabc8a4020

## 実装コード

### CI/CDファイル
```yml
name: ci-cd

on:
  push:
    branches:
      - '**'
      # 現在は全てのブランチのpushで作動。buildステップはdevelopのみ作動

jobs:
  ########## CI ##########
  ######### Lint #########
  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.24

      - name: Install golang ci-lint
        run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.5

      - name: Run golang ci-lint
        run: golangci-lint run --timeout=10m
  ######### Test #########
  test:
    name: Test
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set environment variables from secrets
        run: |
          echo "APP_TIMEZONE=${{ secrets.APP_TIMEZONE }}" >> $GITHUB_ENV
          echo "DB_HOST=${{ secrets.DB_HOST }}" >> $GITHUB_ENV
          echo "DB_PORT=${{ secrets.DB_PORT }}" >> $GITHUB_ENV
          echo "DB_USER=${{ secrets.DB_USER }}" >> $GITHUB_ENV
          echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> $GITHUB_ENV
          echo "DB_NAME=${{ secrets.DB_NAME }}" >> $GITHUB_ENV
          echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" >> $GITHUB_ENV
          echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> $GITHUB_ENV
          echo "REDMINE_APP_ACCESS_KEY=${{ secrets.REDMINE_APP_ACCESS_KEY }}" >> $GITHUB_ENV
          # etc...

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.24

      - name: Cache Go modules
        uses: actions/cache@v3
        with:
          path: ~/go/pkg/mod
          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
          restore-keys: ${{ runner.os }}-go-

      - name: Install dependencies
        run: go mod tidy

      - name: Run unit tests
        run: go test -v ./...
  ########## Build ##########
  build:
    name: Build
    runs-on: ubuntu-latest
    needs: [lint, test] # lint, testジョブが成功した場合のみ作動
    if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/main' # developとmainブランチのみ作動
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

        # github.event.before（前のコミット）とgithub.sha（現在のコミット）の間で変更されたファイルのリストを取得し変更の有無を変数に格納
      - name: Detect changes in codebase
        id: detect-changes
        run: |
          app2_changed="false"
          app_changed="false"
          if git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep -q '^app2/'; then
            app2_changed="true"
          else if git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep -q '^/'; then
            app_changed="true"
          fi
          echo "app2_changed=$app2_changed" >> $GITHUB_ENV
          echo "app_changed=$app_changed" >> $GITHUB_ENV

        # マルチプラットフォームのビルドを可能にするための設定
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

        # マルチプラットフォームのDockerイメージビルドをサポート、及びビルドプロセスの最適化
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

        # AWS credentialsの設定
      - name: Configure AWS credentials from IAM Role
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ap-northeast-1
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}

        # AWS CLIを使用してECRに対して認証トークンを取得
        # 認証トークンを使用してDockerクライアントがECRにログイン
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

        # Dockerイメージをビルド
      - name: Build, tag, and push docker image to Amazon ECR for app
        if: env.app_changed == true
        id: build-app-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          REPOSITORY: exapmle_repository
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker buildx build --platform linux/amd64,linux/arm64 \
            -t $ECR_REGISTRY/$REPOSITORY:$IMAGE_TAG \
            --push.
          echo "image-app=$ECR_REGISTRY/$REPOSITORY:$IMAGE_TAG" >> $GITHUB_ENV

      - name: Build, tag, and push docker image to Amazon ECR for app2
        if: env.app2_changed == true
        id: build-app2-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          REPOSITORY: exapmle_repository2
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker buildx build --platform linux/amd64,linux/arm64 \
            -t $ECR_REGISTRY/$REPOSITORY:$IMAGE_TAG \
            --push .
          echo "image-app2=$ECR_REGISTRY/$REPOSITORY:$IMAGE_TAG" >> $GITHUB_ENV
  ########## CD ##########
  ##### Deploy for staging environment #####
  deploy-staging:
    name: Deploy to Amazon ECS for staging environment
    runs-on: ubuntu-latest
    environment:
      name: STG
    needs: [build] # buildジョブが成功した場合のみ作動
    if: github.ref == 'refs/heads/develop' # developブランチのみ作動
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

        # AWS credentialsの設定
      - name: Configure AWS credentials from IAM Role
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ap-northeast-1
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}

        # Amazon ECSタスク定義の新しいイメージIDを埋め込む
      - name: Fill in the new image ID in the Amazon ECS task definition for app
        id: task-def-app
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: app
          image: ${{ env.image-app}}

      - name: Fill in the new image ID in the Amazon ECS task definition for app2
        id: task-def-app2
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: app2
          image: ${{ env.image-app2 }}

        # Amazon ECSタスク定義をデプロイ
      - name: Deploy Amazon ECS task definition for app
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          task-definition: ${{ steps.task-def-app.outputs.task-definition }}
          service: ${{ secrets.CLUSTER_SERVICE_NAME }}
          cluster: ${{ secrets.CLUSTER_NAME }}
          wait-for-service-stability: true

      - name: Deploy Amazon ECS task definition for app2
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          task-definition: ${{ steps.task-def-app2.outputs.task-definition }}
          service: ${{ secrets.CLUSTER_SERVICE_NAME }}
          cluster: ${{ secrets.CLUSTER_NAME }}
          wait-for-service-stability: true

  ##### Deploy for production environment #####
  deploy-production:
    name: Deploy to Amazon ECS for production environment
    runs-on: ubuntu-latest
    environment:
      name: PRD
    needs: [ build ] # buildジョブが成功した場合のみ作動
    if: github.ref == 'refs/heads/main' # mainブランチのみ作動
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

        # AWS credentialsの設定
      - name: Configure AWS credentials from IAM Role
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ap-northeast-1
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}

        # Amazon ECSタスク定義の新しいイメージIDを埋め込む
      - name: Fill in the new image ID in the Amazon ECS task definition for app
        id: task-def-app
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: app
          image: ${{ env.image-app}}

      - name: Fill in the new image ID in the Amazon ECS task definition for app2
        id: task-def-app2
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: app2
          image: ${{ env.image-app2 }}

        # Amazon ECSタスク定義をデプロイ
      - name: Deploy Amazon ECS task definition for app
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          task-definition: ${{ steps.task-def-app.outputs.task-definition }}
          service: ${{ secrets.CLUSTER_SERVICE_NAME }}
          cluster: ${{ secrets.CLUSTER_NAME }}
          wait-for-service-stability: true

      - name: Deploy Amazon ECS task definition for app2
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          task-definition: ${{ steps.task-def-app2.outputs.task-definition }}
          service: ${{ secrets.CLUSTER_SERVICE_NAME }}
          cluster: ${{ secrets.CLUSTER_NAME }}
          wait-for-service-stability: true

```

### CI/CDワークフローの可視化

![Screenshot 2025-03-21 at 16.27.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672923/c9ea9f10-00b3-4a73-a2fd-6920873acb0a.png)


順を追って解説できればと思います。

### CI/CD トリガー

```yml
on:
  push:
    branches:
      - '**'
```

現在は全てのブランチのpushで作動。buildステップはdevelopまたはmainブランチへのpushで作動するようにしています

### job1 ~ lint ~

```yml
lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.24

      - name: Install golang ci-lint
        run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.5

      - name: Run golang ci-lint
        run: golangci-lint run --timeout=10m
```
ここはGo言語の代表的なlinterである、[golangci-lint](https://github.com/golangci/golangci-lint)を使用しています
Go言語のソースコードを解析して、コーディングスタイルや潜在的なエラーを検出してくれます

### job2 ~ test ~

```yml
test:
    name: Test
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set environment variables from secrets
        run: |
          echo "APP_TIMEZONE=${{ secrets.APP_TIMEZONE }}" >> $GITHUB_ENV
          echo "DB_HOST=${{ secrets.DB_HOST }}" >> $GITHUB_ENV
          echo "DB_PORT=${{ secrets.DB_PORT }}" >> $GITHUB_ENV
          echo "DB_USER=${{ secrets.DB_USER }}" >> $GITHUB_ENV
          echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> $GITHUB_ENV
          echo "DB_NAME=${{ secrets.DB_NAME }}" >> $GITHUB_ENV
          echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" >> $GITHUB_ENV
          echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> $GITHUB_ENV
          echo "REDMINE_APP_ACCESS_KEY=${{ secrets.REDMINE_APP_ACCESS_KEY }}" >> $GITHUB_ENV
          echo "COGNITO_USER_POOL_ID=${{ secrets.COGNITO_USER_POOL_ID }}" >> $GITHUB_ENV
          echo "AWS_S3_REGION=${{ secrets.AWS_S3_REGION }}" >> $GITHUB_ENV
          echo "AWS_S3_ENDPOINT=${{ secrets.AWS_S3_ENDPOINT }}" >> $GITHUB_ENV
          echo "AWS_S3_ACCESS_KEY_ID=${{ secrets.AWS_S3_ACCESS_KEY_ID }}" >> $GITHUB_ENV

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.24

      - name: Cache Go modules
        uses: actions/cache@v3
        with:
          path: ~/go/pkg/mod
          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
          restore-keys: ${{ runner.os }}-go-

      - name: Install dependencies
        run: go mod tidy

      - name: Run unit tests
        run: go test -v ./...
```

ここではソースコードに対して単体テストを行なっています
`.env`に記述してある情報はリポジトリー上では参照できないため、単体テストで使用する環境変数は`Github Secrets`から参照しています
[Github Secrets](https://docs.github.com/ja/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions)について
様々なymlファイルから参照できるだけでなくセキュリティー的にも良さそうです

### job3 ~ build ~

#### ~ build section part1 ~

```yml
########## Build ##########
  build:
    name: Build
    runs-on: ubuntu-latest
    needs: [lint, test] # lint, testジョブが成功した場合のみ作動
    if: github.ref == 'refs/heads/develop' # developブランチのみ作動
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

        # github.event.before（前のコミット）とgithub.sha（現在のコミット）の間で変更されたファイルのリストを取得し変更の有無を変数に格納
      - name: Detect changes in codebase
        id: detect-changes
        run: |
          app_changed="false"
          app2_changed="false"
          if git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep -q '^app2/'; then
            app2_changed="true"
          else if git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep -q '^/'; then
            app_changed="true"
          fi
          echo "app2_changed=$app2_changed" >> $GITHUB_ENV
          echo "app_changed=$app_changed" >> $GITHUB_ENV
```

こちらは`needs`に`lint`, `test`のジョブを設定し、この二つが成功した場合のみ`build`ジョブが動くように設定しています
今回ECRにあるリポジトリーは`app`と`app2`とします。
前のコミットと現在のコミットの差分を比較し、ECRのリポジトリのどちらかまたは両方のビルドを行います

#### ~ build section part2 ~

```yml
        # マルチプラットフォームのビルドを可能にするための設定
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

        # マルチプラットフォームのDockerイメージビルドをサポート、及びビルドプロセスの最適化
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

        # AWS credentialsの設定
      - name: Configure AWS credentials from IAM Role
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ap-northeast-1
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}

        # AWS CLIを使用してECRに対して認証トークンを取得
        # 認証トークンを使用してDockerクライアントがECRにログイン
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2
```

##### Docker Buildsについて
Marketplaceに良さげなコードがあったので今回は`Docker buildx`を使用してイメージをビルドしていきたいと思います

AIに聞いたらdocker との主な違いは下記のようです

特長:

- ​マルチプラットフォームビルド​: docker buildx buildコマンドを使用すると、複数のプラットフォーム（例: linux/amd64, linux/arm64）のためのイメージを同時にビルドできます
- ​効率的なビルドキャッシュ​: BuildKitエンジンを使用することで、効率的なキャッシュの利用とビルドスピードの向上が可能です
- ​複数のビルドノード​: 分散ビルドがサポートされており、クラスタリングや複数のビルドノードでビルドを行うことができます
- ​高度な機能​: Buildxは、カスタムコンテントトラスト、ビルドの依存関係管理など、より高度なビルド機能を提供します

利点:

- ​マルチプラットフォーム​: 複数のプラットフォーム向けにコンテナを同時にビルドでき、マルチアーキテクチャのサポートが容易です
- ​パフォーマンス​: BuildKitの効率的なキャッシュ管理と並列ビルドにより、ビルドパフォーマンスが向上します
- ​柔軟性​: 複雑なビルド要求に対応でき、多くのカスタマイゼーションが可能です

https://github.com/marketplace/actions/build-and-push-docker-images

##### IAM Roleについて

初めはAWSから張り出されたcredentialを参照していたのですが、ベテランエンジニアによるとAWSでIAMロールを作成し使用するのが一般的だそうです
1. ID プロパイダを作成
2. IAM ロールを作成
3. GitHubActionsでOIDCを使用しAWS認証を行う

```yml
- name: Configure AWS credentials from IAM Role
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ap-northeast-1
-         aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
-         aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+         role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
```

IAMロール自体は下記のような構成で作成しております。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::<AWS account ID>:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
                    "token.actions.githubusercontent.com:sub": "repo:<GitHubユーザー名>/<GitHubリポジトリ名>:*"
                }
            }
        }
    ]
}
```

こちらの[記事](https://zenn.dev/kou_pg_0131/articles/gh-actions-oidc-aws)を参考にしました

#### ~ build section part3 ~

```yml
        # Dockerイメージをビルド
      - name: Build, tag, and push docker image to Amazon ECR for app
        if: env.app_changed == true
        id: build-app-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          REPOSITORY: exapmle_repository
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker buildx build --platform linux/amd64,linux/arm64 \
            -t $ECR_REGISTRY/$REPOSITORY:$IMAGE_TAG \
            --push.
          echo "image-app=$ECR_REGISTRY/$REPOSITORY:$IMAGE_TAG" >> $GITHUB_ENV

      - name: Build, tag, and push docker image to Amazon ECR for app2
        if: env.app2_changed == true
        id: build-app2-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          REPOSITORY: exapmle_repository2
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker buildx build --platform linux/amd64,linux/arm64 \
            -t $ECR_REGISTRY/$REPOSITORY:$IMAGE_TAG \
            --push .
          echo "image-app2=$ECR_REGISTRY/$REPOSITORY:$IMAGE_TAG" >> $GITHUB_ENV
```

build section part1にて`app_changed`と`app2_changed`に対し値を入れていると思います
こちらの変数を利用して差分があるファイルのみイメージをビルドしています

```yml
echo "image-app=$ECR_REGISTRY/$REPOSITORY:$IMAGE_TAG" >> $GITHUB_ENV
```

このコマンドはdeployジョブで各ビルド結果のイメージIDをを使用する為変数に格納しています
それぞれappのデプロイには`image_app`を、app2のデプロイには`image-app2`を使用します
このように変数に格納することでそれぞれのジョブごとに値の受け渡しをすることが可能です

### job4 ~ deploy ~

#### ~ deploy section part1 ~

```yml
##### Deploy for staging environment #####
  deploy-staging:
    name: Deploy to Amazon ECS for staging environment
    runs-on: ubuntu-latest
    environment:
      name: STG
    needs: [build] # buildジョブが成功した場合のみ作動
    if: github.ref == 'refs/heads/develop' # developブランチのみ作動
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

        # AWS credentialsの設定
      - name: Configure AWS credentials from IAM Role
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ap-northeast-1
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
```

```yml
name: STG
```

これはGithubのSettingsにおいてEnvironmentsという項目があり、そこにステージング環境と本番環境用でそれぞれの変数を定義しています。
ECRのリポジトリはそれぞれ異なるクラスター名やサービス名を持っているためGithubのEnvironmentsを使用して管理しています。

#### ~ deploy section part2 ~

```yml
        # Amazon ECSタスク定義の新しいイメージIDを埋め込む
      - name: Fill in the new image ID in the Amazon ECS task definition for app
        id: task-def-app
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: app
          image: ${{ env.image-app}}

      - name: Fill in the new image ID in the Amazon ECS task definition for app2
        id: task-def-app2
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: app2
          image: ${{ env.image-app2 }}
```

ここで`build`セクションで定義されたそれぞれのイメージIDが格納してある変数を参照しています
このような手法を取ることでジョブ間の値を受け渡すことができるだけでなく、ビルドとデプロイのステップをまとめなくてもいいので読みやすいコードになったかなと思います

#### ~ deploy section part3 ~

```yml
# Amazon ECSタスク定義をデプロイ
      - name: Deploy Amazon ECS task definition for app
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          task-definition: ${{ steps.task-def-app.outputs.task-definition }}
          service: ${{ secrets.CLUSTER_SERVICE_NAME }}
          cluster: ${{ secrets.CLUSTER_NAME }}
          wait-for-service-stability: true

      - name: Deploy Amazon ECS task definition for app2
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          task-definition: ${{ steps.task-def-app2.outputs.task-definition }}
          service: ${{ secrets.CLUSTER_SERVICE_NAME }}
          cluster: ${{ secrets.CLUSTER_NAME }}
          wait-for-service-stability: true
```

最後はEnvironmentsに定義してあるクラスターとサービス名を参照し、デプロイ完了です




## [引用]
CI/CDについて
- https://www.redhat.com/ja/topics/devops/what-is-ci-cd
- https://about.gitlab.com/ja-jp/topics/ci-cd/
- https://blog.jetbrains.com/teamcity/2023/07/best-ci-tools/
- https://www.qodo.ai/blog/best-ci-cd-tools-for-devops/

GitHub Actionsについて
- https://docs.github.com/ja/actions (オススメ)
マーケットプレイス
- https://github.com/marketplace
- https://docs.github.com/ja/actions/use-cases-and-examples/building-and-testing/building-and-testing-go
- https://github.com/actions/starter-workflows/blob/main/ci/go.yml
- https://zenn.dev/farstep/books/learn-github-actions/viewer/intro (オススメ)
- https://dev.classmethod.jp/articles/github-wf-docer-ecr/

環境変数とシークレット
- https://zenn.dev/farstep/books/learn-github-actions/viewer/environment-variables-and-secrets

IAM ロール
- [GitHub Actions で OIDC を使用して AWS 認証を行う](https://zenn.dev/kou_pg_0131/articles/gh-actions-oidc-aws)


GitHub Actionsのセキュリティについて
- https://engineering.mercari.com/blog/entry/20230609-github-actions-guideline/
- https://docs.github.com/ja/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions

CI
- Build and push Docker image
  - https://github.com/marketplace/actions/build-and-push-docker-images


- Configure AWS Credentials
  - https://github.com/marketplace/actions/configure-aws-credentials-action-for-github-actions

- Amazon ECR "Login" Action for GitHub Actions
  - https://github.com/marketplace/actions/amazon-ecr-login-action-for-github-actions

CD
- Amazon ECS "Deploy Task Definition" Action for Github Actions
  - https://github.com/marketplace/actions/amazon-ecs-deploy-task-definition-action-for-github-actions