Yusuke Ebihara's website
Dotfiles Blog RSS

ECS のタスク定義を terraform で管理しつつ、Github Actions でコンテナを更新する

2024/10/03
terraform ecs github actions

目次

ECSのタスク定義はterraformから定義できる。

# ECS Service
resource "aws_ecs_service" "app" {
  name            = "${local.prefix}-app"
  cluster         = aws_ecs_cluster.this.id
  task_definition = aws_ecs_task_definition.app.arn
  desired_count   = 1
  launch_type     = "FARGATE"

  ...
}

# ECS Task Definition
resource "aws_ecs_task_definition" "app" {
  family                   = "${local.prefix}-app"
  cpu                      = "1024"
  memory                   = "2048"
  ...

  container_definitions = jsonencode([
    ...
  ])
}

一方で、CI/CDを導入すると、Github Actionsなどでタスク定義を更新することがある。

この時、どのようにタスク定義を管理するかが課題となる。

よくあるパターン

パターン1: Github側でタスク定義を指定

例: ecspresso利用を考慮したTerraformのECS(Fargate)構築 - Zenn

パターン2: latestデプロイ

今回のパターン

できるようにしたいこと

Terraform側: latest指定で最新のコンテナを使ったタスク定義

Terraformで構築したECSをCodePipeline等でローリング更新するとタスク定義のリビジョンがずれる問題をdataを使って回避する | DevelopersIO の方式を活用。

dataを利用すると、最新のタスク定義を参照することができる。

terraform定義を以下のように変更する。

  # ECS Service
  resource "aws_ecs_service" "app" {
    name            = "${local.prefix}-app"
    cluster         = aws_ecs_cluster.this.id
-   task_definition = aws_ecs_task_definition.app.arn
+   task_definition = data.aws_ecs_task_definition.app.arn
    desired_count   = 1
    launch_type     = "FARGATE"

    ...
  }

  # ECS Task Definition
  resource "aws_ecs_task_definition" "app" {
    ...
  }

+ data "aws_ecs_task_definition" "app" {
+   task_definition = aws_ecs_task_definition.app.family
+ }

Github側: 最新のタスク定義をawsから取得し、コンテナタグを更新してデプロイ

最新のタスク定義は、aws cliで取得できる。

aws ecs describe-task-definition \
   --task-definition my-task-definition-family \
   --query taskDefinition > task-definition.json

落としてきたタスク定義のイメージタグだけを更新して、再度デプロイする。

ビルドしたイメージは、 latest タグにもpushしておく

これらをGithub Actionsのworkflowに記述すると以下のようになる。

- name: Build and push docker container
  run: |
    docker build -t app .
    docker tag app:latest ${{secrets.AWS_ECR_REPOSITORY_URI}}:${{github.sha}}
    docker tag app:latest ${{secrets.AWS_ECR_REPOSITORY_URI}}:latest
    docker push ${{secrets.AWS_ECR_REPOSITORY_URI}}:${{github.sha}}
    docker push ${{secrets.AWS_ECR_REPOSITORY_URI}}:latest
# deploy to ECS
- name: Get latest ECS task definition
  run: aws ecs describe-task-definition --task-definition ${{ secrets.ECS_TASK_DEFINITION }} --query taskDefinition > task_definition.json
- name: Render task definition
  id: render_task_definition
  uses: aws-actions/amazon-ecs-render-task-definition@v1
  with:
    task-definition: task_definition.json
    container-name: app
    image: ${{secrets.AWS_ECR_REPOSITORY_URI}}:${{github.sha}}
- name: Deploy to ECS (Update task definition)
  uses: aws-actions/amazon-ecs-deploy-task-definition@v1
  with:
    task-definition: ${{steps.render_task_definition.outputs.task-definition}}
    service: ${{secrets.ECS_SERVICE_NAME}}
    cluster: ${{secrets.ECS_CLUSTER_NAME}}
    wait-for-service-stability: true

困る点

terraform定義から料金を計算してくれる infracost が、正しく料金を計算してくれない。

References

コメント

Github Issue と連動しています。