【AWSハンズオン】第4回 ECSクラスターとIAM設定

【AWSハンズオン】第4回 ECSクラスターとIAM設定

前回構築したApplication Load Balancerの上に、コンテナ実行環境であるECSクラスターとIAMロールを設定します。ECS Task Role、Execution Role、ECRリポジトリを作成し、コンテナアプリケーションの実行基盤を構築しましょう。

AWS #AWS#ハンズオン#インフラ

【AWSハンズオン】第4回 ECSクラスターとIAM設定

サムネイル

前回構築したApplication Load Balancerの上に、コンテナ実行環境であるECSクラスターとIAMロールを設定します。ECS Task Role、Execution Role、ECRリポジトリを作成し、コンテナアプリケーションの実行基盤を構築しましょう。

更新日: 8/11/2025

今回作業対象のブランチ

前提条件

Terraform実行環境の起動

前回と同様に、Dockerコンテナ内で作業を進めます。

# コンテナを起動してbashに入る
docker-compose run --rm terraform

これ以降のコマンドは、すべてこのコンテナ内で実行します。

基礎知識

ECS (Elastic Container Service)とは

ECSは、AWSが提供するフルマネージドなコンテナオーケストレーションサービスです。Dockerコンテナの実行、スケーリング、管理を自動化します。

WEBアプリケーション開発者の視点から見ると

  • ローカル開発ではdocker runでコンテナを起動しますが、本番環境では複数のサーバーでコンテナを管理する必要があります
  • ECSが「どのサーバーでコンテナを動かすか」「コンテナが停止したら再起動する」といった運用を自動化

主な概念

概念 説明
Cluster コンテナを実行するためのグループ -
Task Definition コンテナの設定書(Dockerfileの実行時版) CPUメモリ、環境変数、ポート設定
Service Task Definitionを基に、指定した数のタスクを維持 「常に2つのタスクを動かす」
Task Task Definitionから作成される実際のコンテナ実行単位 動作中のコンテナインスタンス

Fargate起動タイプ

今回はFargateを使用します。これは、サーバーレスなコンテナ実行環境です。

EC2起動タイプとの違い

項目 Fargate EC2
サーバー管理 不要(AWS側で管理) 必要(自分でEC2を管理)
料金 使用したCPU・メモリ分のみ EC2インスタンス料金
スケーリング 自動 手動設定が必要
学習コスト 低い 高い

IAMロールの種類

ECSでは2つのIAMロールが必要です。

ECS Execution Role

用途: ECSサービスがタスクを起動・管理するための権限

主な権限

  • ECRからDockerイメージをpull
  • CloudWatch Logsにログを出力
  • Secrets Managerから機密情報を取得

ECS Task Role

用途: アプリケーション(コンテナ内のプログラム)が使用する権限

主な権限

  • S3バケットへのアクセス
  • RDSへの接続
  • 外部APIの呼び出し

権限の分離

ローカル開発では、開発者のAWSクレデンシャルですべてのリソースにアクセスできますが、本番環境では「必要な権限のみ」を付与する原則が重要です。

今回作成するネットワーク構成

リソース 説明 数量
ECS Cluster コンテナを実行するためのクラスター 1個
ECS Execution Role ECSサービスがタスクを実行するためのIAMロール 1個
ECS Task Role アプリケーションが使用するIAMロール 1個
ECR Repository Dockerイメージを保存するリポジトリ 1個
CloudWatch Log Group アプリケーションのログを保存 1個

ネットワークフロー

  1. ECR: Dockerイメージの保存・取得
  2. ECS Cluster: Fargateタスクの実行環境
  3. CloudWatch Logs: アプリケーションログの集約
  4. ALB: 前回作成したTarget Groupにタスクを登録

Terraformコードの実装

ECSクラスター

Fargateベースのクラスターを作成します。

# terraform/ecs.tf

# ECS Cluster
resource "aws_ecs_cluster" "main" {
  name = "${var.project_name}-${var.environment}-cluster"

  setting {
    name  = "containerInsights"
    value = "enabled"
  }

  tags = {
    Name = "${var.project_name}-${var.environment}-cluster"
  }
}

# ECS Cluster Capacity Providers
resource "aws_ecs_cluster_capacity_providers" "main" {
  cluster_name = aws_ecs_cluster.main.name

  capacity_providers = ["FARGATE", "FARGATE_SPOT"]

  default_capacity_provider_strategy {
    base              = 1
    weight            = 100
    capacity_provider = "FARGATE"
  }
}

Container Insightsについて

Container Insightsは、コンテナのメトリクス(CPU、メモリ使用率など)を自動収集する機能です。追加料金が発生しますが、監視には便利です。

IAMロール

ECS Execution RoleとTask Roleを作成します。

# terraform/ecs.tf

# ECS Execution Role
resource "aws_iam_role" "ecs_execution_role" {
  name = "${var.project_name}-${var.environment}-ecs-execution-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ecs-tasks.amazonaws.com"
        }
      }
    ]
  })

  tags = {
    Name = "${var.project_name}-${var.environment}-ecs-execution-role"
  }
}

# ECS Execution Role Policy Attachment
resource "aws_iam_role_policy_attachment" "ecs_execution_role_policy" {
  role       = aws_iam_role.ecs_execution_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

# ECS Task Role
resource "aws_iam_role" "ecs_task_role" {
  name = "${var.project_name}-${var.environment}-ecs-task-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ecs-tasks.amazonaws.com"
        }
      }
    ]
  })

  tags = {
    Name = "${var.project_name}-${var.environment}-ecs-task-role"
  }
}

# ECS Task Role用のカスタムポリシー(アプリケーション固有の権限)
resource "aws_iam_role_policy" "ecs_task_role_policy" {
  name = "${var.project_name}-${var.environment}-ecs-task-policy"
  role = aws_iam_role.ecs_task_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ]
        Resource = "${aws_cloudwatch_log_group.ecs.arn}:*"
      }
    ]
  })
}

ECRリポジトリ

Dockerイメージを保存するためのプライベートリポジトリを作成します。

# terraform/ecr.tf

# ECR Repository
resource "aws_ecr_repository" "app" {
  name                 = "${var.project_name}-${var.environment}-app"
  image_tag_mutability = "MUTABLE"
  force_delete         = true

  image_scanning_configuration {
    scan_on_push = true
  }

  tags = {
    Name = "${var.project_name}-${var.environment}-app-repo"
  }
}

# ECR Repository Policy(開発環境用の簡素化されたポリシー)
resource "aws_ecr_repository_policy" "app" {
  repository = aws_ecr_repository.app.name

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "AllowPull"
        Effect = "Allow"
        Principal = {
          AWS = aws_iam_role.ecs_execution_role.arn
        }
        Action = [
          "ecr:GetDownloadUrlForLayer",
          "ecr:BatchGetImage",
          "ecr:BatchCheckLayerAvailability"
        ]
      }
    ]
  })
}

CloudWatch Logs

アプリケーションのログを保存するLog Groupを作成します。

# terraform/cloudwatch.tf

# CloudWatch Log Group for ECS
resource "aws_cloudwatch_log_group" "ecs" {
  name              = "/ecs/${var.project_name}-${var.environment}"
  retention_in_days = 14  # 開発環境では短期間で削除

  # 削除時にログデータも強制削除
  skip_destroy = false

  tags = {
    Name        = "${var.project_name}-${var.environment}-ecs-logs"
    Environment = var.environment
  }
}

ログ保持期間について

本番環境では30日以上に設定することが一般的ですが、開発環境ではコスト削減のため14日に設定しています。

出力の更新

作成したリソースの情報をterraform/outputs.tfに追加します。

# terraform/outputs.tf(既存の出力に追加)

# ECS関連の出力
output "ecs_cluster_id" {
  description = "ECS Cluster ID"
  value       = aws_ecs_cluster.main.id
}

output "ecs_cluster_arn" {
  description = "ECS Cluster ARN"
  value       = aws_ecs_cluster.main.arn
}

output "ecs_execution_role_arn" {
  description = "ECS Execution Role ARN"
  value       = aws_iam_role.ecs_execution_role.arn
}

output "ecs_task_role_arn" {
  description = "ECS Task Role ARN"
  value       = aws_iam_role.ecs_task_role.arn
}

# ECR関連の出力
output "ecr_repository_url" {
  description = "ECR Repository URL"
  value       = aws_ecr_repository.app.repository_url
}

output "ecr_repository_arn" {
  description = "ECR Repository ARN"
  value       = aws_ecr_repository.app.arn
}

# CloudWatch Logs関連の出力
output "cloudwatch_log_group_name" {
  description = "CloudWatch Log Group Name"
  value       = aws_cloudwatch_log_group.ecs.name
}

output "cloudwatch_log_group_arn" {
  description = "CloudWatch Log Group ARN"
  value       = aws_cloudwatch_log_group.ecs.arn
}

リソースを作成

Dockerコンテナ内で以下のコマンドを実行します。

# terraformディレクトリへ移動
cd terraform

# 実行計画の確認
terraform plan

# リソースの作成
terraform apply

ECSクラスター自体の作成は数秒で完了しますが、IAMロールの反映には1〜2分程度かかる場合があります。

作成結果の確認

# ECS Cluster情報の確認
terraform output ecs_cluster_id
terraform output ecs_cluster_arn

# IAMロール情報の確認
terraform output ecs_execution_role_arn
terraform output ecs_task_role_arn

# ECR Repository URL の確認(重要:次回のDockerイメージpushで使用)
terraform output ecr_repository_url

# CloudWatch Log Group の確認
terraform output cloudwatch_log_group_name

ecr_repository_urlの出力例

123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/my-project-dev-app

AWS Management Consoleで確認

ECS > クラスター

作成されたクラスターを選択し、以下を確認します

カテゴリ 項目 設定値
基本設定 クラスター名 {project_name}-{environment}-cluster
起動タイプ FARGATE
Container Insights 有効
キャパシティプロバイダー デフォルト FARGATE
利用可能 FARGATE, FARGATE_SPOT
アクティブなサービス サービス数 0 (次回作成予定)
実行中のタスク タスク数 0 (次回作成予定)

IAM > ロール

作成された2つのIAMロールを確認します

ECS Execution Role

  • ロール名: {project_name}-{environment}-ecs-execution-role
  • 信頼されたエンティティ: ecs-tasks.amazonaws.com
  • アタッチされたポリシー: AmazonECSTaskExecutionRolePolicy

ECS Task Role

  • ロール名: {project_name}-{environment}-ecs-task-role
  • 信頼されたエンティティ: ecs-tasks.amazonaws.com
  • インラインポリシー: CloudWatch Logsへの書き込み権限

ECR > リポジトリ

作成されたECRリポジトリを確認します

カテゴリ 項目 設定値
基本設定 リポジトリ名 {project_name}-{environment}-app
イメージタグの変更可能性 MUTABLE
イメージ 保存済みイメージ 0 (次回pushする)

CloudWatch > ログ > ロググループ

作成されたLog Groupを確認します

  • ロググループ名: /ecs/{project_name}-{environment}
  • 保持期間: 14日
  • ログストリーム: 0 (タスク実行時に作成される)

コスト管理

ECSクラスター自体は無料ですが、以下のリソースで料金が発生します。

リソース 料金発生タイミング 概算コスト
ECS Fargate タスク実行中のみ vCPU: $0.04048/時間、メモリ: $0.004445/GB・時間
ECR ストレージ使用量 $0.10/GB・月
CloudWatch Logs ログ保存量 $0.50/GB・月
Container Insights メトリクス取得 追加料金

コスト削減のポイント

Container Insightsを無効にする場合

# terraform/ecs.tf の setting ブロックをコメントアウト
# setting {
#   name  = "containerInsights"
#   value = "enabled"
# }

次のステップ

次回は、RDSデータベースを構築します。今回作成したECS Task RoleにRDSアクセス権限を追加し、アプリケーションからデータベースに接続できる環境を整備します。

  • RDS PostgreSQLインスタンスの作成
  • DB Subnet Group、Multi-AZ設定
  • Secrets Managerでの認証情報管理
  • データベース接続確認

検索

検索条件に一致する記事が見つかりませんでした