実現したかったこと
- 運用中サーバーの簡易監視として、定期的にHTTPアクセスを行い、結果を確認したい。
- サーバーレスで実行したい。
- 対象サーバーにアクセスするIPを制限しているため、監視元は固定IPの必要がある。
- 完全自動化し、監視結果だけが通知されて欲しい。
最終的に実現したこと
-
S3
に監視先サーバーデータを配置する。-
データの形式は以下の通り。
servers.json{ "servers": [ {"name": "Google", "url": "http://www.google.co.jp"}, {"name": "Yahoo", "url": "http://www.yahoo.co.jp"} ] }
-
-
AWS Lambda(Python)
から上記のデータを読み込み、各サーバーにHTTPアクセスを行う。 -
監視結果を
Slack
に通知する。 -
上記を、
CloudWatch Events - Schedule
で定期実行する。
設定詳細
VPC設定
- 実現したかったことが、以下で完全に網羅されていたため、参照。
IAM設定
-
Lambda
作成時に、roleのtemplateとして、Simple Microservice permissions
を選択。 -
S3
にアクセスするため、AmazonS3ReadOnlyAccess
のポリシーをアタッチ。 -
Lambda
をVPC
上で実行するため、AWSLambdaVPCAccessExecutionRole
のポリシーをアタッチ。
CloudWatch Events - Schedule設定
Slack
-
Incoming Webhooksを参照して、
Slack
への通知用URLを取得。
AWS Lambda(Python)
- エラーハンドリング周りは改善の余地あり。
lambda_function.py
import json
import requests
import boto3
BUCKET_NAME = 'xxxxxxxxxx'
OBJECT_NAME = 'xxxxxxxxxx/servers.json'
SLACK_POST_URL = 'https://hooks.slack.com/services/xxxxxxxxxx/xxxxxxxxxx/xxxxxxxxxxxxxxxxxxxx'
def lambda_handler(event, context):
json_data = __getServers()
__check_server(json_data)
def __getServers():
s3 = boto3.resource('s3')
obj = s3.Object(BUCKET_NAME, OBJECT_NAME)
response = obj.get()
body = response['Body'].read()
return body.decode('utf-8')
def __check_server(json_data):
data = json.loads(json_data)
servers = data['servers']
has_error = False
for server in servers:
name = server['name']
url = server['url']
print("Check: " + name)
try:
r = requests.get(url)
if r.status_code != 200:
__send_error_message(name, url)
has_error = True
except requests.exceptions.RequestException as e:
__send_request_error_message(name, url)
has_error = True
if has_error == False:
__send_success_message()
def __send_error_message(name, url):
payload = {
"text": name + '\n' + url + '\n' + '*ERROR!*',
"icon_emoji": ":x:"
}
__send_message(payload)
def __send_request_error_message(name, url):
payload = {
"text": name + '\n' + url + '\n' + '*Request Error!*',
"icon_emoji": ":warning:"
}
__send_message(payload)
def __send_success_message():
payload = {
"text": "All Servers OK!",
"icon_emoji": ":o:"
}
__send_message(payload)
def __send_message(payload):
try:
return requests.post(SLACK_POST_URL, json=payload)
except requests.exceptions.RequestException as e:
return None
AWS Lambda(Python)設定時の注意点
- ライブラリはソースコードと同じディレクトリに配置する。
pip install requests -t .
- ソースコードとライブラリをまとめて、zipにして配置する。
zip -r lambda_function.zip *
雑感
-
AWS Lambda
にVPCを設定できるようになったことで、データ送信元を固定IPアドレスにしてLambdaを実行できるようになったため、使いどころが広がった。 - 手軽な通知先として、
Slack
との連携が簡単で便利すぎ。 - servers.jsonの中身をbodyに詰めた、HTTP POST通信をトリガーに、
API Gateway
経由で実行させる方法も試したが、最終的に定期実行がラクな現在の形とした。