40
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【解説】ecspressoはなぜ必要?Terraformと併用するECSデプロイ戦略

Last updated at Posted at 2025-09-30

はじめに

私は普段バックエンドエンジニアとして活動しています。Terraformとecspressoを活用しているプロジェクトが多いのですが、両者の役割分担は、一見すると分かりにくいです。この記事では、Terraformとecspressoを使ったサンプルプロジェクトを作りながら、両者のライフサイクルの違いについて説明いたします。

この記事を読むと分かること

  • Terraformとecspressoの役割の違い
  • なぜECSの変更管理にecspressoが向いているのか
  • ecspressoおよびGitHub Actionsのサンプルコード

想定読者

  • バックエンドエンジニアで、インフラもある程度触る人
  • Terraformとecspressoの違いを知りたい人

ecspressoが解決したい課題

TerraformのみでECSの変更管理をする難しさ

「ecspressoはECSの管理に特化したツールです。」
私はこれを聞いたとき「TerraformでもECSの管理できるじゃん、なぜecspressoが必要?」と疑問が湧きました。はじめに、AWSリソースのライフサイクルを整理し、ecspressoの守備範囲を確認します。

まずTerraformはAWS全体の構成管理を行います。ほとんどのAWSリソースは一度設定すると変更頻度は低いという特徴があります。一方で、ECS上で起動させるイメージはアプリエンジニアが開発して頻繁にデプロイします。CI/CDパイプラインが整備されているエリートなチームであれば、1日に1回の高頻度でアプリをデプロイすることもあるでしょう。

image.png

このときECSの更新をTerraformで行うと次のような問題が生じます。

  • ECSのタスク定義のみ変更したいのに、AWS全体の差分チェックが発生する。場合によってはECS以外のリソースも同時に変更される
  • CI/CDなど他の手段でECSの設定を書き換えると、Terraformに差分アリと判断され、terraform apply 時に、ECSの状態が以前の状態に切り戻される可能性がある
  • 障害発生時にタスク定義、イメージの切り戻しがやりづらい

特に、商用サービスでは事故防止のため、高頻度で変更したいECS周りの管理と、更新頻度が低い他のAWSリソースの管理を分けておきたいかと思います。

ECSの変更はTerraformで管理しない

そこでインフラの中でライフサイクルが短いECS周りのリソースはTerraformで管理せず、別の管理ツールで管理します。この役割を担うのがecspressoです。

  • 表: AWSリソース管理のすみ分け
項目 Terraform ecspresso 変更頻度
ECSタスク定義
ECSサービス
ECSクラスター
その他AWSリソース

アプリチームとインフラチームの境界を明確にする

開発プロセスにおいて、ECS以外のインフラ管理はインフラ管理用のGitリポジトリで管理し、アプリケーションのデプロイ、ECSのリソース管理はアプリ管理用のGitリポジトリで管理します。

これによって、アプリチームとインフラチームの責任分界点が明確になり、アプリ側はインフラチームに変更依頼を出さずに自分たちの管理でアプリのデプロイを管理できます。また、アプリデプロイ時のインフラチームとの調整コスト(コミュニケーションコスト)の削減も狙えます。

  • リポジトリ分割
    • インフラリポジトリ: AWS全般のリソース管理 (terraform)
    • アプリリポジトリ: アプリケーションコード + ecspressoの管理

ecspressoimage.png

Terraform管理からecspresso管理への移行

Terraform管理下のコードを削除

下記のコードは、ECS管理用のtfファイルの例です。もともとECS全体をTerraformで管理していましたが、services配下および container_definitions はコメントアウトされています。terraform.tfstateの管理外になったため、コンテナを再デプロイしても tfstateの diff として現れません。

modules/ecs/main.tf
module "ecs" {
  source = "terraform-aws-modules/ecs/aws"

  # NOTE: Terraformでは、ECSクラスタのみ管理する
  cluster_name = "${var.product_name}-${var.env}"

  cluster_configuration = {
  }

  default_capacity_provider_strategy = {
    FARGATE = {
      weight = 1
    }
  }

  # NOTE: TerraformからECSサービスの定義を削除し、ecspressoでECSサービスを管理する
  services = {
    # fastapi-service = {
    #   cpu           = 256
    #   memory        = 512
    #   desired_count = 1

    # NOTE: Terraformからタスク定義も削除し、ecspressoに移動
    #   container_definitions = {
    #     fastapi = {
    #       image     = data.aws_ecr_image.this.image_uri
    #       essential = true
    # ... (以下略)
    #  }
  }
}

※ 参考: 元々使用していたTerraform module

コメントアウトした箇所をecspressoの定義ファイルに移動

先ほどのmodules/ecs/main.tfでコメントされた部分は、ecspressoの ecs-service-def.jsonnet, ecs-task-def.jsonnet で管理するようになります。それぞれECS Service, ECS Taskdefを制御します。ecspresso deployコマンドを実行すればAWSリソースのうち、ECSサービス, タスクのみ更新されるようになります

  • ECSのサービス定義ファイル
ecs-service-def.jsonnet
{
  "deploymentConfiguration": {
    "deploymentCircuitBreaker": {
      "enable": true,
      "rollback": false
    },
    "maximumPercent": 200,
    "minimumHealthyPercent": 50
  },
  "deploymentController": {
    "type": "ECS"
  },
  "desiredCount": 1,
  "enableECSManagedTags": true,
  "enableExecuteCommand": true,
  "healthCheckGracePeriodSeconds": 30,
  "launchType": "FARGATE",
  "networkConfiguration": {
    "awsvpcConfiguration": {
      "assignPublicIp": "ENABLED",
      "securityGroups": [
        "{{ tfstate `module.ecs.aws_security_group.ecs_sg.id` }}"
      ],
      "subnets": [
        "{{ tfstate `module.vpc.module.vpc.aws_subnet.private[0].id` }}",
        "{{ tfstate `module.vpc.module.vpc.aws_subnet.private[1].id` }}"
      ]
    }
  },
  "pendingCount": 0,
  "platformFamily": "Linux",
  "platformVersion": "LATEST",
  "propagateTags": "NONE",
  "runningCount": 0,
  "schedulingStrategy": "REPLICA",
}

  • ECSのタスク定義ファイル
ecs-task-def.jsonnet
{
  "containerDefinitions": [
    {
      "cpu": 0,
      "essential": true,
      "image": "{{ tfstate `module.ecs.data.aws_ecr_repository.this.repository_url`}}:latest",
      "interactive": false,
      "linuxParameters": {
        "initProcessEnabled": true
      },
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "{{tfstate `module.ecs.module.ecs.module.cluster.aws_cloudwatch_log_group.this[0].name`}}",
          "awslogs-region": "{{ tfstate `module.ecs.module.ecs.module.cluster.aws_cloudwatch_log_group.this[0].region` }}",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "name": "fastapi",
      "portMappings": [
        {
          "containerPort": 8000,
          "hostPort": 8000,
          "protocol": "tcp"
        }
      ],
      "privileged": false,
      "pseudoTerminal": false,
      "readonlyRootFilesystem": false,
      "startTimeout": 30,
      "stopTimeout": 120,
      "healthCheck": {
        "command": [
          "CMD-SHELL",
          "curl -f http://localhost:8000/ || exit 1"
        ],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 10
      }
    }
  ],
  "cpu": "256",
  "executionRoleArn": "{{ tfstate `module.ecs.aws_iam_role.ecs_task_execution_role.arn` }}",
  "family": "{{ tfstate `module.ecs.module.ecs.module.cluster.aws_ecs_cluster.this[0].tags.ServiceName` }}",
  "ipcMode": "",
  "memory": "512",
  "networkMode": "awsvpc",
  "pidMode": "",
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "runtimePlatform": {
    "cpuArchitecture": "X86_64",
    "operatingSystemFamily": "LINUX"
  },
  "taskRoleArn": "{{tfstate `module.ecs.aws_iam_role.ecs_task_role.arn`}}"
}

詳しい使い方を知りたい方は、ecspresso作者の執筆している下記の書籍がおすすめです。(¥500)

CI/CDにecspressoを組み込む

アプリリポジトリにおいて、mainブランチにコードがマージされたときに自動でGitHub Actionsが実行されるように設定します。GitHub Actionsのワークフローは下記のような流れで構成します。

  1. GHAでDockerイメージをビルド
    イメージタグには latest タグと、コミットハッシュを両方付与する
  2. DockerイメージをECRにプッシュ
  3. ecspressoでデプロイ

image.png

.github/workflows/ecs-deploy.yml
name: ECS Deploy
on:
  push:
    branches:
      - main
  workflow_dispatch: # GitHub UIからの手動実行用

jobs:
  build_and_push:
    name: Docker Build and Push Docker Image to ECR
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_AllowGitHubActions }}
          aws-region: ap-northeast-1

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build, tag, and push image to Amazon ECR
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: n700a/fastapi-mini
          IMAGE_TAG: latest # ${{ GitHub.sha }}
        run: |
          docker build -f backend/Dockerfile -t $ECR_REPOSITORY:$IMAGE_TAG backend
          docker tag $ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

  deploy:
      name: Deploy to ECS
      needs: build_and_push
      runs-on: ubuntu-latest
      permissions:
        id-token: write
        contents: read

      steps:
        - name: Checkout code
          uses: actions/checkout@v4

        - name: Configure AWS credentials
          uses: aws-actions/configure-aws-credentials@v4
          with:
            role-to-assume: ${{ secrets.AWS_ROLE_AllowGitHubActions }}
            aws-region: ap-northeast-1

     # ここで ecspresso deploy を実行
        - name: Deploy to ECS service
          uses: kayac/ecspresso@v2
          with:
            version: v2.6.0
            args: deploy --config ./infra/dev/ecspresso/ecspresso.yml

このワークフローを設定しておくと、アプリチームはECSのデプロイ作業から解放され、アプリソースコードの作成に集中することができます。

まとめ

  • アプリ開発に関連するECSの部分は、他のAWSリソースより変更頻度が高い
  • アプリのECSデプロイに特化したツールが ecspresso☕である
  • ecspressoではRDBマイグレーションツールのように deploy / rollback が簡単にできる

本記事では、AWSのリソースのうちアプリ領域とインフラ領域において、デプロイの頻度の違いがあることを述べ、全てをTerraformで管理することの課題を示しました。ecspressoとTerraformを併用することで、AWSリソースのうちアプリ管理とインフラ管理の領域を明確に分けられそうです。

この記事ではecspressoの具体的な環境構築方法については記載していません。ご興味のある方はぜひ一度手を動かしてみて下さい。
この記事が、ecspressoの意義や概念について知るきっかけになると幸いです。

参考記事

40
30
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?