CloudWatch からダウンロードした RDS インスタンスのメトリクスを、
Elasticsearch に突っ込んで、
Kibana のダッシュボードで可視化するところまではできた。
tnakamura.hatenablog.com
RDS インスタンスは今後増えていく予定で、
Kibana のダッシュボードは RDS インスタンスごとに分けたい。
RDS インスタンスが増えるたびに、Kibana をぽちぽち操作してダッシュボードを作るのは手間だな。
なんとか自動化できないものか調べていたら、
Kibana の設定は Elasticsearch の .kibana インデックスに保存されているみたいだった。
ダッシュボードは type = dashboard
に、
Visualization は type = visualization
に保存されていた。
ということは、ダッシュボードの JSON を .kibana インデックスにスクリプトで登録すれば、
動的にダッシュボードを追加できそうだ。
一から JSON を書くのは面倒なので、すでに作成したダッシュボードや Visualization もろもろの JSON
を Kibana からエクスポートし、加工してテンプレートにした。
かなり長いので、一部抜粋。
[
{
"_id": "${instance}",
"_type": "dashboard",
"_source": {
"title": "${instance}",
"hits": 0,
"description": "",
"panelsJSON": "[{\"col\":1,\"id\":\"${instance}-CPUUtilization\",\"panelIndex\":1,\"row\":1,\"size_x\":3,\"size_y\":2,\"type\":\"visualization\"},{\"col\":4,\"id\":\"${instance}-DatabaseConnections\",\"panelIndex\":2,\"row\":1,\"size_x\":3,\"size_y\":2,\"type\":\"visualization\"},{\"col\":7,\"id\":\"${instance}-FreeableMemory\",\"panelIndex\":3,\"row\":1,\"size_x\":3,\"size_y\":2,\"type\":\"visualization\"},{\"col\":10,\"id\":\"${instance}-DiskQueueDepth\",\"panelIndex\":4,\"row\":1,\"size_x\":3,\"size_y\":2,\"type\":\"visualization\"},{\"col\":1,\"id\":\"${instance}-FreeStorageSpace\",\"panelIndex\":5,\"row\":3,\"size_x\":3,\"size_y\":2,\"type\":\"visualization\"},{\"col\":4,\"id\":\"${instance}-ReadIOPS\",\"panelIndex\":6,\"row\":3,\"size_x\":3,\"size_y\":2,\"type\":\"visualization\"},{\"col\":7,\"id\":\"${instance}-WriteIOPS\",\"panelIndex\":7,\"row\":3,\"size_x\":3,\"size_y\":2,\"type\":\"visualization\"},{\"id\":\"${instance}-NetworkReceiveThroughput\",\"type\":\"visualization\",\"panelIndex\":8,\"size_x\":3,\"size_y\":2,\"col\":10,\"row\":3},{\"id\":\"${instance}-NetworkTransmitThroughput\",\"type\":\"visualization\",\"panelIndex\":9,\"size_x\":3,\"size_y\":2,\"col\":1,\"row\":5},{\"id\":\"${instance}-ReadLatency\",\"type\":\"visualization\",\"panelIndex\":10,\"size_x\":3,\"size_y\":2,\"col\":4,\"row\":5},{\"id\":\"${instance}-WriteLatency\",\"type\":\"visualization\",\"panelIndex\":11,\"size_x\":3,\"size_y\":2,\"col\":7,\"row\":5}]",
"optionsJSON": "{\"darkTheme\":true}",
"uiStateJSON": "{\"P-1\":{\"vis\":{\"legendOpen\":false}},\"P-2\":{\"vis\":{\"legendOpen\":false}},\"P-3\":{\"vis\":{\"legendOpen\":false}},\"P-4\":{\"vis\":{\"legendOpen\":false}},\"P-5\":{\"vis\":{\"legendOpen\":false}},\"P-7\":{\"vis\":{\"legendOpen\":false},\"spy\":{\"mode\":{\"name\":null,\"fill\":false}}},\"P-8\":{\"vis\":{\"legendOpen\":false}},\"P-11\":{\"vis\":{\"legendOpen\":false}},\"P-10\":{\"vis\":{\"legendOpen\":false}},\"P-9\":{\"vis\":{\"legendOpen\":false}},\"P-6\":{\"vis\":{\"legendOpen\":false}}}",
"version": 1,
"timeRestore": false,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"filter\":[{\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}}}]}"
}
}
},
]
このテンプレートからダッシュボードの JSON を出力する Python スクリプトを書いた。
import os
import sys
import codecs
from string import Template
TEMPLATE_FILE_NAME = "dashboard_template.json"
JSON_FILE_SUFFIX = "_dashboard.json"
class DashboardGenerator(object):
def _get_work_dir(self):
dir_path = os.path.abspath(os.path.dirname(__file__))
return dir_path
def _get_template_path(self):
dir_path = self._get_work_dir()
template_path = os.path.join(dir_path, TEMPLATE_FILE_NAME)
return template_path
def _get_template(self):
template_path = self._get_template_path()
with open(template_path, "r") as f:
template_text = f.read()
template = Template(template_text)
return template
def _generate_dashboard_json(self, rds_instance_name):
template = self._get_template()
json = template.substitute(instance=rds_instance_name)
return json
def _save_dashboard_json(self, rds_instance_name, json):
file_name = rds_instance_name + JSON_FILE_SUFFIX
dir_path = self._get_work_dir()
file_path = os.path.join(dir_path, file_name)
with codecs.open(file_path, "w", "utf-8") as f:
f.write(json)
def generate(self, rds_instance_name):
json_data = self._generate_dashboard_json(rds_instance_name)
self._save_dashboard_json(rds_instance_name, json_data)
if __name__ == "__main__":
generator = DashboardGenerator()
generator.generate("rds-0001")
出力した JSON を elasticsearch クライアントを使って .kibana インデックスに登録すれば、
ダッシュボードを追加できる。これも Python スクリプトを書いた。
import os
import sys
import json
from elasticsearch import Elasticsearch
class KibanaSetup(object):
def __init__(self):
self.es = Elasticsearch("localhost:9200")
def _get_work_dir(self):
dir_path = os.path.abspath(os.path.dirname(__file__))
return dir_path
def _get_dashboard_json_path(self, rds_instance_name):
work_dir = self._get_work_dir()
file_path = os.path.join(work_dir, rds_instance_name + "_dashboard.json")
return file_path
def _load_dashboard_json(self, rds_instance_name):
file_path = self._get_dashboard_json_path(rds_instance_name)
with open(file_path) as f:
json_data = json.load(f)
return json_data
def _post_object(self, obj):
self.es.index(index=".kibana", doc_type=obj["_type"], id=obj["_id"], body=obj["_source"])
def _create_dashboard(self, rds_instance_name):
json_data = self._load_dashboard_json(rds_instance_name)
for obj in json_data:
self._post_object(obj)
def setup(self, rds_instance_name):
self._create_dashboard(rds_instance_name)
if __name__ == "__main__":
app = KibanaSetup()
app.setup("rds-0001")
これでやりたいことはだいたい出来た。
ダッシュボードに Visualization を追加するときはテンプレートをいじる必要があって、
そこはまだ手間だけど当面は増やす予定ないからいいことにしよう。