Blogブログ

Cloudwatchの情報をZabbixに流して監視したい

こんにちは、徐々に暖かくなってきましたね
もう3月も後半
期末で忙しい方も多いのではないでしょうか?

そんな忙しい中、これは3月中にやってしまいたい!!
と思っていたことがあったので、なんやらかんやらやりました

サーバ監視、どうしてる?

みなさん、サーバ監視どうしてます?
AWS使ってるならCloudwatchですかね?

自社のサービス1つとかであれば、Cloudwatchでトリガー作って、なんかあったらLambdaを利用してチャットに流すぜ!
とかで十分だと思います

しかし、弊社は零細ながらSIerですので、お客さまへ収めたシステムの保守のため、複数システムのサーバ監視を行う必要があります

そこで、基本的にはZabbixを利用しているのですが、AWSのいろんなサービスを使って構築しているサービスについてはまだCloudwatchで監視していました。

これだと、案件都度Cloudwatch => トリガー設定 => Lambdaでチャットに流す
とかがめんどくさい、、、!!

やっぱりZabbixのテンプレートを使いたい!!

ということで、重い腰を上げてCloudwatchからZabbixへデータを流す方法を探していました

Lambdaでいけるやん

すっごい単純でした
すっごいすっごい単純でした

Lambdaってすごいですね
Cloudwatchの情報取得できるやん

1. Lambda関数作る
  a. Cloudwatchの値を取得する
  b. ZabbixSenderを使ってデータを流す
2. Eventbridgeで5分ごとに

これだけで出来るんです

Lambda関数書く

今回はpythonで書きました

Cloudwatchのデータ取得

まず、Cloudwatchからデータを取得する部分


import boto3
import datetime

def getMetricStatistics(namespace, metricname, dimentionname, dimentionvalue, statistics, period):
    awsClient = boto3.client('cloudwatch')
    UTC = datetime.timezone(datetime.timedelta(hours=0), 'UTC')
    metricStatistics = awsClient.get_metric_statistics(
        Namespace = namespace,
        MetricName = metricname,
        Dimensions=[
            {
                'Name': dimentionname,
                'Value': dimentionvalue
            }
        ],
        StartTime = datetime.datetime.now(UTC) - datetime.timedelta(seconds=period),
        EndTime = datetime.datetime.now(UTC),
        Period = period,
        Statistics = [statistics]
    )

    return metricStatistics

boto3(AWS SDK for Python)を利用します

呼び出す時はこんな感じで呼び出しましょう


getMetricStatistics('AWS/RDS', 'CPUUtilization', 'DBInstanceIdentifier', 'hogehoge', 'Average', 300)

Zabbixへ送る

Zabbixへデータを送りたいのですが、RESTでは送れません
TCPでヘッダになんちゃらつけた、ほんじゃらして、としないといけません

その辺りをうまいことやってくれる「zabbix_sender」というコマンドラインユーティリティがあります
yumでインストールできたりするんですが、ちゃうねん、Lambdaで送りたいねん

ということで、ええ感じにやってくれてる人がいるもんです
Python版のzabbix_senderを作ってくれている人がいました
https://pypi.org/project/ZabbixSender/

ただこれ、そのままでは使えなかったです

ヘッダに必要な情報がない、、、、

ということで、ヘッダはつけてあげましょう


def send(self, packet):
	packet = str(packet).encode('utf-8')
    s = socket.socket()
    try:
        s.connect((self.server, int(self.port)))
    except Exception as e:  # TODO: Horrible! Rewrite immediately.
        print(e)

	# この辺り、ヘッダを追加している
    header = struct.pack(b'<4sBQ', b'ZBXD', 1, len(packet))
    packet = header + packet

    s.send(packet)
    time.sleep(0.5)
    status = s.recv(1024).decode('utf-8')
    re_status = re.compile('(\{.*\})')
    status = re_status.search(status).groups()[0]
    self.status = json.loads(status)
    s.close()

これを使って送るようにします


def zabbixSender(targethostname, tagetitemkey, dataPoint):
    # 1. Zabbix Managerを示すオブジェクトを取得
    zabbixManager = ZabbixSender('zabbix_server_url', 10051)

    # 2. Zabbix Senderで送るパケットを作成
    zabbixPacket = ZabbixPacket()
    zabbixPacket.add(targethostname, tagetitemkey, dataPoint)

    # 3. Zabbix Senderでパケット(データポイント)を送信
    zabbixManager.send(zabbixPacket)

呼び出す時はこんな感じ


zabbixSender('hogehoge host name', 'cpu_utilization', res['Datapoints'][0]['Average'])

これでZabbixでの管理ができるようになりました!

サーバ監視は重要ですよ

今弊社ではtoCサービス開発のお手伝いもさせていただいておりまして
実装のみならず、サーバインフラに関しても全て管理させていただいております

そんな状況なので、サービス負荷や停止はすぐに把握できないといけません

Zabbixで管理できると、トリガー設定によりチャットツール(弊社ではDiscord)に投げることができ、
何かあった際にすぐに状況を把握することができます

みなさんも、Zabbix使っていきましょう!
めっちゃ楽しいぃぃぃ

牧長 心

執筆者

CEO

牧長 心