CloudWatchアラームとSNSトピックによるRekognition推論モデルの自動停止とメール通知

- KDDI Engineer & Designer Advent Calendar 2023 Day 8 を担当します、4日間連続でカレー食べれるくらいカレー好き男です。（ Coco壱の肉塊カレー最高に美味い・・
- はい、KAGのアドベントカレンダー4日目に引き続き、今回はKDDI本体の方のアドベントカレンダーの記事を書いていきます。
- AWS Rekognitionで作成した推論モデルの停止忘れによる課金発生に怯えて、夜しか眠れないので、それを自動で阻止するシステムを構築したので紹介します。

## 目次
- 1.どんなシステム？
- 2.背景
- 3.構築手順
- 4.ソースコード
- 5.おわりに

## 1.どんなシステム？
#### 何するもの？
##### Rekognitionとは
まず、軽くRekognitionとは何か説明しますが、AWSには、画像認識などの機械学習を簡単に実現できるサービスとして、Rekognitionが提供されています。

https://aws.amazon.com/jp/rekognition/

このRekognitionは、推論モデルを作成するために画像をinputしてカスタムラベル(識別子)を付与して、モデルのトレーニングを行います。推論モデルが出来上がったら、モデルを起動することで使用可能となり、画像を読み込ませて、例えば犬の画像を読み込ませたら、これは犬です、と判別してくれると言ったものになります。

##### システム概要
こちらの推論モデルは起動してから停止するまでに課金が発生するので、CloudWatchで推論モデルが起動していることを示すメトリクスを監視して、一定時間以上起動していたらアラームを発火させます。そしてアラームが発火したらSNSと連携し、SNSトピックから管理者にメール通知を行い、かつ、Lambdaで停止処理をトリガーします。停止処理を実行したら再度、SNSトピックを用いてユーザに、今度は停止した旨を通知するといった流れになっています。

#### アーキテクチャ
以下のような構成になっています。
![aws](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754596/8c8ff85a-9835-3220-d289-d5cd4721b1ef.png)



## 2.背景
私は、Webポータルサイトの開発を行いながら、別の案件でこのRekognitionを用いた画像認識システムの開発をしているのですが、テストでRekognition推論モデルを利用したあとに、停止したかどうか気になって、マネージメントコンソールに確認しにいくという行動を度々とっていました。あれ、家の鍵閉めたよな、、？的なアレです。なので、自動で停止できるようにしてしまえばいいじゃんっ♪と考えたわけです。

現在は、起動時間が閾値を超えたタイミングと、自動で推論モデルの停止をしたときにメールが届くようになっています。

- 起動時間が閾値を超えたことを検知したときの通知
![通知.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754596/24eedfcc-f074-41cc-2d63-c3a051f3d977.png)


- 推論モデルの停止処理をしたときの通知
![停止.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754596/00256b07-1df1-cfec-30df-68759e0ab1ed.png)



## 3.構築手順
マネージメントコンソールのスクショを赤枠線などで指示はしません、掻い摘まんで構築手順を説明していきます。
#### 前提条件
Rekognitionの推論モデルが存在すること

#### 手順
１：CloudWatchアラームを設定
Rekognition推論モデルの実行は、InServiceInferenceUnitsメトリクスにより検知できます。
なので、こいつを監視してあげますが、単にエラーになった時だけを監視しようとすると、以下の記述にあるように、アラーム状態になったまましばらくステータスが正常に戻らないという現象が起きます。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarms-evaluating-missing-data

なので、以下のように、データ欠落時に評価を引き延ばす動きを回避してあげます。
具体的には、CloudWatchのアラームから数式を追加し、FILL関数を適用することでデータポイントが欠落している箇所を”0”として補完してあげます。これによって、データが欠落する部分を0、つまりエラーではないと認識させます。そのため、評価期間が過ぎたときにアラームは正常の状態に遷移させることができます（戻す）。
![cloudwatch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754596/e8c89f88-ae29-5ea2-dc6f-4e200d8fdb0d.png)

なお、アラームを飛ばすための閾値となる時間は、初めはテストのために5分など短い数字にしましょう。

２：SNSトピックを設定
次にAmazon SNSでトピックを作成し、アラーム通知をトリガーに指定したメールアドレスに通知を飛ばすようにします。
SNSのトピックにCloudWatchのアラームのarnを指定し、また、通知を転送したいメールアドレスを設定することで、アラームが出たときにSNSがそれをサブスクリプションして指定したメールアドレスに通知を飛ばすことができます。

３：Lambdaを作成
つづいて、Rekognition推論モデルの停止処理をLambdaから実行するためにLambdaを作成したあと、Lambdaのarnを先ほど作成したトピックのサブスクリプションに指定してあげます。
また、Lambdaの発火だけではなく、停止したことを指定したメールアドレスに飛ばすためのSNSの指定をしてあげます。こちらは新しくトピックを作成して、手順2同様にメールアドレスをサブスクリプションに設定してあげます。
また、lambdaにsnsとRekognitionを触るための権限を付与することも忘れないようにしましょう。権限を付与し忘れると無条件にLambdaの処理は失敗します。
なお、Lambdaのソースコードは次の章に示します。

４：動作確認
ここまできたら、後は動作確認のみです。マネコンからRekognitionに移動し、お使いのプロジェクトから推論モデルを起動してしばらく待ちましょう。ここまでの手順が正しく設定できていれば、モデルが起動してから5分(設定した時間)ほど経つと、閾値超過メールが届いて、Rekognitionモデルが停止し、停止メールが届くはずです。なお、実際に推論モデルが停止しているかはマネコンから確認してみましょう(初回だけ確認すればokです)。実行マークが消えて、開始ボタンが活性化しているかと思います。（停止している証拠）

これで、完成です。

## 4.ソースコード
```python:Lambda_function.py
import boto3
import json

sns_client = boto3.client('sns')

def send_sns():
    # SNSトピックARNを指定
    sns_topic_arn = 'XXXX'
    # メールの送信情報を設定
    message = {
        'Subject': 'Rekognitionモデルを停止しました。',
        'Message': '5分以上、Rekognitionの推論モデルが起動したままの状態であることを検知したので停止しました。'
    }
    # SNSトピックにメッセージを送信
    response = sns_client.publish(
        TopicArn=sns_topic_arn,
        Message=json.dumps(message, ensure_ascii=False)
    )
    print('SNS Publish Response:', response)
    return {
        'statusCode': 200,
        'body': json.dumps('メール送信リクエストが送信されました。')
    }

def lambda_handler(event, context):
    client = boto3.client('rekognition')
    #RekognitionのプロジェクトARNを指定
    project_version_arn = 'XXXX'
    response = client.stop_project_version(ProjectVersionArn=project_version_arn)
    send_sns()
    return response
    
```

## 5.おわりに
- 今回はCloudWatchアラームでのメトリクス監視を起因として課金が発生しないようにする仕組みを作りました。
- これで推論モデルを使用したあと、1度閉じたマネコンを再び開くといったことがなくなりました。
- さあ、次はKAGのアドベントカレンダー20日目でお会いしましょう。Catch you later.