PythonとDiscord Webhookで自作するサーバー監視システム

Python tutorial - IT technology blog
Python tutorial - IT technology blog

「深夜のサーバーダウン」という悪夢

Webアプリやボットを動かしているVPSをいくつか管理していますか?朝起きたらサービスが完全に停止していた、という経験は誰にでもあるはずです。顧客からのクレーム、上司からの呼び出し。そして原因を調べてみれば、ディスク容量がいっぱいだったり、特定のプロセスがRAMを使い果たしてフリーズしていたりといった、実にあっけないものだったりします。

大量のエラー通知とともに目が覚めるのは、まさに悪夢です。実際、リソースの状態を事前に把握していれば、こうした事態は防げます。1時間おきに手動でサーバーにSSH接続してtopdf -hを叩く代わりに、Pythonにその役目を任せましょう。わずか15分のセットアップで、システムに異変があればすぐにDiscordで知らせてくれる、忠実な「門番」を手に入れることができます。

本格的なツールか、それともPythonか?

コードを書き始める前に、現在の監視ソリューションをいくつか見てみましょう。適切なツールを選ぶことで、時間とコストの両方を節約できます。

一般的な監視方法の比較

  • 専用ツール (Prometheus, Zabbix): これらは真の「怪物」です。強力でグラフも美しいですが、リソースを非常に消費します。1GB RAMのVPSにPrometheus + Grafana(通常200-400MB RAMを占有)を載せるのは、自分を苦しめているようなものです。
  • クラウドサービス (Datadog, New Relic): 機能は非常に優れています。しかし、月額料金がサーバーのレンタル費用よりも高くなることもあります。
  • 自作Pythonスクリプト: スタートアップや個人サーバーに最適な選択です。超軽量(わずか15-20MB程度のRAM消費)、100%カスタマイズ可能、そして完全に無料です。

以下の比較表を参考に判断してください:

項目 Zabbix/Prometheus Pythonスクリプト
RAM消費量 ~300MB以上 < 20MB
デプロイ 複雑 非常に早い
コスト 無料/有料 0円

なぜDiscord Webhookなのか?

メールは遅く、スパムフォルダに入りやすいです。Telegramは一部の地域で接続に問題が発生することがあります。一方、Discordは非常に柔軟なWebhookの仕組みを提供しています。JSONを含むPOSTリクエストを所定のURLに送信するだけで完了です。メッセージはプロフェッショナルなRich Embed形式で即座に表示され、色によって警告の深刻度を明確に区別できます。

3ステップで監視スクリプトを構築する

開始するには、サーバーにPython 3が必要です。システム情報の取得にはpsutilを、Discordへのデータ送信にはrequestsを使用します。

ステップ1: ライブラリのインストール

サーバーのターミナルで以下のコマンドを実行します:

pip install psutil requests

ステップ2: Webhook URLの取得

  1. Discordを開き、サーバー設定 -> 連携 に移動します。
  2. Webhook -> 新しいWebhook を選択します。
  3. ボットの名前(例:「Sentry Bot」)を設定し、URLをコピーします。このURLは秘密にしておいてください!

ステップ3: 処理ロジックの作成

以下のスクリプトはCPU、RAM、ディスクをチェックします。いずれかの数値が安全なしきい値を超えると、アラートをトリガーします。

import psutil
import requests
import socket
from datetime import datetime

# 警告しきい値の設定
DISCORD_WEBHOOK_URL = "YOUR_WEBHOOK_URL_HERE"
CPU_THRESHOLD = 80  # CPUが80%を超えたら警告
RAM_THRESHOLD = 85  # RAMが85%を超えたら警告
DISK_THRESHOLD = 90 # ディスクが90%を超えたら警告

def get_system_status():
    hostname = socket.gethostname()
    # 正確な数値を得るために1秒間のCPU平均を取得
    cpu_usage = psutil.cpu_percent(interval=1)
    ram_usage = psutil.virtual_memory().percent
    disk_usage = psutil.disk_usage('/').percent
    return hostname, cpu_usage, ram_usage, disk_usage

def send_discord_alert(hostname, cpu, ram, disk):
    payload = {
        "embeds": [{
            "title": f"🚨 リソース警告: {hostname}",
            "color": 15158332, # 赤色
            "fields": [
                {"name": "CPU", "value": f"{cpu}%", "inline": True},
                {"name": "RAM", "value": f"{ram}%", "inline": True},
                {"name": "Disk", "value": f"{disk}%", "inline": True},
            ],
            "footer": {"text": f"記録時刻: {datetime.now().strftime('%H:%M:%S %Y-%m-%d')}"}
        }]
    }
    requests.post(DISCORD_WEBHOOK_URL, json=payload)

def main():
    hostname, cpu, ram, disk = get_system_status()
    if cpu > CPU_THRESHOLD or ram > RAM_THRESHOLD or disk > DISK_THRESHOLD:
        send_discord_alert(hostname, cpu, ram, disk)
    else:
        print(f"システム正常: CPU {cpu}% | RAM {ram}% | Disk {disk}%")

if __name__ == "__main__":
    main()

Crontabによる自動化

スクリプトは完成しましたが、まさか手動で実行し続けるわけにはいきません。5分ごとに自動実行させるために、Linuxの定番スケジューリングツールである Crontab を使用します。

crontab -e を入力し、ファイルの末尾に以下の行を追加します:

*/5 * * * * /usr/bin/python3 /home/user/monitor.py >> /var/log/monitor.log 2>&1

注意:Cron実行時の環境エラーを避けるため、絶対パス(例:/usr/bin/python3)を使用することをお勧めします。

スクリプトをより「賢く」するための実践的なアドバイス

実際のサーバー群で運用してみた経験から、いくつかのアドバイスがあります:

  1. スパム防止: CPUが連続して90%に張り付いている場合、Discordの通知が爆発してしまいます。状態が「正常」から「警告」に変わったときだけメッセージを送信するようにコードを修正しましょう。
  2. OOM Killerの監視: RAMがいっぱいになると、Linuxは重いプロセス(MySQLなど)を強制終了させることがあります。psutil.process_iter() を追加して、重要なサービスが生きているかチェックする機能を追加しても良いでしょう。
  3. すべてをログに記録する: 常にログをファイルに書き出してください。サーバーが本当にダウンしたとき、これらのログは午前2時に何が起きたかを知るための唯一の手がかりになります。

自前で監視ツールを構築することは、安心感を得られるだけでなく、DevOps的な思考を鍛える良い訓練にもなります。サーバーの突然の「心停止」を心配することなく、ぐっすり眠れる夜を過ごせるよう願っています!

Share: