AWS EC2 のインスタンスで毎日cronのバッチが実行されているが、そのログを監視して、「毎日正常にバッチが動いている」かを確認することになりました。
そこで、今回やるのは、
Lambdaを定期実行 → EC2のcronログをtail → 結果をTeamsに投稿
になります。図で表すと以下の通りです。

今回作るもの
今回必要となるのは、以下の通りです。
- AWS Lambda
 - Python
lambda_function.py ・・・Lambdaで実行されるメインプログラム。
send_teams.py ・・・lambda_function.pyで呼ばれる。Teamsに投稿するプログラム - Event Bridge(Cloud Watch Events)
 
AWS Lambda
まずは、Lambdaの設定を行っていきます。
AWS Lambda > 関数 の右上にある、関数作成を押下します。


一から作成を選択したまま、
 ・関数名
 ・ランタイム(今回は、Pythonにしました。)
を設定します。設定が終わったら関数の作成ボタンを押します。

Pythonプログラムの作成
Lambda関数の作成が終わったら、Pythonプログラムを書いていきます。
コードタブに「lambda_function.py」が自動作成されているので、ここにメインプログラムを記載していきます。
【自動作成後の画面】

今回は、Teamsに投稿するプログラムを別途用意するので、コードソース下のタブにある File > New File でsend_teams.pyファイルを作成します。
各ソースの中身は、以下の通りです。
lambda_function.py
import json
import urllib.request
import boto3
import send_teams as st
import datetime
import dateutil.parser
import time
def lambda_handler(event, context):
    jst_datetime = datetime.datetime.now()
    
    command = "grep mailbatch.sh /var/log/cron | tail -20"
    instance_id = "xxxxxxxxxxxxxxxxxxx"
    ssm = boto3.client('ssm', region_name='ap-northeast-1')
    retry = 3
    
    # 最大でリトライ回数までコマンドを実行
    for i in range(1,retry):
    
        # コマンド実行
        r = ssm.send_command(
            InstanceIds = [instance_id],
            DocumentName = "AWS-RunShellScript",
            Parameters = {
                "commands": [
                command
                ]    
            }
        )
        command_id = r['Command']['CommandId']
        
        # 処理終了待ち
        time.sleep(3)
        
        # 結果取得
        res = ssm.list_command_invocations(
              CommandId = command_id,
              Details = True
            )
        invocations = res['CommandInvocations']
        status = invocations[0]['Status']
            
        # ステータスが"Success"の場合
        if status == "Success":
            # 処理を抜ける
            break
    
    # ステータスが"Success"の場合
    if status == "Success":
        # コマンドの実行結果部分を取得
        description = invocations[0]['CommandPlugins'][0]['Output']
    
        # 改行を<br>タグに変換
        description = description.replace('\n','<br>')
    
        # Teamsに投げるメッセージを作成
        message='<table><tr><th>取得日時</th> <th align="left">{}</th></tr><tr><th>内容</th><th align="left"><font size="1">{}</font></th></tr></table>'.format(jst_datetime.strftime("%Y/%m/%d %H:%M:%S"),description)  
        
    # ステータスが"Success"以外の場合
    else:
        message='<table><tr><th>取得日時</th> <th align="left">{}</th></tr><tr><th>内容</th><th align="left"><font size="1">{}</font></th></tr></table>'.format(jst_datetime.strftime("%Y/%m/%d %H:%M:%S"),"Lambda取得エラー ステータス=" + status)    
    # Teamsに投げるタイトルの設定
    title="バッチ稼働状況通知"
    # Teamsに送信
    st.send(title,message)
    #print(message)
    
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }send_teams.py
import os
import urllib.request
import json
def send(title,message):
    send_data = {"title":title,"text": message}
    send_text = "payload=" + json.dumps(send_data)
    send_text =  json.dumps(send_data)
    request = urllib.request.Request(
        os.environ["NOTIFICATION_TARGET"], 
        data=send_text.encode("utf-8"),
        method="POST"
    )
    urllib.request.urlopen(request)
【プログラム修正後の画面】

Lambdaの設定
環境変数の設定で、Teamsの「Incoming Webhook」のURLを設定します。
まず、URLを取得しましょう。
Teamsのチャネルで左クリック > コネクタ > Incoming Webhook
でWebhookを作成します。
[Teams]


次に、WebhookでURLをコピーできたら、Lambdaの環境変数「NOTIFICATION_TARGET」に設定します。
[Lambda]

アクセス制限
LambdaとEC2でアクセスの許可がそれぞれ必要になります。
Lambda側
- AmazonEC2ReadOnlyAccess
 - AmazonSSMFullAccess
 
EC2側
- AmazonSSMManagedInstanceCore
 
トリガの設定(Event Bridge)
トリガーでLambdaの起動タイミングを設定します。
今回は、Event Bridgeで3時間おきに起動するようにしました。
Lambdaの画面で「トリガーを追加」から設定できます。

スケジュール式は、cron式で設定しました。ポイントは以下になります。
- 左から[分] [時] [日] [月] [曜日] [年] 6つの必須フィールド。
 - / は、○○毎。
⇒今回は、3時間毎に動かしたいので、*/3。 - 日フィールド及び曜日フィールドを同時に指定することはできない。
一方のフィールドに値を指定すると、もう一方のフィールドで ? (疑問符) を使用する必要がある。
⇒毎日実行させたいので、日を*、もう一方を?にします。 
稼働確認
設定が完了したら、3時間おきに稼働状況がTeamsに投稿されるはずです。

まとめ
今回は、LambdaでEC2のcronログを参照して、稼働確認をやってみました。これまでAWSに触れることがなかったので、Lambdaを作ってみて色々使っていく中で理解が深まりました。
Lambdaでは簡単にテストもできるし、利用できる言語も豊富なので、かなり使い勝手がよい印象でした。
今後も色々試してみたいと思います。
  
  
  
  

コメント