【運用自動化】Amazon Connectでシステム障害を即座に音声通知する仕組みを作ってみた

【運用自動化】Amazon Connectでシステム障害を即座に音声通知する仕組みを作ってみた

2025.12.02

Amazon Connect アドベントカレンダー 2025、3日目の記事です!

クラスメソッドとギークフィードさん、AWS Japanさんの有志が募ってチャレンジしている企画になります。

(アドベントカレンダーのカレンダー一覧はこちら↓)

https://qiita.com/advent-calendar/2025/amazon-connect

はじめに

システム障害は、緊急度によっては1分1秒を争う迅速な対応が必要になります。
しかし、運用担当者への連絡など、コミュニケーションに時間がかかる場合があります。
Amazon Connect を活用すると、音声通知が自動化できると思ったので試してみました!

アーキテクチャ図

以下の構成で、EC2の障害検知から自動通知までを実現します。

  1. CloudWatch Alarm が EC2 の CPU 使用率を監視
  2. アラーム状態になると EventBridge がトリガー
  3. Step Functions が DynamoDB から通知先情報を取得
  4. SNSでメール通知、Amazon Connect で電話発信

CleanShot 2025-12-01 at 20.32.59@2x.png

前提

  • Amazon EC2
    • Amazon Linux 2023 (ami-03852a41f1e05c8e4)
  • Amazon Connect
    • 構築や電話番号取得など、初期設定が完了していること
  • Amazon SNS
    • メールアドレスの紐付けが完了していること

本記事では作成手順については解説しません。
下記のリソースの設定値をご参考ください。

リソースの設定値

CloudWatch Alarm

インスタンスの CPU 使用率が 80% 以上の時にアラート状態になるように設定しました。

CleanShot 2025-12-01 at 16.25.11@2x.png

DynamoDB

CloudShell で、下記の AWS CLI コマンドを入力し、データを入れておきました。
インスタンス ID を基準に、電話番号と SNS ARN がマッピングされるイメージです。

aws dynamodb put-item \
    --table-name <DynamoDBテーブル名> \
    --item '{
      "instance_id": {"S": "<EC2インスタンスID>"},
      "phonenumber": {"S": "<電話番号>"},
      "sns_arn": {"S": "<SNSトピックARN>"}
    }'

CleanShot 2025-12-01 at 18.21.08@2x.png

CleanShot 2025-12-01 at 18.22.33@2x.png

Amazon Connect

日本語でプロンプトを読み上げるシンプルな構成で設定しました。

CleanShot 2025-12-01 at 21.02.51@2x.png

CleanShot 2025-12-01 at 21.04.47@2x.png

StepFunctions

全体的な StepFunctions の処理の流れは下記のイメージです。

CleanShot 2025-12-01 at 20.16.34@2x.png

以下はサンプルコードです。
"SourcePhoneNumber": "<AmazonConnectに登録した電話番号>", は、
例えば 050 の場合、+8150xxxxxxxx のような形で入力します。

{
  "Comment": "EC2 インスタンス障害通知ワークフロー",
  "StartAt": "DynamoDB から情報取得",
  "States": {
    "DynamoDB から情報取得": {
      "Type": "Task",
      "Resource": "arn:aws:states:::dynamodb:getItem",
      "Parameters": {
        "TableName": "<DynamoDBテーブル名>",
        "Key": {
          "instance_id": {
            "S.$": "$.detail.configuration.metrics[0].metricStat.metric.dimensions.InstanceId"
          }
        }
      },
      "ResultPath": "$.dynamodb_result",
      "Next": "インスタンス情報が存在するか確認",
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "Next": "エラー処理",
          "ResultPath": "$.error"
        }
      ]
    },
    "インスタンス情報が存在するか確認": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.dynamodb_result.Item",
          "IsPresent": true,
          "Next": "メッセージ作成"
        }
      ],
      "Default": "インスタンス情報なし"
    },
    "メッセージ作成": {
      "Type": "Pass",
      "Parameters": {
        "instance_id.$": "$.detail.configuration.metrics[0].metricStat.metric.dimensions.InstanceId",
        "alarm_name.$": "$.detail.alarmName",
        "state.$": "$.detail.state.value",
        "reason.$": "$.detail.state.reason",
        "timestamp.$": "$.detail.state.timestamp",
        "sns_arn.$": "$.dynamodb_result.Item.sns_arn.S"
      },
      "ResultPath": "$.message_data",
      "Next": "SNS 通知送信"
    },
    "SNS 通知送信": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Parameters": {
        "TopicArn.$": "$.message_data.sns_arn",
        "Subject": "【緊急】EC2 インスタンス障害通知",
        "Message.$": "States.Format('EC2 インスタンスで障害が発生しました。\n\n【詳細情報】\nインスタンスID: {}\nアラーム名: {}\n状態: {}\n理由: {}\n発生時刻: {}\n\n至急ご確認ください。', $.message_data.instance_id, $.message_data.alarm_name, $.message_data.state, $.message_data.reason, $.message_data.timestamp)"
      },
      "ResultPath": "$.sns_result",
      "Next": "Amazon Connect 発信"
    },
    "Amazon Connect 発信": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:connect:startOutboundVoiceContact",
      "Parameters": {
        "InstanceId": "<AmazonConnectインスタンスID>",
        "ContactFlowId": "<AmazonConnectフローID>",
        "SourcePhoneNumber": "<AmazonConnectに登録した電話番号>",
        "DestinationPhoneNumber.$": "$.dynamodb_result.Item.phonenumber.S"
      },
      "ResultPath": "$.connect_result",
      "Next": "成功",
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "Next": "成功",
          "ResultPath": "$.connect_error"
        }
      ]
    },
    "成功": {
      "Type": "Succeed"
    },
    "インスタンス情報なし": {
      "Type": "Fail",
      "Error": "InstanceNotFound",
      "Cause": "指定されたインスタンスIDが DynamoDB に登録されていません"
    },
    "エラー処理": {
      "Type": "Fail",
      "Error": "WorkflowError",
      "Cause": "ワークフロー実行中にエラーが発生しました"
    }
  }
}

※ 注意

Step Functions の作成時に自動的に付与されるロールでは、権限が足りません。
以下のポリシーを必ず追加してください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "connect:StartOutboundVoiceContact",
            "Resource": "arn:aws:connect:ap-northeast-1:<AWSアカウントID>:instance/*/contact/*"
        }
    ]
}

EventBridge

対象 CloudWatch Alarm が ALARM 状態の時にトリガーされるように設定しました。

{
  "source": ["aws.cloudwatch"],
  "detail-type": ["CloudWatch Alarm State Change"],
  "detail": {
    "alarmName": ["<CloudWatchアラーム名>"],
    "state": {
      "value": ["ALARM"]
    }
  }
}

ターゲットには、Step Functions を登録しています。

CleanShot 2025-12-01 at 20.36.48@2x.png

▼ Amazon_EventBridge_Invoke_Step_Functions_xxxxxxxxx IAM ロールのポリシー

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "states:StartExecution"
            ],
            "Resource": [
                "arn:aws:states:ap-northeast-1:<AWSアカウントID>:stateMachine:<StepFunctions名>"
            ]
        }
    ]
}

▼ Amazon_EventBridge_Invoke_Step_Functions_xxxxxxxxx IAM ロールの信頼関係

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "events.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

障害発生からの流れ

CleanShot 2025-12-01 at 20.32.59@2x.png

EC2 インスタンスで stress コマンドで負荷をかけてみます。

$ stress --cpu 2 --timeout 300s

CloudWatch Alarm がアラーム状態になり、EventBridge がトリガーされます。

CleanShot 2025-12-01 at 20.52.03@2x.png

EventBridge → Step Functions

DynamoDB を確認し、SNS トピックにメール通知を実施した後、
phonenumber に電話をかけてアナウンスプロンプトを読み上げます。

CleanShot 2025-12-01 at 20.32.59@2x.png

結果

メール通知

下記のように、案内メールが届いていました。

CleanShot 2025-12-01 at 21.00.30@2x.png

電話連絡

実際、Amazon Connect の電話番号で電話がかかってきて、
下記の CloudWatch Logs のように案内アナウンスが流れてきました。

{
    (...省略)
    "Parameters": {
        "TextToSpeechType": "text",
        "Text": "只今、システム障害が発生しました。\n詳細はメールにてご案内しております。",
        "Voice": "Kazuha"
    }
}

まとめ

障害発生時には、速やかな対応が重要です。
今回は、EC2 の障害検知から自動連絡までの仕組みを作ってみました。
実際アラート状態になってから、数秒程度でメール通知と電話連絡がきました。
Amazon Connect の運用自動化で、障害発生時の初動対応を大幅に効率化できそうですね!

参考記事

https://dev.classmethod.jp/articles/amazon-connect-stepfunctions-startoutboundvoicecontact/

この記事をシェアする

FacebookHatena blogX

関連記事