概要
- AWS DMS(Database Migration Service)のエラーをSlackへ通知するための実装法
- AWS Chatbotを試したがUnsupportedEventsが発生していたため、Chatbotの代わりにLambdaで通知するようにした
- Cloud Formation(yml)で実装
やったこと
先に実装内容を載せておきます
DMS, SNS, Lambda Permission, IAMの設定内容
AWSTemplateFormatVersion: 2010-09-09
Resources:
DMSAlertInstanceEventSubscription:
Type: "AWS::DMS::EventSubscription"
Properties:
Enabled: true
EventCategories:
- "configuration change"
- failure
- deletion
- notification
SnsTopicArn: !Ref DMSAlertSNSTopic
SourceIds:
- instance-test01
SourceType: replication-instance
DMSAlertTaskEventSubscription:
Type: "AWS::DMS::EventSubscription"
Properties:
Enabled: true
EventCategories:
- "state change"
- failure
- deletion
SnsTopicArn: !Ref DMSAlertSNSTopic
SourceIds:
- task-test01
SourceType: replication-task
SNSTopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: DMSNotificationPublishPolicy
Effect: Allow
Principal:
Service:
- "dms.amazonaws.com"
Action:
- "SNS:Publish"
Resource:
- !Ref DMSAlertSNSTopic
Topics:
- !Ref DMSAlertSNSTopic
DMSAlertSNSTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: dms-alert
Subscription:
- Endpoint: !GetAtt DMSAlertLambdaLambdaFunction.Arn
Protocol: lambda
# - Endpoint: xxxxxx@gmail.com
# Protocol: email
LambdaPermission:
Type: AWS::Lambda::Permission
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt DMSAlertLambdaLambdaFunction.Arn
Principal: "sns.amazonaws.com"
SourceArn: !Ref DMSAlertSNSTopic
DMSAlertLambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: dms-alert-lambda-role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Path: /
Policies:
- PolicyName: dms-alert-lambda-policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
- logs:CreateLogGroup
Resource:
- arn:aws:logs:ap-northeast-1:xxxxxx:log-group:/aws/lambda/dms-alert:*
おすすめ
AWS::DMS::EventSubscription
の設定値SourceIds
やEventCategories
はnot requiredなので最初は設定せずに動作確認するのがおすすめです
replication-instanceの動作確認をする場合は、マネコンから設定値Allocated storage (GiB)
あたりを適当に設定変更し即時反映
するとinstanceの終了/起動/設定変更の通知が飛ぶはずです
AWS::SNS::Topic
の通知対象にLambdaだけでなく自身のEmailも設定しておくと、Slackに通知が来ない場合の原因特定の作業に役立ちます
Lambdaの設定内容
function:
DMSAlertLambda:
handler: app/dms_alert/handler.handler
name: dms-alert
memorySize: 256
timeout: 900
runtime: python3.8
role: DMSAlertLambdaRole
environment:
WEBHOOK_URL: "https://hooks.slack.com/services/XXXX/YYYYYYYY/ZZZZZZZZZZZZZZZ"
STAGE: ${self:provider.stage}
CHANNEL: "#dms_alert_channel"
package:
individually: true
include:
- app/dms_alert/**
import json
import os
import requests
from logging import getLogger, INFO
logger = getLogger(__name__)
logger.setLevel(INFO)
url = os.environ['WEBHOOK_URL']
stage = os.environ['STAGE']
channel = os.environ['CHANNEL']
def handler(event, context):
logger.info(json.dumps(event))
text = 'DMS ALERT\n'
try:
json_dict = json.loads(event['Records'][0]['Sns']['Message'])
for key, val in json_dict.items():
text += f'{key}: {val}\n'
except Exception as e:
# 検知内容によってはjsonでないケースがあるが不要なメッセージであるため処理を止める
# "This is a message to notify that DMS will attempt to send you event notifications.. "
logger.info(e)
return
msg = {
"channel": channel,
"text": text
}
encoded_msg = json.dumps(msg).encode('utf-8')
_ = requests.post(url, data=encoded_msg)
logger.info("message: " + text)
event['Records'][0]
の中身のどの値をSlackに通知するか迷いました
結局event['Records'][0]['Sns']['Message']
の中身を全部送信しています
SNS TopicからChatbotにメッセージが送信できなかった
当初Lambdaではなく、AWS Chatbotを経由してメッセージを送信しようと試しましたが、うまく通知されなかったのでここに内容を残しておきます
下記のSNSTopicの設定に加えて、マネージメントコンソールからChatbot Configured clients
の設定画面から上記で追加したTopic紐付けるよう設定(Chatbotの設定は既に登録されていたためCFnで作らなかった)
...
DMSAlertSNSTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: dms-alert
Subscription:
- Endpoint: https://global.sns-api.chatbot.amazonaws.com
Protocol: HTTPS
- Endpoint: xxxxxxx@gmail.com
Protocol: email
しかし、DMSの設定を変更して通知を待てどEmailの方には届くけどSlackの方には届かない状況になりました
CloudWatchが出力しているChatbotのログを確認するとUnsupportedEvents
と出ていました
DMSからのEventはSNS Topic経由でChatbotに流してくれないと判断し、渋々Lambdaで送信処理を実装することに決めました(参考サイト: Amazon SNS から AWS Chatbot を経由した通知がうまくいかない原因と対処方法)
まとめ
Chatbotにだって出どこによっては受け流したくないメッセージがある