AWS Lambdaで起動しっぱなしになっているEC2インスタンスを通知してくれるシステムを作る

作成: 2021年04月14日

更新: 2021年04月14日

概要

起動しっぱなしになっているEC2インスタンスを毎日20時にSlackにお知らせしてくれるシステムをAWS Lambdaで作成しました.

Slackでアプリの作成

  1. Slack API: Applications | Slackにアクセスし,Create New Appをクリック
  2. App Name,ワークスペースを入力
  3. Incoming Webhooksをクリック
  4. トグルをオンにし,Add New Webhook to Workspaceをクリックして投稿先のチャンネルを選び許可するをクリック
  5. curl -X POST -H 'Content-type: application/json' --data '{"text":"Hello, World!"}' https://hooks.slack.com/services/XXXXXXX/XXXXXXX/XXXXXXXをshellから入力して選択したチャンネルHello, World!と投稿されることを確認

ロールの作成

  1. IAM Management Consoleにアクセス
  2. 左メニューからロールをクリック
  3. ロールの作成をクリック
  4. エンティティの種類としてAWSサービスを選択し,ユースケースとしてLambdaを選択し,次のステップをクリック
  5. ポリシーにAWSLambdaBasicExecutionRole,AmazonEC2ReadOnlyAccessをアタッチし,次のステップをクリック
  6. 次のステップをクリック
  7. ロール名を入力し,ロールの作成をクリック

Lambda関数の作成

  1. Lambdaにアクセス
  2. 左メニューから関数をクリック
  3. 関数の作成をクリック
  4. 一から作成を選択
  5. 関数名を入力しランタイムはPython3.8を選択
  6. デフォルトの実行ロールの変更から既存のロールを使用するを選び,既存のロールで先ほど作成したロールを選択して関数の作成をクリック
  7. lambda_function.pyを以下のように変更 (urlのところはSlack API 作成時のURLに変更する必要があります)
import urllib3 
import json
import boto3

http = urllib3.PoolManager()
ec2 = boto3.client('ec2')
def lambda_handler(event,context):

    # running状態のインスタンスのインスタンスIDを取得し集合にする :➀
    no_tag = ec2.describe_instances(
        Filters=[{'Name':'instance-state-name','Values':['running']}]
        )
    no_tag_set = set(ec2['InstanceId'] for resId in no_tag['Reservations'] for ec2 in resId['Instances'])


    # 常時起動のタグがついたインスタンスIDを取得し集合にする:➁
    with_tag = ec2.describe_instances(
        Filters=[{'Name':'tag:status','Values': ['running']}]
        )
    with_tag_set = set(ec2['InstanceId'] for resId in with_tag['Reservations'] for ec2 in resId['Instances'])


    # running状態のインスタンスと常時起動タグつきインスタンスとの差集合演算を行う:➀ - ➁
    set_target_instances = no_tag_set - with_tag_set


    # 演算結果をリストにする
    list_target_instances = list(set_target_instances)


    # # 停止忘れ or 常時起動のタグつけ忘れがある場合はSNSで通知    
    if list_target_instances == []:
    # 停止忘れがない場合は何もしない
        pass
    else:
        # Slack API 作成時のURL を入力
        url = "https://hooks.slack.com/services/xxxxxxxxxxxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxx"
        instance_page_url = "https://ap-northeast-1.console.aws.amazon.com/ec2/v2/home?region=ap-northeast-1#Instances"
        alert_instances_msg = "\n".join(list_target_instances)
        msg = {"text": f"<!channel> EC2インスタンスを停止し忘れていませんか?確認しましょう!\n{instance_page_url}\n起動しているインスタンスのID一覧\n{alert_instances_msg}"}
        encoded_msg = json.dumps(msg).encode('utf-8')
        resp = http.request('POST', url, body=encoded_msg)
        print({
            "message": msg, 
            "status_code": resp.status, 
            "response": resp.data
        })
  1. 作成したAWS Lambda関数の設定からトリガーを追加をクリック
  2. トリガーにEventBridgeを選択
  3. 新規ルールの作成を選び,ルール名,ルールの説明を入力
  4. ルールタイプをスケジュール式にして,スケジュール式を入力(Rate または Cron を使用したスケジュール式 - AWS Lambda)UTC+0000であることに注意
  5. トリガーを追加をクリック

参考記事

SNSでSlackにメッセージ送信する #slack | DevelopersIO
AWS Lambdaを使ってEC2停止忘れを通知してみた | DevelopersIO