★★ 中級

17. EventBridge

AWS の イベントバス。スケジュール起動(cron)、AWS サービスのイベントへの自動応答、SaaS との連携が 1 つに統合されたサービス。

EventBridge とは

従来の「CloudWatch Events」が EventBridge にリブランド・拡張されたもの。次の 3 通りの使い方:

  1. スケジュール起動: 毎時 0 分に Lambda 起動、毎日 03:00 に ECS タスク実行など
  2. AWS サービスのイベントに応答: EC2 が停止 → SNS 通知、CodeBuild 完了 → Slack 通知
  3. カスタムイベントバス: 自社アプリが発行したイベントを下流の複数サービスに配信

SNS との違い: SNS は「pub/sub」、EventBridge は「ルール+ターゲット」のフィルタリング型。複雑な条件マッチに強い。

スケジュール(cron)

aws_cloudwatch_event_rule + aws_cloudwatch_event_target(リソース名は CloudWatch Events 時代の名残)。

resource "aws_cloudwatch_event_rule" "nightly" {
  name                = "nightly-cleanup"
  description         = "毎日 03:00 JST にクリーンアップ Lambda を起動"
  schedule_expression = "cron(0 18 * * ? *)"   # UTC 18:00 = JST 03:00
}

resource "aws_cloudwatch_event_target" "nightly_lambda" {
  rule      = aws_cloudwatch_event_rule.nightly.name
  target_id = "nightly-cleanup"
  arn       = aws_lambda_function.cleanup.arn
}

resource "aws_lambda_permission" "from_eventbridge" {
  statement_id  = "AllowEventBridge"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.cleanup.function_name
  principal     = "events.amazonaws.com"
  source_arn    = aws_cloudwatch_event_rule.nightly.arn
}

Cron 式の書式

# cron(分 時 日 月 曜日 年)
cron(0  18 *  *   ?   *)   # 毎日 18:00 UTC
cron(*/5 * *  *   ?   *)   # 5 分おき
cron(0  9  *  *   MON *)   # 毎週月曜 09:00 UTC
cron(0  0  1  *   ?   *)   # 毎月 1 日 00:00 UTC

# rate 式(より簡単)
rate(5 minutes)
rate(1 hour)
rate(1 day)

イベントパターンマッチ

「EC2 が stopped 状態になったら Lambda を呼ぶ」のような条件起動。

resource "aws_cloudwatch_event_rule" "ec2_stopped" {
  name        = "ec2-stopped-notify"
  description = "EC2 が停止したら通知"

  event_pattern = jsonencode({
    source      = ["aws.ec2"]
    detail-type = ["EC2 Instance State-change Notification"]
    detail = {
      state = ["stopped", "terminated"]
    }
  })
}

resource "aws_cloudwatch_event_target" "ec2_stopped_to_sns" {
  rule      = aws_cloudwatch_event_rule.ec2_stopped.name
  target_id = "to-sns"
  arn       = aws_sns_topic.alerts.arn

  input_transformer {
    input_paths = {
      instance = "$.detail.instance-id"
      state    = "$.detail.state"
    }
    input_template = "\"Instance <instance> entered state: <state>\""
  }
}

典型的なイベントソース

sourcedetail-type
aws.ec2EC2 Instance State-change Notification
aws.codebuildCodeBuild Build State Change
aws.ecsECS Task State Change
aws.s3Object Created(要 EventBridge 通知有効化)
aws.guarddutyGuardDuty Finding
aws.healthAWS Health Event(メンテ通知等)

EventBridge Scheduler(推奨)

2022 年に追加された 新方式のスケジューラaws_cloudwatch_event_rule よりタイムゾーン対応、ワンタイム実行、柔軟な再試行が可能で、新規はこちらが推奨。

resource "aws_iam_role" "scheduler" {
  name = "eventbridge-scheduler"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Action = "sts:AssumeRole"
      Principal = { Service = "scheduler.amazonaws.com" }
    }]
  })
}

resource "aws_iam_role_policy" "scheduler_invoke_lambda" {
  role = aws_iam_role.scheduler.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect   = "Allow"
      Action   = "lambda:InvokeFunction"
      Resource = aws_lambda_function.cleanup.arn
    }]
  })
}

resource "aws_scheduler_schedule" "nightly" {
  name       = "nightly-cleanup"
  group_name = "default"

  flexible_time_window {
    mode = "OFF"
  }

  schedule_expression          = "cron(0 3 * * ? *)"
  schedule_expression_timezone = "Asia/Tokyo"   # ← タイムゾーン直接指定 (旧方式は UTC のみ)

  target {
    arn      = aws_lambda_function.cleanup.arn
    role_arn = aws_iam_role.scheduler.arn

    retry_policy {
      maximum_event_age_in_seconds = 86400
      maximum_retry_attempts       = 3
    }
  }
}

カスタムイベントバス

自社アプリのドメインイベント(注文確定、決済完了 etc.)を発行・購読する基盤。

resource "aws_cloudwatch_event_bus" "app" {
  name = "myapp-events"
}

resource "aws_cloudwatch_event_rule" "order_created" {
  name           = "order-created"
  event_bus_name = aws_cloudwatch_event_bus.app.name

  event_pattern = jsonencode({
    source      = ["myapp.orders"]
    detail-type = ["OrderCreated"]
  })
}

# アプリは PutEvents API で投入:
# aws events put-events --entries '[{
#   "Source":"myapp.orders","DetailType":"OrderCreated",
#   "Detail":"{\"orderId\":\"123\"}",
#   "EventBusName":"myapp-events"
# }]'