GitHubActionでrails×dockerアプリをECSへデプロイする

業務でGithubactionを使用した自動デプロイを実施したので記録

# GitHubActionsとは
CI/CDを実装する際に利用できるワークフローの自動化ツール。
Githubへのpushやプルリクのクローズなど様々な条件をトリガーに自動デプロイやテスト、リンターの実行などに使うことができる

# 前提
- 業務でRuby on RailsのアプリケーションをDocker環境にて開発
- インフラはAWS ECR,ECSを使用
- デプロイはecspressoを使用


# 実行するデプロイ処理イメージ
1. ECRへのpush、ECSのサービス更新ができる権限をcredencialをAssumeroleで取得
2. ECRへdockerイメージのビルドとプッシュ
3. DBマイグレーションの実行
4. ECSサービス更新
5. Slack 等へ完了・エラー通知

# 実際の実装
```name: deploy_to_prd
on:
  pull_request:
    types:
      - closed
    branches:
      - main

env:
  AWS_REGION: 対象のリージョンを記載
  AWS_ROLE_ARN: arn:aws:iam::{{usernameを記載}}:role/{{Githubacitions用に作成したrole名}}
  ECR_REPOSITORY: {{ECRのリポジトリ名}}
  IMAGE_TAG: ${{ github.sha }}

permissions:
  id-token: write
  contents: read

jobs:
  deploy_to_prd:
    if: github.event.pull_request.merged == true #pull requestがマージされた場合のみ実行
    runs-on: ubuntu-latest
    steps:
      - name: Git clone the repository #pull requestがマージされた場合のみ実行
        uses: actions/checkout@v4
        with:
          ref: 'main'
      - name: configure aws credentials #AWSの操作権限をアシュメロールにて付与
        uses: aws-actions/configure-aws-credentials@v3
        with:
          role-to-assume: ${{ env.AWS_ROLE_ARN }}
          aws-region: ${{ env.AWS_REGION }}
      - name: login to ecr
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2
      - name: build and push docker image to ecr
        run: |
          docker build -t ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }} .
          docker push ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}
      - name: install ecspresso
        uses: kayac/ecspresso@v2
        with:
          version: v2.3.1
      - name: DB Migrate and Deploy to Amazon ECS
        run: |
          ecspresso run --config ecspresso/app/ecspresso.yml --overrides='{"containerOverrides":[{"name":"app", "command":["rails", "db:migrate"]}]}'
          ecspresso deploy --config ecspresso/ecspresso.yml
```
# 詳細解説
トリガー

```name: deploy_to_prd
on:
  pull_request:
    types:
      - closed
    branches:
      - main
```
プルリクエストがマージした瞬間としたかったですが、選べるイベントでマージはないためプルリクエストがクローズされたらで設定します。（プルリクエストがクローズかつマージした場合のみの設定を下に記載する）

```
jobs:
  deploy_to_prd:
    if: github.event.pull_request.merged == true #pull requestがマージされた場合のみ実行
    runs-on: ubuntu-latest
```
ジョブ名称は deploy_to_prd:としています。
もしプルリクエストがマージされたときに以下を実行することを条件に追加
runs-onは実行環境を指定しており、ubuntuのlatestとしました。


```steps:
      - name: Git clone the repository
        uses: actions/checkout@v4
        with:
          ref: 'main'
```
GithubActions上の環境にmainブランチをcloneする

```
- name: configure aws credentials #AWSの操作権限をアシュメロールにて付与
        uses: aws-actions/configure-aws-credentials@v3
        with:
          role-to-assume: ${{ env.AWS_ROLE_ARN }}
          aws-region: ${{ env.AWS_REGION }}
```
AssumeRoleを使ってAWS上のECRへプッシュ,ECSのサービス作成・タスク起動する権限を取得します。
AssumeRoleとはRoleを一時的に借りるようなイメージです。（曖昧）
詳細については以下の記事がとってもわかりやすかったので参照ください。

参考記事：https://dev.classmethod.jp/articles/iam-role-passrole-assumerole/
```
      - name: login to ecr
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2
```
ecrへログインを行います。
```
     - name: build and push docker image to ecr
        run: |
          docker build -t ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }} .
          docker push ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}
```
dockerのimageをbuildしてECRへpushを行なっています。
`${{steps.login-ecr.outputs.registry}}`とすることで`id: login-ecr`の行で取得した情報を使用するようにしています。

```
      - name: install ecspresso
        uses: kayac/ecspresso@v2
        with:
          version: v2.3.1
```
ecspressoをGithubactions環境へインストール

```
      - name: DB Migrate and Deploy to Amazon ECS
        run: |
          ecspresso run --config ecspresso/ecspresso.yml --overrides='{"containerOverrides":[{"name":"app", "command":["rails", "db:migrate"]}]}'
          ecspresso deploy --config ecspresso/ecspresso.yml
```
1行目のecspresso runでecspressoを使用してECSをrunさせてマイグレーションを実施します。
2行目のecspresso deployでデプロイを実施します。

# 今後やりたいこと
これで目的のデプロイは実施されるようになりましたが、実行から完了まで10分以上かかっているので、Docker buildの際にキャッシュを利用するなど時間の短縮に向けた改善を行いたいなーと思っています。