【新・実践シェルスクリプト講座 第2回】夜中に「サイトが見れません!」と電話で起こされないための自動蘇生術
こんにちは!「リナックス先生」です。
前回は、コマンド一発でWebサーバー環境を構築する「自動構築スクリプト」を作りましたね。
コウ君、その後のサーバー運用は順調?
先生…それが、聞いてくださいよ。
昨日の深夜、アクセスが急増したみたいで、メモリ不足でApacheが落ちちゃってたんです。
朝起きたらクライアントから「サイトが見れない!」って鬼のように着信が入ってて…(涙)。
24時間画面を見張り続けるなんて無理ですよ!
あらら、インフラエンジニアの洗礼を受けたわね。
サーバーは「落ちるもの」よ。大切なのは、落ちないように祈ることじゃなくて、「落ちたらすぐに拾い上げる(再起動する)」こと。
今回は、ダウンを検知して自動で蘇生し、Discordに「直しておいたよ」と報告するスクリプトを作るわよ!
新シリーズ「新・実践シェルスクリプト講座」の第2回は、**「サービス死活監視と自動復旧」**です。
単にプロセスがあるか確認するだけでなく、実際にHTTPアクセスを行って「サイトが正常に見えているか」までチェックする、実践的な監視スクリプトを構築します。
本講座のカリキュラム(全4回)
本シリーズでは、「攻めの自動化」でサーバー管理を楽にします。
- 黒い画面でポチポチするな!「Webサーバー構築(LAMP環境)」をボタン一発で全自動化する【完了】
- 【今回】Webサイトが死んだら自動で蘇生せよ!「サービス死活監視」と「自動再起動」
- ローカル保存じゃ終わらない!「DBバックアップ」と「AWS S3/クラウドへの自動転送」
- 黒い画面をアプリ化!?「対話型メニュー」で作る自分だけの管理ツール
1. そもそも、なぜWebサーバーは「死ぬ」のか?
設定ミスをしていないのに、稼働中のサーバーが突然止まる原因の多くは「OOM Killer (Out Of Memory Killer)」です。
アクセス集中などでメモリが足りなくなると、Linuxカーネルはシステム全体を守るために、メモリを食っているプロセス(多くの場合 Apache や MySQL)を強制的にキル(停止)します。
この場合、サーバー自体(OS)は動いていますが、Webサイトだけが表示されない状態になります。
これを復旧するには、人間が systemctl restart httpd を打つ必要がありますが…それをスクリプトにやらせましょう。
2. 通知の準備:Discord Webhook
「再起動しました」という報告を受け取るために、今回はDiscordを使います。
(SlackやTeamsでも手順は似ています)
- Discordで通知を送りたいチャンネルの「設定(歯車)」を開く。
- 「連携」→「ウェブフック」→「新しいウェブフック」を作成。
- 「ウェブフックURLをコピー」ボタンを押して、URLをメモしておく。
これだけで、特定のURLにデータを投げるだけでメッセージが届くようになります。
3. 自動復旧スクリプト「auto_heal.sh」
では、スクリプトを作成します。
仕様は以下の通りです。
- プロセス監視:
httpdとmariadbが起動しているかチェック。停止していたら起動する。 - HTTP監視: 自分のサイトにアクセスして、ステータスコード
200 OKが返ってくるかチェック。応答がなければApacheを再起動する。 - 通知: 復旧処置を行ったらDiscordに通知する。
vim auto_heal.sh を作成します。
#!/bin/bash
# ==========================================
# 設定エリア
# ==========================================
# 監視対象のサービス名
TARGET_SERVICES=("httpd" "mariadb")
# 監視対象のURL(自分のサイト)
CHECK_URL="http://localhost/"
# Discord Webhook URL(ここに先ほどコピーしたURLを貼る)
DISCORD_URL="https://discord.com/api/webhooks/xxxxxxxx/xxxxxxxxx"
# ログファイル
LOG_FILE="/var/log/auto_heal.log"
# --- 安全設定 ---
set -u
# ==========================================
# 関数定義
# ==========================================
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# Discord通知関数
send_discord() {
local message="$1"
# JSON形式でメッセージを作成
# メンション(@here)を付けて緊急度をアピール
local payload="{\"content\": \"🚑 **[Server Alert] 自動復旧発動** @here\n${message}\"}"
# curlでPOST送信
curl -s -H "Content-Type: application/json" -X POST -d "$payload" "$DISCORD_URL"
}
# ==========================================
# 1. プロセス死活監視 (systemctl check)
# ==========================================
log "--- 監視チェック開始 ---"
for service in "${TARGET_SERVICES[@]}"; do
# is-active は起動中なら0、停止中なら非0を返す
if ! systemctl is-active --quiet "$service"; then
log "【危険】$service が停止しています! 再起動を試みます..."
# サービスの再起動
systemctl start "$service"
# 結果確認
if systemctl is-active --quiet "$service"; then
log "【成功】$service の再起動に成功しました。"
send_discord "✅ 停止していたサービス **$service** を再起動しました。"
else
log "【失敗】$service の再起動に失敗しました。手動対応が必要です。"
send_discord "⛔ **$service** の再起動に失敗しました! 至急確認してください!"
fi
fi
done
# ==========================================
# 2. HTTP応答監視 (curl check)
# ==========================================
# プロセスが生きていても、ゾンビ状態でアクセスを受け付けない場合があるため
# 実際にアクセスして確認する
# curlオプション解説
# -s: 静かに(プログレスバーを出さない)
# -o /dev/null: 取得したHTMLは捨てる
# -w "%{http_code}": ステータスコード(200, 404, 500等)だけを表示
http_status=$(curl -s -o /dev/null -w "%{http_code}" "$CHECK_URL")
# ステータスコードが 200 (OK) じゃなかったら異常とみなす
# 000 は接続不可
if [ "$http_status" != "200" ]; then
log "【危険】Webサイト応答なし (Status: $http_status)。Apacheを再起動します..."
systemctl restart httpd
sleep 5 # 起動待ち
# 再チェック
retry_status=$(curl -s -o /dev/null -w "%{http_code}" "$CHECK_URL")
if [ "$retry_status" == "200" ]; then
log "【成功】Webサイトが復旧しました。"
send_discord "✅ Webサイトの応答がありませんでした(Status: $http_status)。Apacheを再起動し、復旧しました。"
else
log "【失敗】Webサイトが復旧しません (Status: $retry_status)。"
send_discord "⛔ Apacheを再起動しましたが、Webサイトが見れません(Status: $retry_status)。ログを確認してください。"
fi
else
log "Webサイトは正常です (Status: 200)"
fi
log "--- 監視チェック終了 ---"
💡 プロのテクニック:プロセス監視 vs サービス監視
systemctl で「active」になっていても、アクセス過多でフリーズしていてサイトが開かないことはよくあります。
逆に、プロセスは死んでいるのに、pidファイルだけ残っていて「active」と誤認されることも。
だからこそ、「実際にアクセスしてみる(外形監視)」と「プロセスを見る(内部監視)」の両方を組み合わせるのが最強の監視方法なのです。
4. 定期実行の設定
作成したスクリプトに実行権限を与え、Cronに登録します。
5分おきに実行するのが一般的です。
# 実行権限付与 chmod +x auto_heal.sh # 動作テスト(わざとApacheを止めてから実行してみよう) systemctl stop httpd ./auto_heal.sh # -> Discordに通知が来れば成功!
Cronの設定 (crontab -e)
# 5分ごとに監視を実行 # PATHを通しておくとトラブルが少ない PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin */5 * * * * /root/auto_heal.sh >> /var/log/cron_heal.log 2>&1
5. このスクリプトの弱点と対策
このスクリプトは便利ですが、万能ではありません。
例えば、「設定ファイル(httpd.conf)の記述ミス」でApacheが起動しない場合、このスクリプトは5分おきに永遠に再起動を試み、失敗し、Discordに通知を送り続けます(これを「通知スパム」と呼びます)。
実務では、「3回連続で失敗したら、スクリプト自体を一時停止する」といったロジックを追加することもありますが、まずは「深夜に叩き起こされる回数を減らす」ための第一歩として、このスクリプトを使ってみてください。
まとめ:エンジニアは寝るのが仕事
今回は「サービス死活監視と自動復旧」を自動化しました。
| 監視項目 | 使用コマンド | 目的 |
|---|---|---|
| プロセス監視 | systemctl is-active |
サービスが落ちていないか確認 |
| HTTP監視 | curl -w "%{http_code}" |
Webサイトが正常に見えているか確認 |
| 通知 | curl -X POST (Discord) |
復旧結果をスマホに通知 |
これで、突発的なメモリエラーでApacheが落ちても、次の5分後には自動で蘇生されます。
あなたは朝起きて、Discordの通知を見て「おっ、夜中に一回コケたな。後でログ見ておくか」とコーヒーを飲めばいいのです。
次回予告:バックアップは「外」に出せ!
サーバー監視は完璧になりました。
しかし、もしサーバーのディスク自体が壊れたら? VPSごとそのデータセンターが火事になったら?
サーバーの中にバックアップがあっても、一緒に消えてしまいます。
次回は、「データベース(MariaDB)のダンプ」を取り、それを「AWS S3(クラウドストレージ)」などの外部へ自動転送する、プロ仕様のBCP(事業継続計画)対策スクリプトを作成します。
今回のスクリプトは、Webサーバー以外にも応用が効くわ。
例えば、Minecraftサーバーの監視とか、Botプログラムの監視とか。
「動いてなきゃいけないもの」があったら、とりあえず監視させる癖をつけるといいわよ!
▼監視スクリプトのテストは、本番環境ではなくサブのVPSで!


コメント