CPU使用率が稀に100%付近で張り付いてアプリが動かねぇって事態があるからCloudWatchで監視してアラートをGoogleChatにメッセージ送信する。
方式としては、CloudWatchでEC2のCPUを監視して90%を超えたらLambdaを叩いてGoogleChatにメッセージを飛ばす。
- GoogleChatでメッセージ受信用のスペースを作る。
- LambdaでアラートをGoogleChatにメッセージ送信する関数を作る。
- CloudWatchでCPU監視をアラーム発生時にLambdaの関数を呼び出す。
細けぇところは省略しながら書いていく。
※アラームとアラートの違いは他に任せるとして、この記事では私の気分で書く!
GoogleChatの設定
スペースを追加してWebHookを追加する。WebHookのURLはLambdaの関数内で直書きする。

Lambdaの関数作成
関数を作成する。関数名やらは適当に。ここではPython3.13を使用する。

ソースコードを貼り付けて、Deployをクリック

ソースコードは以下の内容
import json
import urllib.request
def lambda_handler(event, context):
# message_detail = 'from aws lambda'
message_detail = event['alarmData']['alarmName'] + " " + event['alarmData']['configuration']['description']
message = {'text': message_detail}
url = '<<GoogleChatのWebhook URL>>'
headers = {'Content-Type': 'application/json; charset=UTF-8'}
byte_encoded = json.dumps(message).encode('utf-8')
req = urllib.request.Request(
url=url
, data=byte_encoded
, headers=headers
)
response = urllib.request.urlopen(req)
print(response.read())
とりあえずGoogleChatに送信できるか気になる!message_detail
を固定文字列に変えて、デプロイしてからテストボタンを押すと、GoogleChatにメッセージが送られる。

ここでアクセス権を設定しておく。設定しておかないとCloudWatchからLambdaを呼び出したときにCloudWatch Alarms is not authorized to perform: lambda:InvokeFunction on the resource because no resource-based policy allows the lambda:InvokeFunction action
ってエラーが発生する。
設定タブ内のアクセス権限を開いて、アクセス権限を追加をクリク

ステートメントIDは適当に入力して、プリンシパルはlambda.alarms.cloudwatch.amazonaws.com
だそうでアクションはlambda:InvokeFunction
を選択して保存する。

これでLambdaの設定は終わり。
CloudWatchの設定
CloudWatchから「すべてのアラーム」を開いて、「アラームの作成」をクリックする。

メトリクスと条件の指定で「メトリクスを選択」をクリックする。

メトリクスの選択で、「EC2」をクリックする。

「インスタンス別メトリクス」をクリックする。

検索欄に「CPUUtilization」(しーぴーゆーゆーてぃりぜいしょん)を入力しエンターを押すと、一覧が更新される。
※CPUUtilizationの最大値は100%×CPUコア数らしい。
監視したいEC2インスタンスを選択して「メトリクスの選択」をクリックする。

適当に入力して「次へ」をクリックする。ここでは5分間の平均値で80%以上の場合アラームを出すことにする。

アクションの設定でデフォルトで通知が設定されているが削除してLambdaアクションの追加をクリックする。先程作ったLambdaの関数を指定して「次へ」をクリックする。

アラーム名とアラームの説明を入力して「次へ」をクリックする。 ここで入力したアラーム名とアラームの説明は、Lambda関数でGoogleChatのメッセージで使用する。アラーム名は編集できないようなので注意する。

最終確認画面が出てくるので、「アラームの作成」をクリックする。

これでCloudWatchの瀬底は終わり。
動作確認
CloudShellで確認
CloudShellを起動する。画面上部の検索欄に「CloudShell」と入力して起動するのもよし、画面左下の「CloudShell」をクリックするもよし。


以下のコマンドを実行するとアラームが発生する。
aws cloudwatch set-alarm-state --alarm-name <<アラーム名>> --state-value ALARM --state-reason "test"
実行するとほーら、アラーム状態となった。

んで、GoogleChatにメッセージが飛んで、、、ない?あれ?
アラームの履歴を見てみると、正常に実行された模様。

Lambda側の実行ログは、CloudWatchのロググループから参照できる。 イベントの時刻があっているからこのログだと思うが、赤枠内リンクをクリックする。

正常終了しているっぽい、、、けど、Lambdaで最後にprintしているログが出力されていないからデプロイ押し忘れてたのか?

ソースが少し微妙だったから、修正した。
import json
import urllib.request
def lambda_handler(event, context):
print("#event")
print(json.dumps(event))
# message_detail = 'from aws lambda'
message_detail = event['alarmData']['alarmName']
message_detail += '\n'
message_detail += event['alarmData']['configuration']['description']
message = {'text': message_detail}
url = 'https://chat.googleapis.com/v1/spaces/AAAAR9eDSpo/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=iES37VFN5aidsn8NZM4JRZeZxQ2MxH4Qg1ncdFqf2Cg'
headers = {'Content-Type': 'application/json; charset=UTF-8'}
byte_encoded = json.dumps(message).encode('utf-8')
req = urllib.request.Request(
url=url
, data=byte_encoded
, headers=headers
)
response = urllib.request.urlopen(req)
print(response.read())
これで、GoogleChatにメッセージが送信された。

EC2で監視可能なメトリクスは以下に記載がある。https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/viewing_metrics_with_cloudwatch.html
ちなみにボリューム(SSD?HDD?)の残容量はCloudWatchで監視項目がないので仕組みが必要とか?
ストレスツールで確認
通知は送られるようになったけど、ホントにそんな状況になるのか不安。実際にサーバに負荷をかけてみる。
ストレスツールをインストール
$ sudo dnf install stress
CPU負荷をかける
$ stress -c 1
これでCPUが100%近くに張り付くので5分待機、、、無事にアラートメッセージが送信された。
コメント