Lambdaを使用してCloudWatchアラームをLINE Notifyで通知してみる

#ご挨拶
AWS Advent Calendar 2021の16日目の記事になります！
今回はLambdaを使用してLINEにCloudWatchからのアラームを送信したのでその時の知識のまとめです。
#やること
今回のメインはLambdaになります。
Pythonを使用してLambda関数を作成しました。
SNSのサブスクリプションにLambdaを選択してそのSNSをCloudWatchアラームの通知送信先に選択することでLINEに送信できるようにしました。
言葉だけだと理解しにくいので構成図を作成しました。
###構成図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/6d19a780-2b33-d138-0033-fac1ce8ad412.png)

#Lambdaの設定やLINE Notifyの設定、コードを参考にさせていただいたサイト
[LambdaでLine Notifyを使って予定通知をやってみた](https://dev.classmethod.jp/articles/tried-using-line-notify-with-lambda-to-notify-the-appointment/)
[CloudWatchアラームをLINEに投げてみた](https://raptor-falcon.hatenablog.com/entry/2017/09/04/053119)
[Python + AWS Lambda + Line Notify で自動で毎朝Lineに本日のお天気を通知してみた。](https://qiita.com/tan5o/items/6c5f2bd6f3f29b1ae465)
[LINE Notify API Document](https://notify-bot.line.me/doc/ja/)
[requestsのドキュメント](https://requests-docs-ja.readthedocs.io/en/latest/api/)
#Lambda関数
今回作成したLambda関数になります。

```python:lambda_function.py
import os
import requests
import json

token = os.environ['TOKEN_KEY']
url = os.environ['URL']
headers = {'Authorization':f'Bearer {token}'}

def lambda_handler(event, context):
    Message = json.loads(event['Records'][0]['Sns']['Message'])
    AlarmName = Message['AlarmName']
    NewStateValue = Message['NewStateValue']
    Instance = Message['Trigger']['Dimensions'][0]['value']
    NewStateReason = Message['NewStateReason']
    
    if NewStateValue == 'ALARM':
        data = {'message': f'\nアラーム名：{AlarmName}\
                \nステータス：{NewStateValue}\
                \nインスタンス：{Instance}\
                \n理由：{NewStateReason}',
                'stickerPackageId':789,
                'stickerId':10860}
        requests.post(url=url, data=data, headers=headers)
    elif NewStateValue == 'OK':
        data = {'message': f'\nアラーム名：{AlarmName}\
                \nステータス：{NewStateValue}\
                \nインスタンス：{Instance}\
                \n理由：{NewStateReason}',
                'stickerPackageId':789,
                'stickerId':10858}
        requests.post(url=url, data=data, headers=headers)
```
[SNS メッセージイベント](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-sns.html)
json.loadsでMessageをjsonオブジェクトに戻しています。
evetnの中身からLINEに送るメッセージを作成しています。
アラーム時とOK時で送るスタンプを変更することでどちらのメッセージなのか判断できるようにしています。

#LINE Notifyの設定
[LINE Notify](https://notify-bot.line.me/ja/)に自分のLINEアカウントでログイン
ログインしたら右上のアカウント名をクリックしてマイページを選択します。
![スクリーンショット 2021-11-13 180256.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/eafa558f-91ce-31c6-0409-d44b930cc67a.png)
ページを移動したらトークンを発行するをクリックしてトークン名と通知する先を選択します。
今回は自分だけに通知するので1:1でLINE Notifyから通知を受け取るを選択しました。
トークンキーを発行したらメモしておきます。
![スクリーンショット 2021-11-13 181611.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/68f136ab-178b-f344-04a3-8b4f8e81291b.png)
トークンキーが発行出来たらcurlコマンドで送信できるか試してみる

```text:WSL2
curl -X POST -H "Authorization: Bearer 発行したトークンキー" -F "message=テスト送信" https://notify-api.line.me/api/notify
```
成功すると自分のLINEに-F "message=テスト送信"で記載したメッセージが届きます。
#必要なモジュールのインストールとLambda関数の設定
Lambda関数の設定方法は以前書いた記事をご覧ください。[LambdaからRDSへ接続してみる](https://qiita.com/Mattun_0226/items/d8f97c652873d80b1367)
今回は上記の記事とは違うところだけを記載します。
上記の記事は必要なモジュールをLambdaのコードと一緒にアップロードしていましたが、レイヤーという機能を使用することがベストプラクティスのようなので今回はレイヤーを作成します。
##モジュールインストール
以下のコマンドを実行してpythonディレクトリを作成してrequestsをインストールしてください

```text:PowerShell
mkdir python
cd python
pip install -t ./ requests
```
作成したらpythonディレクトリをzipにします。
zipファイル名は任意のもので大丈夫です。
今回はreq.zipにしました。
##レイヤー作成
[レイヤー作成方法](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-layers.html)
AWSマネジメントコンソールからLambda→レイヤー→レイヤーの作成の順で進んでください
進むと以下の画面が出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/7f7b4909-9b32-78cc-528f-5b17951211e5.png)
レイヤーの名前を入力したらアップロードをクリックして上記で作成したzipをアップロードします。
互換性のあるアーキテクチャはオプションなので今回は選択しません。
互換性のあるランタイムはpython3.9を選択します。
選択したら作成をクリックします。
作成したらLambda関数→コード→レイヤー→レイヤーの追加をクリックします。
画面を下にスクロールするとあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/a83c71ad-f855-70ad-262c-96e1a3af0317.png)
レイヤーの追加をクリックしたらレイヤーを選択の部分でカスタムレイヤーを選択、カスタムレイヤーで上記で作成したレイヤーを選択します。
選択したら追加をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/db53fb3e-7278-b59f-2983-4c9a1b0b6072.png)
追加すると以下の画像のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/8bb35354-ee43-41ae-2cda-32dd2d612455.png)
ここまで完了したらコードのところに以下のコードを張り付けてテスト送信をしてみます。
TOKEN_KEYは環境変数から取ってきています。LINE Notifyの設定をしたときにメモをしたトークンキーを設定してください。
URLはhttps://notify-api.line.me/api/notify を環境変数に設定しています。

```python:テスト送信用
import os
import requests

token = os.environ['TOKEN_KEY']
url = os.environ['URL']
headers = {'Authorization':f'Bearer {token}'}

def lambda_handler(event, context):
    data = {'message': 'test送信'}
    requests.post(url=url, data=data, headers=headers)
```
テスト送信が成功するとLINEにメッセージが届きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/9e1b21c8-c835-cef8-fd26-f433bb7ac071.png)
メッセージが届いたらとりあえずLINE NotifyとLambdaの設定は完了です。
コードをlambda_function.pyに戻してCloudWatchアラームとSNSの設定を行います。
#CloudWatchアラームとSNSの設定
アラームはEC2インスタンスのCPU使用率が70%を超えたら通知するように設定します。
##SNSの設定
マネジメントコンソールからSNSのダッシュボードに移動します。
移動したら画面左にあるトピックをクリックしてトピックを作成します。
![スクリーンショット 2021-12-12 164926.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/5d8c15b6-5492-1cb5-e592-5c6b4a3f23c5.png)
以下の画面を開いたら「タイプ」を選択して「名前」を入力します。
「タイプ」はサブスクリプションとしてLambdaを使うのでスタンダードを選択します。
「名前」は任意の物で大丈夫です。
他の設定はデフォルトのまま作成をします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/1bf448d1-0596-a745-77e7-e27573f698ec.png)
作成ができたらサブスクリプションの作成を行います。
以下の画面からサブスクリプションの作成をクリックします。
![スクリーンショット 2021-12-12 165623.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/23910d52-405d-9872-4bf5-c18712d26ec6.png)
サブスクリプションの設定画面では「プロトコル」にAWS Lambdaを選択してエンドポイントにLambda関数のARNを入力します。
入力したらサブスクリプションの作成をクリックして作成します。
![スクリーンショット 2021-12-12 165844.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/86a5d8bf-b519-104e-094f-f6256f7b5b07.png)
##CloudWatchアラームの設定
マネジメントコンソールからCloudWatchのダッシュボードに移動します。
CloudWatchのダッシュボードからすべてのメトリクスに移動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/91edd1b7-8f8d-62ad-0d77-de1755216ea2.png)
移動するとメトリクスが選択できるのでEC2→インスタンスメトリクス→アラームを設定したいインスタンスのCPUUtilizationにチェックを入れます。
チェックを入れた後、グラフ化したメトリクスに移動してアクションにあるベルのマークをクリックします。
![スクリーンショット 2021-12-12 170736.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/db78c41c-15dc-76f8-b4ca-30c23decd1fa.png)
ベルのマークをクリックするとアラーム作成画面が開きます。
設定画面を開いたら条件を以下のように設定します。
設定したら次へをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/cde28df4-e33f-4ab2-bea4-8bdc480b7b5b.png)
次の画面では通知の設定を行います。
通知はアラーム状態の時とOK状態になったときにLINEに通知できるように二つ設定を行います。
「アラーム状態トリガー」でアラーム状態を選択
「SNSトピックの選択」で既存のSNSトピックを選択
「通知の送信先」で上記手順で作成したSNSトピックを選択
通知の追加をクリックするともう一つ作れるのでOK状態も同じように作成します。
設定ができたら次へをクリックします。
![スクリーンショット 2021-12-12 171215.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/0ca126a8-8647-4756-370e-cfa85509a3cc.png)
次の画面ではアラーム名を入力して次へをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/03ada4af-5092-dd65-61be-d8601c527c72.png)
次の画面は確認画面なので問題が無ければアラームの作成をクリックします。
#動作確認
上記の設定まで完了するとLINEにOK通知が飛んでくると思います。
アラーム時の動作も確認したいと思います。
確認方法はAWS CLIでCloudWatchアラームのステータスをアラームに変更するか、実際にEC2インスタンスのCPU負荷を上げる方法があります。
今回は両方ともやってみます。
[set-alarm-state](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudwatch/set-alarm-state.html)
以下のコマンドを実行します。

```text:CloudShell
aws cloudwatch set-alarm-state --alarm-name アラーム名 --state-value ALARM --state-reason "test run"
```
成功すると以下のようにメッセージとスタンプが送られてきます。
![スクリーンショット 2021-12-12 184336.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/28a50c28-1a79-3893-3dd7-8ea28626af04.png)
次はEC2インスタンスに負荷をかけてみます。
EC2インスタンスに接続して以下のコマンドを10回くらい実行します。
jobsで確認するとこんな感じになってます。

```text:EC2
yes > /dev/null &

jobs
[1]   Running                 yes > /dev/null &
[2]   Running                 yes > /dev/null &
[3]   Running                 yes > /dev/null &
[4]   Running                 yes > /dev/null &
[5]   Running                 yes > /dev/null &
[6]   Running                 yes > /dev/null &
[7]   Running                 yes > /dev/null &
[8]   Running                 yes > /dev/null &
[9]   Running                 yes > /dev/null &
[10]   Running                 yes > /dev/null &
[11]-  Running                 yes > /dev/null &
[12]+  Running                 yes > /dev/null &
```
アラームになると以下の画像のように理由に詳細なメッセージが入って送られてきます。
![スクリーンショット 2021-12-12 185801.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/115d0091-39e2-74e1-1e14-e7c9622c072d.png)


#感想
かなり簡単なコードと構成ですがLambdaの使い方の基礎的な部分は学べる内容だったかなと思います。
LINE Notifyはメッセージの文字の色が変えられないらしく、そこが変えられればスタンプを送らないでも良いと思いました。
業務でもLambdaを使用する機会が増えてきているので今後も学習を続けていこうと思います。