新機能のAmazon ECS Express ModeをTerraformを使って試してみた!

このブログはクリエーションライン・アドベントカレンダー2025 の9日目の記事です。

はじめに

先日AWSからECSの新機能であるAmazon ECS Express Modeが発表されました。
従来ECSを構築するにはコンテナ設定以外にALBやVPCの設定等の作業を行う必要がありましたが、
Amazon ECS Express Modeを使用することでコンテナ設定以外の設定をAWSがよしなにやってくれるサービスのようです。
似たようなサービスとしてはAWS App Runnerがありますが、
今回のAmazon ECS Express ModeはWebSocketに対応しているなど、
ECSの大部分を自動で構築することになるのでAWS App Runnerよりも機能が豊富そうです。

Amazon ECS Express Mode は、AWS 全体で一般的に使用されるリソースを作成するための新たな統合により、Amazon ECS サービスリソースへのシンプルなインターフェイスを提供します。ECS Express Mode は、ECS クラスター、タスク定義、Application Load Balancer、自動スケーリングポリシー、Amazon Route 53 ドメインを 1 つのエントリポイントから自動的にプロビジョニングして設定します。

https://aws.amazon.com/jp/blogs/news/build-production-ready-applications-without-infrastructure-complexity-using-amazon-ecs-express-mode

この記事では最近対応したTerraformを使ってECS Express Modeを試してみたいと思います。

セットアップ

Terraformのファイルを作成してきます。
ファイル構成等についてはこちらの記事を参考に。

Terraformでも最近Amazon ECS Express Modeがサポートされ、構築できるようになりました。
v6.23.0のチェンジログからaws_ecs_express_gateway_serviceとしてECS Express Modeのリソースが確認できるため、
対応済みのバージョン以降をご使用ください。
https://github.com/hashicorp/terraform-provider-aws/blob/v6.23.0/CHANGELOG.md

マネジメントコンソールから作成する場合は公式ドキュメントをご参照ください。
https://aws.amazon.com/jp/blogs/news/build-production-ready-applications-without-infrastructure-complexity-using-amazon-ecs-express-mode/

Terraformリソース

aws_ecs_express_gateway_serviceのドキュメントは以下のリンクから確認できます。

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_express_gateway_service

Terraformのサンプルコードは下記になります。(一部生成AIで作成したコードを含む)
AWSの認証設定をしていただき、terraform applyすればECRからECSまで作成されるはずです。
サンプルコードではPythonを使用しているため、Dockerfile等のファイルはご自身の環境に合わせて作成をお願いします。

# ECRリポジトリ
resource "aws_ecr_repository" "demo-express-mode" {
  name = "${var.environment}-${var.project_name}-demo"
}

# Dockerイメージのビルドとプッシュ
resource "terraform_data" "docker_build_push" {
  triggers_replace = [
    filemd5("${path.module}/Dockerfile"),
    filemd5("${path.module}/app.py"),
    filemd5("${path.module}/requirements.txt")
  ]

  provisioner "local-exec" {
    command = <<-EOT
      aws ecr get-login-password --region ${var.aws_region} | docker login --username AWS --password-stdin ${aws_ecr_repository.demo-express-mode.repository_url}
      docker build -t ${aws_ecr_repository.demo-express-mode.repository_url}:latest ${path.module}
      docker push ${aws_ecr_repository.demo-express-mode.repository_url}:latest
    EOT
  }

  depends_on = [aws_ecr_repository.demo-express-mode]
}

# =============================================================================
# ECS Express Mode用IAMロール
# =============================================================================

# ECSタスク実行ロールの信頼ポリシー
data "aws_iam_policy_document" "ecs_task_execution_assume_role" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["ecs-tasks.amazonaws.com"]
    }
  }
}

# ECSタスク実行ロール
resource "aws_iam_role" "ecs_task_execution" {
  name               = "${var.environment}-${var.project_name}-ecs-task-execution-role"
  assume_role_policy = data.aws_iam_policy_document.ecs_task_execution_assume_role.json

}

# ECSタスク実行ロールにAWS管理ポリシーをアタッチ
resource "aws_iam_role_policy_attachment" "ecs_task_execution" {
  role       = aws_iam_role.ecs_task_execution.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

# ECS Express Modeインフラストラクチャロールの信頼ポリシー
data "aws_iam_policy_document" "ecs_infrastructure_assume_role" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["ecs.amazonaws.com"]
    }
  }
}

# ECS Express Modeインフラストラクチャロール
resource "aws_iam_role" "ecs_infrastructure" {
  name               = "${var.environment}-${var.project_name}-ecs-infrastructure-role"
  assume_role_policy = data.aws_iam_policy_document.ecs_infrastructure_assume_role.json

}

# ECS Express Modeインフラストラクチャロールにマネージドポリシーをアタッチ
resource "aws_iam_role_policy_attachment" "ecs_infrastructure" {
  role       = aws_iam_role.ecs_infrastructure.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSInfrastructureRoleforExpressGatewayServices"
}

# =============================================================================
# ECS Express Gateway Service
# =============================================================================

# ECS Express Modeサービス
resource "aws_ecs_express_gateway_service" "demo" {
  service_name  = "${var.environment}-${var.project_name}-express-service"
  primary_container {
    image = "${aws_ecr_repository.demo-express-mode.repository_url}:latest"
  }

  execution_role_arn     = aws_iam_role.ecs_task_execution.arn
  infrastructure_role_arn = aws_iam_role.ecs_infrastructure.arn

  depends_on = [
    terraform_data.docker_build_push,
    aws_iam_role_policy_attachment.ecs_task_execution,
    aws_iam_role_policy_attachment.ecs_infrastructure
  ]

}

terraform apply実行完了後でも、リソースの作成が完了されるまで時間が掛るので少し待ちます。
構築状況はEマネジメントコンソールのECSページから確認ができます。

すべてのリソースが完了する自動設定されたドメイン(アプリケーション URL)からアクセスをするとデプロイしたサイトが確認できるようになります。

最後に

この記事ではTerraformを使ってAmazon ECS Express Modeを試してみました。
最低限の内容でもTerraformのコード量はECSと比べてかなり少なくなり構築時間も短くなることが実感できました。

このサービスを使うときに悩むポイントとしては冒頭で出したAWS App Runnerとどちらを採用するかがあるかと思います。
料金面だとAWS App Runnerは使用していない間は自動的にアイドル状態になり、料金が最低限しか発生しないのでAmazon ECS Express Modeよりも安くなる可能性があります。
MVPなどの開発段階はAWS App Runnerを採用し、検証/本番環境などでより細かい制御が必要な場合はAmazon ECS Express Modeで手軽に試し、条件によってはECSを構築するのも一案かもしれません。

参考リンク

新規CTA