ChatOpsの一環としてサービスのアラートをSlackに投げれるようにします
さっと調べた感じ今だとCloudwatch -> SNS -> Lambda -> Slackというのがlambda to slackのblueprintもあるので楽そう + 使ってみたかったのですが担当サービスがそもそもlambdaが使えないリージョンだったため断念
なので代替案としてCloudwatch -> SNS -> SQS -> script -> Slack で実装してみます
既にSNSで特定のメールアドレスに対して通知を送るようにしてあるので、メール+Slackで通知がいくようにします
準備
SQSの作成
slack通知用のQueueを作成します
特別な設定はしません
今回は「sns2slack」という名前のQueueを作成
ここで作成したQueueのARNをメモしておきます
SNSトピックの作成
queueに通知するためのトピックを作成します
既にメール通知用のトピックがあればそれに追加
メール、HTTPなど複数選択できるので今回はメール+SQSへの通知をするように設定
CreateSubscriptionで通知先を追加します
Protocolに「Amazon SQS」に設定
EndpointにSQSの作成でメモしたQueueのARNを入力
Emailに関しても同様の手順で設定します
権限の付与
SNSがSQSへメッセージを送るための権限が必要なので下記手順を参考に権限を付与する(ステップ2)
Amazon SQS キューへの Amazon SNS メッセージの送信
対象Queueを選択してPerissionsのタブをクリック
「Add Permission」をクリックして権限の追加を行います
参考に書いてあるとおりに入力を行います
valueにはSNSのTopicのARNを入力します
スクリプトの準備
SQSへメッセージを取得しにいくスクリプトを用意します
#!/bin/bash # AWS configuration SQS_URL="<sqs url>" REGION="<region>" # slack configuration SLACK_CHANNEL="<channel name>" SLACK_USERNAME="CloudWatchAlarmBot" SLACK_ICON="<icon_name>" SLACK_WEBHOOK_URL="<slack webhook url>" # project configuration PROJECT="<project name>" warn(){ echo $1 >&2 sleep 10 continue } delete_queue(){ handle=$1 aws sqs delete-message --queue-url ${SQS_URL} --region ${REGION} --receipt-handle ${handle} } push2slack(){ messages=($@) set -- ${messages[*]} name=$1 description=$2 state=$3 metric=$4 operator=$5 threshold=$6 period=$7 evaluation_periods=$8 data=`cat << EOF payload={ "channel": "${SLACK_CHANNEL}", "username": "${SLACK_USERNAME}", "icon_emoji": "${SLACK_ICON}", "link_names": 1 , "attachments": [{ "fallback": "Alarm", "color": "#993300", "pretext": "CloudWatch Alarm" , "title": "${description} ", "text": "確認お願いします @channel", "fields": [ { "title": "Project", "value": "$PROJECT", "short": true }, { "title": "Detail", "value": "${metric} ${operator} ${threshold} . check in every ${period} seconds. failed ${evaluation_periods} times.", "short": true } ] }] } EOF` curl -X POST --data-urlencode "${data}" ${SLACK_WEBHOOK_URL} } main(){ while true do res=`aws sqs receive-message --queue-url ${SQS_URL} --region ${REGION}` handle=`echo ${res} | jq -r '.Messages[].ReceiptHandle'` body=`echo ${res} | jq -r '.Messages[].Body'` [[ ${body} == "" || ${handle} == "" ]] && warn 'body or handle not found' IFS=$'\n' messages=`echo ${body} | jq -r '.Message' | jq -r -c ' \ .AlarmName, \ .AlarmDescription, \ .NewStateReason, \ .Trigger.MetricName, \ .Trigger.ComparisonOperator, \ .Trigger.Threshold, \ .Trigger.Period, \ .Trigger.EvaluationPeriods'` push2slack ${messages[*]} IFS=$' \t\n' [[ $? == 0 ]] && delete_queue $handle sleep 10 done } main $@
固定値をそれぞれ設定したものにして実行すればOKです
デーモン化
先述のスクリプトをデーモン化もさせておきたいのでsupervisorでデーモン化させまます
ansibleでスクリプト含め対象サーバにデーモン化させるまでのplaybookを用意しました
READMEに従い実行すると環境が整います
確認
アラート設定を変えて通知がいくか確認します
無事Slackに通知が行きました
感想
- シェルスクリプトに結構時間がかかってしまったのでもっと早く書けるようになりたい
- SQS,SNS共に便利に使えそう
- Lambda使いたかった...