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では簡単にテストもできるし、利用できる言語も豊富なので、かなり使い勝手がよい印象でした。
今後も色々試してみたいと思います。
コメント