koudenpaのブログ

趣味のブログです。株式会社はてなでWebアプリケーションエンジニアをやっています。職業柄IT関連の記事が多いと思います。

ECS Fargate + ecspresso + GitHub Actions 運用構成例

先日の記事でECS Fargate*1をアゲたので、どういう使い方の実感でアゲたのか軽くメモしておく記事。

AWS Containersのカレンダー | Advent Calendar 2023 - Qiitaにも登録しておいた。

手軽に箇条書きです。

ホスティング対象・条件など

  • フロントエンドのSSR
  • バックエンドのAPI
  • ECSタスクはローリングデプロイ

IaC

Terraform(Terraform Cloud)でやっている。ECSに関連する管理対象は概ね以下。

ECSのサービスとタスクはIaCの対象外にして、ecspressoでデリバリ構成として管理する。

デリバリ

GitHub Actionsのワークフローでecspressoを動かす。

同じワークフローのジョブでデプロイするイメージもビルド、ビルドした結果のイメージタグをジョブ間で引き渡してタスク定義に埋め込んでいる

バックエンドのデプロイ前にDBマイグレーションしたい。これもECSタスクで行う。デプロイするものと同じバックエンドのイメージのCMDを上書きしてRunした。

ワークフローファイルは概ね以下のような感じ。

name: Deploy Production
on:
  push:
    branches: [ release ]

env:
  AWS_REGION: ap-northeast-1
  AWS_ROLE: github-actions-role
  BACKEND_ECR_REPOSITORY: backend
  FRONTEND_ECR_REPOSITORY: frontend

permissions:
  id-token: write
  contents: read
  
concurrency:
  group: "cd-production"
  cancel-in-progress: false

jobs:  
  build-backend:
    runs-on: ubuntu-latest
    outputs:
      image-backend: ${{ steps.image-backend.outputs.image }}
    steps:      
      - イメージをビルドしてECRにPushするステップが並ぶ
          
  build-frontend:
    runs-on: ubuntu-latest
    outputs:
      image-frontend: ${{ steps.image-frontend.outputs.image }}
    steps:      
      - イメージをビルドしてECRにPushするステップが並ぶ
          
  deploy:
    runs-on: ubuntu-latest
    needs: 
      - build-backend
      - build-frontend
    steps:      
      - name: Checkout
        uses: actions/checkout@v4
          
      - name: Configure AWS credentials
        id: aws-credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ${{ AWS_REGION }}
          role-to-assume: ${{ AWS_ROLE }}
          role-session-name: ecspresso
      - uses: kayac/ecspresso@v2
        with:
          version: latest
      - run: >-
          ecspresso run --config ecspresso/backend-production.yml 
          --overrides '{"containerOverrides":[{"name":"laravel", "command":["php", "artisan", "migrate", "--force"]}]}'
        env:
          BACKEND_IMAGE: ${{needs.build-backend.outputs.image-backend}}
      - run: >-
          ecspresso deploy --config ecspresso/backend-production.yml
        env:
          BACKEND_IMAGE: ${{needs.build-backend.outputs.image-backend}}
      - run: >-
          ecspresso deploy --config ecspresso/frontend-production.yml
        env:
          FRONTEND_IMAGE: ${{needs.build-frontend.outputs.image-frontend}}

タスク定義の変更次第でdeploy時にサービスの強制更新を求められて失敗する場面があるが、これはその際だけワークフローファイルを更新して再実行している。

まとめ?

やや登場人物は多いが、どこで何を管理するかの切り分けが腑に落ちたら平易に実際的な管理を行えると思う。

ECSのサービスやタスク定義をIaC管理下に置いてしまうのはデリバリとの競合で困ることになる。これだけ避ければよいという感触。今回の例のようにそもそも管理しないか、変更を無視するか、など色々手法はあるはず。

なお、平易で実際的なデリバリを構成できているのはecspressoの便利さによるところが大きい。公私でともに非常にお世話になっている。

github.com

ビール1杯くらいの投げ銭で感謝の意を示しておいた。

*1:Amazon Elastic Container Service(Amazon ECS)のAWS Fargateが正しいか?