- 1 EventBridge × VPC Lattice × Fargate 統合本番運用 — イベント駆動マイクロサービスの最短ルート
- 1.1 1. なぜEventBridge × VPC Lattice × Fargate 統合か — 3軸隣接領域の本番統合パターン
- 1.2 2. EventBridge本番運用 — Rule × EventBus × Pipes × Scheduler
- 1.2.1 EventBridge 4本柱の役割と選定基準
- 1.2.2 Rule Event Pattern 設計 — source + detail-type 厳密化
- 1.2.3 カスタムEventBus vs Default EventBus — 本番使い分け基準
- 1.2.4 EventBridge Pipes 実装 — SQS/DDB Streams → Fargate Task
- 1.2.5 EventBridge Scheduler — cron + Group + DLQ + Retry 設計
- 1.2.6 Fargate Task Target 統合 — TaskOverride でイベントペイロード受渡
- 1.2.7 Dead Letter Queue + Retry Policy 設計
- 1.2.8 mermaid01: EventBridge Rule → Fargate Task 起動フロー
EventBridge × VPC Lattice × Fargate 統合本番運用 — イベント駆動マイクロサービスの最短ルート

本記事は Serverless本番運用 Vol2 (EventBridge×SQS×SNS×Kinesis) + Network本番運用 Vol2 (TGW×PrivateLink×DX) + Container本番運用 Vol1 (ECS×Fargate×ECR) の隣接領域を統合し、イベント駆動マイクロサービスを Fargate + VPC Lattice + EventBridge の3層で実装する本番運用ガイドです。
本記事の対象
- EventBridge Rule/EventBus基礎を理解しており Fargate Service 連携を本番設計したいエンジニア
- VPC Lattice Service Network で Microservice 間通信を実装中のチーム
- Service Discovery + Auth Policy + Container Insights の3層統合に課題を感じる中堅
本記事完遂後の発展: Service Connect + Container Vol2 GitOps編 (ArgoCD/Kustomize) で本番Kubernetes統合へ。
1. なぜEventBridge × VPC Lattice × Fargate 統合か — 3軸隣接領域の本番統合パターン
単一サービス運用の限界と3軸統合の必然性
マイクロサービスアーキテクチャが成熟するにつれ、EventBridge単体・VPC Lattice単体・Fargate単体での運用では回避できない本番課題が顕在化します。
EventBridge単体の限界: Rule → Lambda 直結は Lambda の15分制限という絶対的な壁に当たります。バッチ処理・動画エンコード・機械学習推論・大規模データ変換など、分単位〜時間単位の処理では Fargate Task への統合が必須です。Lambdaのタイムアウト上限を設計時に無視すると、本番で突然ジョブが切断されるインシデントを引き起こします。
VPC Lattice単体の限界: Service Network でマイクロサービス間通信を整備しても、イベント駆動でのサービス呼び出し機構がありません。同期HTTP呼び出しのみのアーキテクチャでは、サービス間の依存が密結合になり、一時的な障害が連鎖します。EventBridge との統合で非同期イベント発行とサービス間デカップリングが実現します。
Fargate単体の限界: ECS Service として常時稼働するコンテナは、低頻度バッチやイベントトリガー処理には過剰なコストです。EventBridge Scheduler + Fargate Task の組み合わせで、実行時のみコンテナを起動するサーバーレスバッチが実現します。VPC Lattice の Auth Policy と組み合わせることで、Fargate Task 間の IAM 認証通信も統一されます。
3軸統合で実現する5つの本番品質
| 品質軸 | 実現要素 | 単体では困難な理由 |
|---|---|---|
| Event-Driven | EventBridge Rule/EventBus/Pipes | Lambda 15分制限超ジョブは Fargate Task 必須 |
| Service Mesh | VPC Lattice Service Network + TargetGroup | サービス発見と認証をネットワーク層で統合 |
| Container Orchestration | Fargate + ECS Task Definition + awsvpc | イベント受信後のコンテナライフサイクル管理 |
| IAM Auth | VPC Lattice Auth Policy + Fargate Task Role | 二重認証の統合設計が単体では複雑化 |
| X-Ray Trace | EventBridge → Fargate → VPC Lattice の3層トレース | Trace Context 伝搬が層をまたぐと断絶 |
隣接3シリーズとの差別化
本記事は以下の3シリーズの延長上に位置しますが、統合設計という点で質的に異なります。
- Serverless本番運用 Vol2 (EventBridge×SQS×SNS×Kinesis): EventBridge の詳細設定と Lambda/SQS との非同期統合にフォーカス。コンテナ・ネットワーク層の統合は対象外。
- Network本番運用 Vol2 (TGW×PrivateLink×DX): VPC 間接続と Transit Gateway 中心。VPC Lattice のサービスメッシュ応用と EventBridge 統合は対象外。
- 本記事 (EventBridge×VPC Lattice×Fargate): 3層を同時に設計・実装し、イベント発火からコンテナ実行・サービス間通信・分散トレースまで一貫した本番運用パターンを提供。
- 痛点1: Lambda 15分制限超で Fargate 統合パターン不明
EventBridge Rule → Lambda でジョブを起動していたが、処理時間が15分超になると強制終了。Fargate Task Target への切り替え方法が不明で、TaskOverride で環境変数をイベントペイロードとして渡す設計にたどり着けない。 - 痛点2: VPC Lattice TargetGroup に Fargate Task が登録されない
ECS Service を VPC Lattice TargetGroup に登録しようとすると失敗。原因は Fargate がawsvpcネットワークモード必須なのに対し、TargetGroup が IP Type で ENI の IP を直接登録する仕様を知らないこと。 - 痛点3: Pipes + DynamoDB Streams → Fargate でデッドレターキュー設計不在
EventBridge Pipes の Source に DynamoDB Streams を設定し Fargate Task を起動する構成で、タスク失敗時の DLQ が未設定。失敗イベントがサイレントに消えて障害原因調査が不可能になる。 - 痛点4: VPC Lattice Auth Policy + Fargate Task Role の二重認証設計が複雑化
VPC Lattice の Service Auth Policy (SigV4 必須) と Fargate Task の IAM Role (ECS Task Execution Role + Task Role) が重なり、どの IAM Principal に何の権限が必要か整理できない。 - 痛点5: 3層 X-Ray 分散トレースが断絶
EventBridge → Fargate → VPC Lattice という呼び出し連鎖で X-Ray Service Map が繋がらない。EventBridge は X-Ray トレースを自動注入しないため、Fargate Task 側でのトレース ID 引き継ぎが必要なことを見落とす。
統合本番運用5原則
本記事を通じて以下の5原則を実装します。それぞれのセクションで具体的な Terraform コードとともに解説します。
- EventBus分離原則: 業務イベントはカスタム EventBus で分離。Default EventBus は AWS サービスイベント専用として混在を防ぐ。
- Service Network階層化原則: VPC Lattice Service Network はワークロード境界 (prod/staging) 単位で分離。一つの Service Network への過剰な Service 集約を避ける。
- Fargate awsvpcモード統一原則: すべての Fargate Task/Service で
awsvpcネットワークモードを使用。VPC Lattice TargetGroup (IP Type) との整合性を確保。 - Auth Policy統合原則: VPC Lattice Auth Policy と Fargate Task Role の IAM Principal を明示的にマッピング。暗黙の権限継承に頼らない。
- X-Ray 3層トレース原則: EventBridge → Fargate Task → VPC Lattice Endpoint の各層でトレース Context を明示的に伝搬。X-Ray SDK の手動計装を省略しない。
Serverless本番運用 Vol2 — EventBridge×SQS×SNS×Kinesis
2. EventBridge本番運用 — Rule × EventBus × Pipes × Scheduler

EventBridge 4本柱の役割と選定基準
EventBridge は単一サービスのように見えて、実際には4つの独立した機能柱で構成されています。本番運用では各柱の役割を明確に分離し、用途に応じて使い分けることが重要です。
| コンポーネント | 主用途 | Fargate統合パターン | 特記事項 |
|---|---|---|---|
| EventBridge Rule | イベントパターンマッチング → Target起動 | Rule → ECS RunTask | 1 Rule = 最大5 Targets |
| EventBus | イベントルーティングの分離・アーカイブ | カスタムEventBus → Rule → Fargate | Cross-account送信可能 |
| Pipes | ソース→Target 変換パイプライン | SQS/DDB Streams → Fargate Task | Filtering + Enrichment 内蔵 |
| Scheduler | cron/one-time スケジュール実行 | Scheduler → ECS RunTask | スケジューラ専用 (Rule.schedule_expression の後継) |
Rule Event Pattern 設計 — source + detail-type 厳密化
Event Pattern は source と detail-type の二段階で絞り込むのが本番品質の基本です。detail のみで絞り込むと、他サービスや他環境のイベントが意図せず一致するリスクがあります。
{
"source": ["com.myapp.order-service"],
"detail-type": ["OrderCreated"],
"detail": {
"status": ["PENDING"],
"amount": [{ "numeric": [">=", 10000] }]
}
}
このパターンは com.myapp.order-service が発行した OrderCreated イベントのうち、status=PENDING かつ amount >= 10000 のものだけを Fargate Task で処理します。source を省略すると Default EventBus の全イベントにマッチする可能性があるため、必ず指定してください。
Terraform での実装:
resource "aws_cloudwatch_event_rule" "order_fargate" {
name = "order-fargate-processor"
description = "OrderCreated(PENDING, amount>=10000) → Fargate Task"
event_bus_name = aws_cloudwatch_event_bus.app.name
event_pattern = jsonencode({
source= ["com.myapp.order-service"]
detail-type = ["OrderCreated"]
detail = {
status = ["PENDING"]
amount = [{ numeric = [">=", 10000] }]
}
})
tags = {
Environment = "production"
ManagedBy= "terraform"
}
}
カスタムEventBus vs Default EventBus — 本番使い分け基準
Default EventBus は AWS サービス (EC2 State Change, RDS, S3 Event Notification 等) が自動的にイベントを送信するバスです。業務アプリケーションのカスタムイベントを Default EventBus に混在させると、イベントの整理・アーカイブ・監査が複雑化します。
resource "aws_cloudwatch_event_bus" "app" {
name = "myapp-production"
tags = {
Environment = "production"
Purpose = "application-events"
}
}
# EventBus Policy: Cross-account イベント受信 (同一Org内)
resource "aws_cloudwatch_event_bus_policy" "app" {
event_bus_name = aws_cloudwatch_event_bus.app.name
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Sid = "AllowOrgAccounts"
Effect = "Allow"
Principal = { AWS = "*" }
Action = "events:PutEvents"
Resource = aws_cloudwatch_event_bus.app.arn
Condition = {
StringEquals = {
"aws:PrincipalOrgID" = var.organization_id
}
}
}]
})
}
カスタムEventBus を使うべき場合:
– アプリケーション固有のカスタムイベント発行
– 複数アカウント・複数環境への Cross-account ルーティング
– イベントのアーカイブ・リプレイが必要な業務フロー
– Default EventBus とのイベント分離が監査要件になる場合
Default EventBus を使うべき場合:
– EC2 インスタンス状態変化・RDS フェイルオーバー等の AWS サービスイベント受信
– CloudTrail イベントのリアルタイム反応 (API Call 監視等)
EventBridge Pipes 実装 — SQS/DDB Streams → Fargate Task
EventBridge Pipes は Source からのイベントを Filtering → Enrichment → Target の順に処理するフルマネージドパイプラインです。従来 Lambda を中継レイヤーとして挿入していた変換処理を、Pipes の Input Transformation で代替できます。
resource "aws_pipes_pipe" "ddb_to_fargate" {
name = "orders-ddb-to-fargate"
role_arn = aws_iam_role.pipes.arn
source = aws_dynamodb_table.orders.stream_arn
source_parameters {
dynamodb_stream_parameters {
starting_position= "LATEST"
batch_size = 10
maximum_retry_attempts = 3
dead_letter_config {
arn = aws_sqs_queue.pipes_dlq.arn
}
}
filter_criteria {
filter {
pattern = jsonencode({
eventName = ["INSERT"]
dynamodb = { NewImage = { status = { S = ["PENDING"] } } }
})
}
}
}
target = "arn:aws:ecs:${var.region}:${var.account_id}:cluster/${aws_ecs_cluster.app.name}"
target_parameters {
ecs_task_parameters {
task_definition_arn = aws_ecs_task_definition.order_processor.arn
launch_type= "FARGATE"
network_configuration {
aws_vpc_configuration {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.fargate_task.id]
assign_public_ip = "DISABLED"
}
}
overrides {
container_override {
name = "order-processor"
environment {
name = "EVENT_PAYLOAD"
value = "$.detail"
}
environment {
name = "TRACE_ID"
value = "$.id"
}
}
}
task_count = 1
}
}
tags = {
Environment = "production"
ManagedBy= "terraform"
}
}
resource "aws_sqs_queue" "pipes_dlq" {
name = "orders-pipes-dlq"
message_retention_seconds = 1209600 # 14日
visibility_timeout_seconds = 300
tags = {
Environment = "production"
}
}
- DLQ は Pipes Source ごとに独立して設定:
dead_letter_configを省略すると、Target (Fargate Task) 失敗時のイベントがサイレントに消える。本番では必ず SQS DLQ を設定すること。 - maximum_retry_attempts は 3 が基準: 一時的なネットワーク障害・Fargate キャパシティ不足に対応。処理の冪等性 (idempotency) を実装した上で設定する。
- DLQ のメッセージ保持期間は14日: 障害発生から分析・修正・リプレイまでの猶予として14日 (1209600秒) が実運用での推奨値。
- DLQ アラーム設定:
ApproximateNumberOfMessagesVisible > 0で CloudWatch Alarm を設定し、失敗イベントの蓄積を即座に検知する。
EventBridge Scheduler — cron + Group + DLQ + Retry 設計
EventBridge Scheduler は従来の CloudWatch Events Schedule Rules の後継で、タイムゾーン対応・Group管理・フレキシブルウィンドウ・DLQが追加されています。
resource "aws_scheduler_schedule_group" "batch" {
name = "batch-jobs-production"
tags = {
Environment = "production"
}
}
resource "aws_scheduler_schedule" "nightly_batch" {
name = "nightly-order-aggregation"
group_name = aws_scheduler_schedule_group.batch.name
flexible_time_window {
mode = "FLEXIBLE"
maximum_window_in_minutes = 15
}
schedule_expression = "cron(0 2 * * ? *)"
schedule_expression_timezone = "Asia/Tokyo"
target {
arn= "arn:aws:ecs:${var.region}:${var.account_id}:cluster/${aws_ecs_cluster.app.name}"
role_arn = aws_iam_role.scheduler.arn
ecs_parameters {
task_definition_arn = aws_ecs_task_definition.aggregation.arn
launch_type= "FARGATE"
network_configuration {
assign_public_ip = false
security_groups = [aws_security_group.fargate_task.id]
subnets = var.private_subnet_ids
}
task_count = 1
}
retry_policy {
maximum_retry_attempts = 3
maximum_event_age_in_seconds = 3600
}
dead_letter_config {
arn = aws_sqs_queue.scheduler_dlq.arn
}
}
}
resource "aws_sqs_queue" "scheduler_dlq" {
name = "scheduler-dlq-production"
message_retention_seconds = 1209600
tags = { Environment = "production" }
}
Scheduler 本番設計のポイント:
– flexible_time_window で最大15分のずれを許容することで、同時刻起動によるリソース競合を回避
– schedule_expression_timezone = "Asia/Tokyo" で JST ベースのスケジュール指定 (UTC 変換不要)
– retry_policy.maximum_event_age_in_seconds = 3600 でスケジュール起動から1時間以内のリトライに制限
Fargate Task Target 統合 — TaskOverride でイベントペイロード受渡
EventBridge Rule から Fargate Task を起動する際、イベントの内容をコンテナに渡す唯一の手段が ECS Task Override の環境変数です。イベントペイロードを S3 や DynamoDB に書き込んで Fargate から参照するパターンも存在しますが、シンプルな構成では環境変数経由が推奨です。
resource "aws_cloudwatch_event_target" "fargate" {
rule = aws_cloudwatch_event_rule.order_fargate.name
event_bus_name = aws_cloudwatch_event_bus.app.name
target_id= "fargate-order-processor"
arn= aws_ecs_cluster.app.arn
role_arn = aws_iam_role.eventbridge_ecs.arn
ecs_target {
task_definition_arn = aws_ecs_task_definition.order_processor.arn
launch_type= "FARGATE"
task_count = 1
network_configuration {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.fargate_task.id]
assign_public_ip = false
}
}
input_transformer {
input_paths = {
order_id= "$.detail.orderId"
amount = "$.detail.amount"
event_id= "$.id"
event_time = "$.time"
}
input_template = jsonencode({
containerOverrides = [{
name = "order-processor"
environment = [
{ name = "ORDER_ID", value = "<order_id>" },
{ name = "AMOUNT",value = "<amount>" },
{ name = "EVENT_ID", value = "<event_id>" },
{ name = "EVENT_TIME", value = "<event_time>" }
]
}]
})
}
}
resource "aws_iam_role" "eventbridge_ecs" {
name = "eventbridge-ecs-execution"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "events.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy" "eventbridge_ecs" {
name = "ecs-run-task"
role = aws_iam_role.eventbridge_ecs.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect= "Allow"
Action= ["ecs:RunTask"]
Resource = aws_ecs_task_definition.order_processor.arn
},
{
Effect= "Allow"
Action= ["iam:PassRole"]
Resource = [
aws_iam_role.ecs_task_execution.arn,
aws_iam_role.ecs_task_role.arn
]
}
]
})
}
- ecs:RunTask だけでは不十分: EventBridge の IAM Role には
ecs:RunTaskに加えてiam:PassRoleが必要。Task Execution Role と Task Role の両方に PassRole を付与しないとAccessDeniedExceptionが発生する。 - Resource は Task Definition ARN まで絞り込む:
ecs:RunTaskの Resource に*を使うと最小権限原則違反。Task Definition ARN (リビジョン指定 or:*で任意リビジョン) を指定する。 - Fargate awsvpc モードで assign_public_ip = false 必須: Private Subnet に NAT Gateway + VPC Endpoint 構成が前提。Public IP を付与すると VPC Lattice Auth Policy の IP ベース制御が破綻する。
Dead Letter Queue + Retry Policy 設計
EventBridge の DLQ とリトライポリシーは、Rule レベルと Scheduler レベルで独立して設定が必要です。
# Rule レベルの DLQ
resource "aws_cloudwatch_event_target" "fargate_with_dlq" {
rule = aws_cloudwatch_event_rule.order_fargate.name
event_bus_name = aws_cloudwatch_event_bus.app.name
target_id= "fargate-order-processor"
arn= aws_ecs_cluster.app.arn
role_arn = aws_iam_role.eventbridge_ecs.arn
retry_policy {
maximum_retry_attempts = 3
maximum_event_age_in_seconds = 3600
}
dead_letter_config {
arn = aws_sqs_queue.eventbridge_dlq.arn
}
ecs_target {
task_definition_arn = aws_ecs_task_definition.order_processor.arn
launch_type= "FARGATE"
task_count = 1
network_configuration {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.fargate_task.id]
assign_public_ip = false
}
}
}
resource "aws_sqs_queue" "eventbridge_dlq" {
name = "eventbridge-fargate-dlq"
message_retention_seconds = 1209600
visibility_timeout_seconds = 300
redrive_allow_policy = jsonencode({
redrivePermission = "allowAll"
})
tags = { Environment = "production" }
}
# DLQ メッセージ蓄積アラーム
resource "aws_cloudwatch_metric_alarm" "eventbridge_dlq_alarm" {
alarm_name = "eventbridge-fargate-dlq-not-empty"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name= "ApproximateNumberOfMessagesVisible"
namespace = "AWS/SQS"
period = 300
statistic = "Sum"
threshold = 0
alarm_description= "EventBridge Fargate DLQ にメッセージが蓄積しています"
alarm_actions = [aws_sns_topic.alerts.arn]
dimensions = {
QueueName = aws_sqs_queue.eventbridge_dlq.name
}
}
mermaid01: EventBridge Rule → Fargate Task 起動フロー
flowchart LR
subgraph Sources["イベントソース"]
APP["アプリケーション\n(PutEvents)"]
DDB["DynamoDB Streams\n(変更データ)"]
SCHED["Scheduler\n(cron / one-time)"]
end
subgraph EventBridge["EventBridge レイヤー"]
BUS["カスタム EventBus\n(myapp-production)"]
RULE["EventBridge Rule\n(Event Pattern Match)"]
PIPES["EventBridge Pipes\n(Filter → Transform)"]
end
subgraph ECS["ECS / Fargate レイヤー"]
CLUSTER["ECS Cluster\n(Fargate)"]
TASKDEF["Task Definition\n(awsvpc モード)"]
TASK["Fargate Task\n(コンテナ実行)"]
end
subgraph Result["処理結果"]
SUCCESS["正常完了\n(Exit Code 0)"]
DLQ["SQS DLQ\n(失敗イベント保持)"]
ALARM["CloudWatch Alarm\n(DLQ 蓄積検知)"]
end
APP -->|PutEvents| BUS
BUS -->|Route| RULE
DDB -->|Stream| PIPES
SCHED -->|RunTask| CLUSTER
RULE -->|ECS RunTask\n+ TaskOverride| CLUSTER
PIPES -->|ECS RunTask\n+ ContainerOverride| CLUSTER
CLUSTER --> TASKDEF
TASKDEF --> TASK
TASK -->|Exit 0| SUCCESS
TASK -->|Exit != 0\nmax retry 3| DLQ
DLQ -->|ApproximateMessages > 0| ALARM
- ✅ カスタム EventBus でアプリケーションイベントを分離 (Default EventBus との混在なし)
- ✅ Rule Event Pattern に
source+detail-typeを必ず指定 (過剰マッチ防止) - ✅ EventBridge IAM Role に
ecs:RunTask+iam:PassRole(Task Execution Role + Task Role 両方) - ✅ Fargate Task は
awsvpcネットワークモード + Private Subnet + NAT Gateway 構成 - ✅ Rule / Pipes / Scheduler すべてに DLQ + Retry Policy (maximum_retry_attempts=3) を設定
- ✅ DLQ に CloudWatch Alarm (ApproximateNumberOfMessagesVisible > 0) を設定
- ✅ TaskOverride の環境変数でイベントペイロードをコンテナに受渡
- ✅ Scheduler は cron + JST タイムゾーン + flexible_time_window で競合回避