はじめに
GMOコネクトの小倉です。
よくありがちなAWSでの簡易な監視通知の構成だと、通知内容が「人に優しくない」ことで苦労したこと、ありませんか?
↑を解消するにあたって、Lambda function(プログラム実装)を仲介させれば当然、良い感じの監視通知になることは自明ですが、デメリットとして将来的なRuntime versionupへの追随等、煩わしい点があることも否めないです。
そのため今回は、Lambda functionを仲介させない方式で監視通知内容の改善を試し、技術的な要点をまとめました。
本投稿がどなたかの一助になれば幸いです。
まとめ
- Lambda functionを利用せずとも、監視通知内容の整形ができる
- slack向けに全体メンションも可能
AWS構成 概略(before)とslack通知内容
ここで、この構成の時に届いたslack通知を見てみましょう。
・・・・どうでしょう?
これは個人的には分かりづらいと感じたのと、メンションされないので通知に気付けない可能性もあると思います。
AWS構成 概略(after)とslack通知内容
いかがでしょうか?
- 通知内容が箇条書きされており、内容がシンプルでわかりやすい
- メンションされており、通知に気づきやすい
と思います。
ざっくり何をしたか?
- CloudWatch AlarmのTarget設定を削除
- CloudWatch Alarm State Changeをトリガーに動作する、EventBridge ruleを追加。
注意 :
(1) どのCloudWatch AlarmがState ChangeしたらEventBridge ruleが動作するか? 対象のCloudWatch Alarmを列挙=ホワイトリスト方式で指定します。 指定しない場合、例えば全体メンションしたくないAlarmについても当該のEventBridge ruleを介して通知されてしまうことになります。
(2) 入力トランスフォーマーを利用して、input event内容を整形します。
作成したCloudFormation
抜粋ではありますが、出来上がったCloudFormationを紹介いたします。
(ⅰ) app.yaml
ポイント :
(1) AlarmActionsとOKActionsは不要のため、コメントアウト
(2) Outputsで、当該AlarmにCloudFormation上、一意の名付けをして変数export
Resources:
ECSAlarmCPUUtilization:
Type: AWS::CloudWatch::Alarm
Condition: IsCreateEcsService
Properties:
AlarmName: !Sub "${EnvPrefix}-${Env}-alarm-ecs-CPUUtilization-${DeployRegion}"
AlarmDescription: !Sub "ECS Fargate(${Env}/${DeployRegion}) CPUUtilization avg > 80%"
# Alarm/OK Actions will hook by eventbridge. That's reason why don't need to define below.
# AlarmActions:
# - !Ref AlarmSNSTopicArn
# OKActions:
# - !Ref AlarmSNSTopicArn
MetricName: CPUUtilization
Namespace: AWS/ECS
Dimensions:
- Name: ClusterName
Value: !Ref ECSCluster
- Name: ServiceName
Value: !GetAtt ECSService.Name
Statistic: Average
Period: 60
EvaluationPeriods: 2
Threshold: 80
ComparisonOperator: GreaterThanThreshold
TreatMissingData: missing
Outputs:
## Alarm
ECSAlarmCPUUtilization:
Value: !Ref ECSAlarmCPUUtilization
Export:
Name: !Sub "${AWS::StackName}-ECSAlarmCPUUtilization"
(ⅱ) notify.yaml
ポイント :
(1) 変数としてexportしたAlarm名をimportするため、入力パラメータでapp.yamlのスタック名を指定しつつ、alarmNameでホワイトリスト化
(2) 入力パス(InputPathsMap)でinputイベントと変数mappingを行い、入力テンプレート(InputTemplate)で整形
(3) slack全体メンションするため、入力テンプレートで <!channel>\n
を指定
Parameters:
AppStack:
Type: String
Default: dev1-app
AllowedValues:
- dev1-app
- dev2-app
Description: Name of the Application stack.
Resources:
EventsRuleCwAlarmStateChange:
Type: AWS::Events::Rule
Condition: IsDeployEventBridgeRuleCwAlarmStateChange
Properties:
Name: !Sub "${EnvPrefix}-${Env}-events-rule-cw-alarm-state-change-${DeployRegion}"
EventPattern:
source:
- aws.cloudwatch
detail-type:
- CloudWatch Alarm State Change
detail:
alarmName:
- Fn::ImportValue: !Sub "${AppStack}-ECSAlarmCPUUtilization"
state:
value:
- ALARM
- OK
Targets:
- Id: "EventsRuleCwAlarmStateChangeSns"
Arn: !Ref AlarmSNSTopicArn
InputTransformer:
InputPathsMap:
alarmName: "$.detail.alarmName"
alarmDescription: "$.detail.alarmDescription"
reason: "$.detail.state.reason"
latestState: "$.detail.state.value"
previousState: "$.detail.previousState.value"
time: "$.time"
region: "$.region"
accountId: "$.account"
InputTemplate: >-
{"version":"1.0","source":"custom","content":{"description":"<!channel>\n:rotating_light: *AccountId:* <accountId>\n*Alarm:* <https://console.aws.amazon.com/cloudwatch/home?region=<region>#alarm:name=<alarmName>|<alarmName>>\n*AlarmDescription:* <alarmDescription>\n*LatestState:* <latestState>\n*PreviousState:* <previousState>\n*Reason:* <reason>\n*Region:* <region>\n*Time:* <time>"}}
State: "ENABLED"
最後に
ご一読いただき、ありがとうございました。
弊社では、AWSを使ったサービスの開発や技術支援をはじめ、幅広い支援を行っておりますので、何かありましたらお気軽にお問合せください。