こんにちは、MS課OJT中の峯です。 Amazon CognitoとFacebookとの連携を書いたときは技術4課でOJT中でしたが、今はMS課でOJT中です。今回はQuickSightを使ったZabbixのアラートを見える化について書きたいと思います。
なぜこんなことをしたか?
MS課にてOJTの研修課題でZabbixサーバーに自分自身を監視させるというのをやっていました。
先輩から
「アラートをAthenaとかQuickSightとかでいい感じにして、いつどんなアラートがあがってるかとかどのホストグループからあがってるかとか分析したいんだよね」
ってことでこの要件のざっくりとした検証?お試し?を私がやることになりました。
実際やってみた
構成
課題を進めていた検証用の環境ではSESを使い、ZabbixのアラートメールがS3バケットに保存され、メールの本文はbase64でエンコードされていました。Athenaでのテーブル作成のためにメールをデコードし、なんとかJSONファイルにしなければなりません。というわけで以下のような構成になりました。
- ZabbixサーバーからのアラートメールがS3バケットに保存されます。
- ↑をトリガーにしてLambdaを発火。保存されたメールの本文をbase64デコードします。そして必要な情報を抜き取り、それらを書き込んだJSONファイルを別のS3バケットに保存します。
- GlueのクローラーをつかってAthenaに自動でテーブル作成・更新します。
- QuickSightで見える化!!!
Glue、Athena、QuickSightについては利用できるリージョンが限られています(2018/2/現在)。今回はそれぞれバージニア北部で利用しました。
手順
Zabbixの設定
設定というか、アクションにてメールのデフォルトメッセージを以下のようにします。
次のLambdaはこのテンプレを想定して作ってあります。
Lambdaの作成
Lambdaを作成していきます。今回はpython3.6でコードを書きます。s3-get-object-python3というテンプレがあるのでそれを使用します。
書いたコードは以下になります。
import json
import urllib.parse
import base64
import boto3
import uuid
s3 = boto3.resource('s3')
s3client = boto3.client("s3")
jsons_bucket_name = "JSON保存用バケット名"
#アラートメールから開始と終点を指定して文字列を取ってきます。
def get_alert_info(alert, startWord, endWord):
alert_info = alert.split(startWord)[1].split(endWord)[0]
return alert_info
#jsonファイルに保存する辞書もしくはcsvファイルに保存するリストを作成します。
def make_alert_info(mails_bucket_name, mail_key):
mail = s3client.get_object(Bucket=mails_bucket_name, Key=mail_key)
alert = mail['Body'].read()
alert = alert.decode("utf8").replace('\n','').replace('\r','')
from_address = get_alert_info(alert, "From: <", ">")
to_address = get_alert_info(alert, "To: <", ">")
subject = get_alert_info(alert, "Subject: ", "MIME-Version")
body = base64.b64decode(alert.split('AmazonSES')[1])
body = body.decode("utf8").replace('\n','').replace('\r','')
host_group = get_alert_info(body, "Host group: ", "Host: ")
host_name = get_alert_info(body, "Host: ", "Date:")
row_datetime = get_alert_info(body, "Date:", "Trigger: ")
datetime = row_datetime.replace(" , ", " ")
triger_name = get_alert_info(body, "Trigger: ", "Trigger status: ")
triger_status = get_alert_info(body, "Trigger status: ", "Trigger URL:")
alert_info_json = {
"HostGroup":host_group,
"HostName":host_name,
"Datetime":datetime,
"TriggerName":triger_name,
"TriggerStatus":triger_status
}
return alert_info_json
#辞書をjsonファイルに書き込みます
def write_json(alert_info_json, json_path):
with open(json_path, "w") as file:
json.dump(alert_info_json, file)
#実行します。
def lambda_handler(event, context):
json_key = str(uuid.uuid4()) + ".json" #uuidで被らないファイル名にします
json_path = "/tmp/" + json_key #一時ファイルのパス
mails_bucket_name = event['Records'][0]['s3']['bucket']['name'] #eventからバケット名を取ってきます
mail_key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8') #バケットにアップロードしたオブジェクトのキーを取ってきす
alert_info_json = make_alert_info(mails_bucket_name, mail_key) #json用辞書作成
write_json(alert_info_json, json_path) #json書き込み
s3client.put_object(Bucket=jsons_bucket_name, Key=json_key) #json用バケットにアップロードします
メール保存用のS3バケットにアップロードされたオブジェクトからsplit関数を使い、メール本文、さらにその中から必要なものを取り出します(こちらのブログを参考にしました)。取り出したものをJSONファイルに書き込みJSON保存用のS3バケットに保存します。 ロールのポリシーにはCloudWatch Logsの書き込み権限だけでなく、メール保存用S3バケットのオブジェクト読み取り権限(GetObject)、JSON保存用S3バケットのオブジェクト書き込み権限(PutObject)を追加しておきます。(ビジュアルエディタのおかげでポリシーの編集がだいぶ楽になりました)。
AthenaとGlueの設定
続いてGlueをつかってデータベースとテーブルを作成します。
マネコンからデータベースを作成します。
クローラーを作成します。
クローラーの名前を入力します。
S3バケットを選択します。パスは最後にスラッシュを入れてください。
ロールを作成します。
スケジュールを設定します。今回は「Run on demand」です。
先ほど作成したデータベースを選択します。
Glueの設定はOKです。ではAthenaを確認してみましょう。 データベースとテーブルが作成されてることがわかります。
ちなみにクエリを投げるとこんな感じ。
QuickSightの設定
さて、いよいよQuickSightの設定です。といっても、とくに難しいことはないです。はじめて利用する場合はプランを選んでサインアップする必要があります。私はスタンダードにしました。あまり覚えてないですが、以下の作業はサインアップするときにやらないといけないはずです。。。
パーミッションの設定
まずはパーミッションの設定です。右上のユーザーのアイコンから「Manage QuickSight」を開きます。
Account Settingからパーミッションの設定をします。Athenaだけでなく、JSONを置いているS3バケットへのパーミッションも許可しないといけません。
もとの画面に戻り、New analyticsから見える化していきます。
New DatasetからAthenaを選択し、先ほど作成したもので設定していきます。
データソース名を決めて、「Validate connection」をクリックし、接続が検証されれば「Validated」になります。
Athenaで作成したデータベースとテーブルを選択します。
SPICEにインポートするか直接クエリを投げるか選択します。今回は「Directly query your data」にします。SPICEについてはこちら
見える化
では、どう見える化されたでしょうか。
おや?微妙なグラフが表示されました。表示されない場合はフィールドをいろいろ選択してみてください。QuickSightではグラフのことをビジュアルと呼びます。ビジュアルは数種類用意されていますが、今回は画像の赤丸で囲ったものを使用します。
上のビジュアルを選択し、Field wellsからx軸とグループに表示するフィールドを選択します。今回はx軸にdatetime、グループはtrigernameにします。実際に表示されたビジュアルがこちら
なんだかまだ微妙だ... そもそもアラートの量がすくないのもあるが... ここからはこのビジュアルをもうちょっといい感じにしていきます。
ビジュアルをいい感じにする
Calculatedフィールド
x軸に設定したdatetimeフィールドが文字列型のままなので、これを日付型にして、さらに年・月・日のフィールドを作成します。データセットの編集画面を開きます。
datetimeフィールドの型が「String」となっていますが、「Date」を選択します。
「Date」を選択すると、年月日がもとの文字列でどう並んでいる入力します。
これでdatetimeフィールドが日付になりました。次はコレをもとにして、年・月・日のCalculatedフィールドを作成していきます。FieldsのNew Fieldsから作成します。
フィールド名はそれぞれDay、Month、Yearとします。Formula欄には関数を入力します。truncDate関数を使用します。年月日が日付型で返されます。後述しますが、ビジュアルの表示を設定しなおす必要があります。似たような関数にextract関数がありますがこちらは数値型が返されます。
これで年月日それぞれのフィールドが作成されました。ビジュアルの画面に戻り、x軸を「Day」にすると下のようになります
x軸の表示の設定を変えます。「Day」フィールドは日付まで、「Month」フィールドは月まで、「Year」フィールドは年まで見えるようにします。またソートを昇順にします。下の画像は「Day」の設定例です。
フィルター
これでx軸の日付はいい感じになりました。次はフィルターを設定します。フィルターのタブからフィルターを作成します。
tirggerstatusがPROBLEMのもののみを表示するフィルターをつくります。
hostgroupとかhostnameとかのフィルターも作っても作りましたが、今回は検証ということもあり、データが少ないので必要はなさそう... これでだいたいいい感じになりました。
まとめ
いかがでしたでしょうか。今回は研修で使用したZabbixであったため、アラートの量も少なく、日によってどのアラートが何個とんでいるかがわかるくらいで、見える化する意味はあまりありませんでした。何をどう見たいかにもよると思いますが、どのホストグループ・ホストからいつにどんなアラートが飛びやすくなっているかという分析も可能かもしれません。