この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
CX事業本部の高橋雄大です。
AWSリソースの監視にはCloudWatchを利用することが多いですが、通知の手段は多岐にわたります。今回はAmazon Connectを活用した電話通知の方法を紹介します。
Amazon Connectとは?
Amazon Connectはクラウド型のコンタクトセンター(コールセンター)です。単純な電話の受発信だけでなく、問い合わせフロー設計による対応の自動化や、他のAWSサービスとの連携が簡単にできます。
料金は電話番号の利用料と分単位の従量課金のみで初期費用は不要です。
Amazon Connect(クラウドベースのコンタクトセンター)| AWS
実装してみた
Amazon ConnectはLambda関数から実行することが可能です。CloudWatchのアラームをSNSからLambdaで受け取り、Lambda関数からAWS SDKを利用してAmazon Connectの問い合わせフローを実行します。
コンタクトセンターの準備
Amazon ConnectはCloudFormationに対応していないため、AWSのマネージメントコンソールから環境を構築する必要があります。以下の記事を参考に、インスタンスの作成から電話番号の取得まで行います。
問い合わせフローの作成
Amazon Connectの問い合わせフローを作成します。以下の図が問い合わせフローの完成形になります。
CloudWatchアラームで検知したエラー内容を通知したいので、「音声の設定」と「プロンプトの再生」を設定します。プロンプトの再生では、どのような形式でメッセージを受け取るのか選択します。
Lambdaが送信したテキストを再生する場合は、以下のようにプロンプトの再生を設定をしてください。
- プロンプト: テキスト読み上げ機能 (アドホック)&動的に入力する
- タイプ: ユーザー定義
- 属性: message
- 解釈する: テキスト
運用監視の実装
環境
以下の環境で実装をしています。
- Lambdaランタイム: Python3.7
- Region: ap-northeast-1
- AWS CLI: 1.16.170
ディレクトリ構成
srcディレクトリにLambda関数のソースコードを配置しています。
├─ src
│ └─ lambda
│ ├─ call_error_message.py
│ └─ run_error.py
└─ template.yaml
Lambda関数
SNSからメッセージを受け取り、Amazon Connectの問い合わせフローを実行するLambda関数です。
src/lambda/call_error_message.py
import boto3
import os
import json
DESTINATION_PHONE_NUMBER = os.getenv('DestinationPhoneNumber')
SOURCE_PHONE_NUMBER = os.getenv('SourcePhoneNumber')
INSTANCE_ID = os.getenv('InstanceId')
CONTACT_FLOW_ID = os.getenv('ContactFlowId')
connect = boto3.client('connect')
def lambda_handler(event: dict, context: dict) -> None:
message = get_message(event)
call_message(message)
def get_message(payload: dict) -> str:
messages = json.loads(payload['Records'][0]['Sns']['Message'])
aws_account_id = messages['AWSAccountId']
message = f'Lambda関数でエラーが発生しました。'
message += f'対象のAWSアカウントIDは {aws_account_id} です。'
return message
def call_message(message: str) -> None:
connect.start_outbound_voice_contact(
DestinationPhoneNumber=DESTINATION_PHONE_NUMBER,
ContactFlowId=CONTACT_FLOW_ID,
InstanceId=INSTANCE_ID,
SourcePhoneNumber=SOURCE_PHONE_NUMBER,
Attributes={
'message': message
}
)
意図的に例外を返却して、CloudWatchでアラームを発生させるLambda関数です。
src/lambda/run_error.py
def lambda_handler(event: dict, context: dict) -> None:
raise Exception('Error!')
テンプレート
Lambda関数とCloudWatchとSNSをCloudFormationでデプロイするためのテンプレートです。CloudWatchのアラームは、RunErrorFunctionで1分間に1回以上のエラーが発生した場合に検知するよう設定しています。
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Parameters:
ProjectName:
Type: String
DestinationPhoneNumber:
Type: String
SourcePhoneNumber:
Type: String
InstanceId:
Type: String
ContactFlowId:
Type: String
Globals:
Function:
Runtime: python3.7
MemorySize: 128
Timeout: 10
Environment:
Variables:
TZ: Asia/Tokyo
Resources:
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName:
Fn::Sub: ${ProjectName}-lambda-execution-role
PolicyDocument:
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: '*'
- Effect: Allow
Action:
- sns:Publish
Resource: '*'
- Effect: Allow
Action:
- connect:StartOutboundVoiceContact
- connect:StopContact
Resource: '*'
CallErrorMessageFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName:
Fn::Sub: ${ProjectName}-call-error-message
CodeUri: src/lambda
Handler: call_error_message.lambda_handler
Role:
Fn::GetAtt:
- LambdaExecutionRole
- Arn
Environment:
Variables:
DestinationPhoneNumber:
Ref: DestinationPhoneNumber
SourcePhoneNumber:
Ref: SourcePhoneNumber
InstanceId:
Ref: InstanceId
ContactFlowId:
Ref: ContactFlowId
Events:
CloudWatchAlarmTopic:
Type: SNS
Properties:
Topic:
Ref: CloudWatchAlarmTopic
RunErrorFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName:
Fn::Sub: ${ProjectName}-run-error
CodeUri: src/lambda
Handler: run_error.lambda_handler
Role:
Fn::GetAtt:
- LambdaExecutionRole
- Arn
ErrorsAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName:
Fn::Sub: ${ProjectName}-errors
Namespace: AWS/Lambda
Dimensions:
- Name: FunctionName
Value: !Sub ${ProjectName}-run-error
MetricName: Errors
ComparisonOperator: GreaterThanOrEqualToThreshold
Period: 60
EvaluationPeriods: 1
Statistic: Sum
Threshold: 1
AlarmActions:
- Ref: CloudWatchAlarmTopic
TreatMissingData: notBreaching
CloudWatchAlarmTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName:
Fn::Sub: ${ProjectName}-cloud-watch-alarm
TopicName:
Fn::Sub: ${ProjectName}-cloud-watch-alarm
環境変数の設定
デプロイで利用する環境変数を設定します。
export PROJECT_NAME='cloudwatch-amazon-connect' #プロジェクト名
export AWS_ACCOUNT_ID='' #AWSアカウントID
export REGION='ap-northeast-1' #リージョン
export DESTINATION_PHONE_NUMBER='+819000000000' #通知先の電話番号
export SOURCE_PHONE_NUMBER='+815000000000' #取得した電話番号
export INSTANCE_ID='' #インスタンスID
export CONTACT_FLOW_ID='' #コンタクトフローID
インスタンスIDとコンタクトフローIDは、Amazon Connectの問い合わせフロー作成画面から確認できます。「追加フロー情報」もしくは「URL」のArnから取得してください。
arn:aws:connect:{AWS::Region}:{AWS::AccountId}:instance/{インスタンスID}/contact-flow/{コンタクトフローID}
S3バケットの作成
パッケージ化したソースコードをアップロードするためのS3バケットを作成します。
aws s3api create-bucket \
--bucket ${PROJECT_NAME}-artifact-${AWS_ACCOUNT_ID} \
--region ${REGION} \
--create-bucket-configuration LocationConstraint=${REGION}
パッケージ
ソースコードをパッケージ化します。
aws cloudformation package \
--template-file template.yaml \
--output-template-file template-output.yaml \
--s3-bucket ${PROJECT_NAME}-artifact-${AWS_ACCOUNT_ID}
デプロイ
CloudFormationのテンプレートに記載した各リソースをデプロイします。
aws cloudformation deploy \
--template-file template-output.yaml \
--stack-name ${PROJECT_NAME}-stack \
--parameter-overrides \
ProjectName=${PROJECT_NAME} \
DestinationPhoneNumber=${DESTINATION_PHONE_NUMBER} \
SourcePhoneNumber=${SOURCE_PHONE_NUMBER} \
InstanceId=${INSTANCE_ID} \
ContactFlowId=${CONTACT_FLOW_ID} \
--no-fail-on-empty-changeset \
--capabilities CAPABILITY_NAMED_IAM
動作確認
RunErrorFunction
を実行して意図的にエラーを発生させます。
aws lambda invoke log \
--invocation-type Event \
--function-name ${PROJECT_NAME}-run-error \
--region ${REGION} \
--payload '{}'
電話通知のみ実行する場合はCallErrorMessageFunction
を実行します。
aws lambda invoke log \
--invocation-type Event \
--function-name ${PROJECT_NAME}-call-error-message \
--region ${REGION} \
--payload '{"Records": [{"Sns": {"Message": "{\"AWSAccountId\": \"12345\"}"}}]}'
通知先の電話番号に音声通知が届けば成功です。
まとめ
CloudWatchアラームの内容をLambdaから簡単に電話で通知することができました。Amazon Connectは他にも様々な機能を備えています。例えば、電話の受信者にプッシュ番号を入力してもらい、Lambda関数で番号に応じた処理を実行することも可能です。
次回はAmazon ConnectからLambda関数を実行させる方法について記事を書こうと思います。