#!/bin/bash
# =============================================================================
# Docker 網路健康監控與自動修復腳本
#
# 功能:
# 1. 監控 mo.wooo.work 服務健康狀態
# 2. 檢測 Docker 網路轉發問題
# 3. 自動修復並發送 Telegram 告警
#
# 用法:
# 每 5 分鐘執行一次(透過 cron)
# */5 * * * * /home/wooo/scripts/docker_health_monitor.sh >> /var/log/docker_health_monitor.log 2>&1
#
# 作者:Claude Code
# 日期:2026-01-28
# =============================================================================
set -e
# =============================================================================
# 配置區
# =============================================================================
# 服務端點
HEALTH_URL="https://mo.wooo.work/health"
LOCAL_URL="http://127.0.0.1:5001/health"
CONTAINER_NAME="momo-pro-system"
# Telegram 配置
TELEGRAM_BOT_TOKEN="8075645931:AAH-EGKMo8ZC4QJs-Nc1_0s92xHrGdQvdpg"
TELEGRAM_CHAT_ID="5619078117"
# 超時設定(秒)
CURL_TIMEOUT=15
MAX_RETRIES=2
# 日誌檔案
LOG_FILE="/var/log/docker_health_monitor.log"
# =============================================================================
# 函數定義
# =============================================================================
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
send_telegram() {
local message="$1"
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d chat_id="${TELEGRAM_CHAT_ID}" \
-d text="${message}" \
-d parse_mode="HTML" \
> /dev/null 2>&1 || true
}
check_external_health() {
# 檢查外部健康端點
local http_code
http_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout ${CURL_TIMEOUT} --max-time ${CURL_TIMEOUT} "${HEALTH_URL}" 2>/dev/null || echo "000")
echo "${http_code}"
}
check_local_port() {
# 檢查本地端口連通性
local http_code
http_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout ${CURL_TIMEOUT} --max-time ${CURL_TIMEOUT} "${LOCAL_URL}" 2>/dev/null || echo "000")
echo "${http_code}"
}
check_container_internal() {
# 檢查容器內部服務是否正常
local result
result=$(docker exec ${CONTAINER_NAME} curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 http://127.0.0.1:80/health 2>/dev/null || echo "000")
echo "${result}"
}
is_container_running() {
docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"
}
restart_docker_service() {
log "正在重啟 Docker 服務..."
sudo systemctl restart docker
# 等待容器啟動
log "等待容器啟動(60 秒)..."
sleep 60
# 驗證恢復
local http_code
http_code=$(check_external_health)
if [ "${http_code}" = "200" ]; then
log "Docker 服務重啟成功,服務已恢復"
return 0
else
log "Docker 服務重啟後服務仍未恢復 (HTTP ${http_code})"
return 1
fi
}
restart_container() {
log "正在重啟容器 ${CONTAINER_NAME}..."
docker restart ${CONTAINER_NAME}
# 等待容器啟動
log "等待容器啟動(30 秒)..."
sleep 30
# 驗證恢復
local http_code
http_code=$(check_external_health)
if [ "${http_code}" = "200" ]; then
log "容器重啟成功,服務已恢復"
return 0
else
log "容器重啟後服務仍未恢復 (HTTP ${http_code})"
return 1
fi
}
# =============================================================================
# 主程式
# =============================================================================
main() {
log "========== 開始健康檢查 =========="
# 第一步:檢查外部健康端點
local external_code
external_code=$(check_external_health)
log "外部健康檢查: HTTP ${external_code}"
if [ "${external_code}" = "200" ]; then
log "服務正常運行"
log "========== 檢查完成 =========="
exit 0
fi
# 第二步:服務異常,開始診斷
log "偵測到服務異常,開始診斷..."
# 檢查容器是否運行
if ! is_container_running; then
log "容器 ${CONTAINER_NAME} 未運行"
# 嘗試啟動容器
log "嘗試啟動容器..."
docker start ${CONTAINER_NAME} 2>/dev/null || true
sleep 30
external_code=$(check_external_health)
if [ "${external_code}" = "200" ]; then
send_telegram "🟢 MOMO Pro 服務已恢復
問題: 容器未運行
動作: 已自動啟動容器
時間: $(date '+%Y-%m-%d %H:%M:%S')"
log "容器啟動成功,服務已恢復"
exit 0
fi
fi
# 檢查本地端口連通性
local local_code
local_code=$(check_local_port)
log "本地端口檢查: HTTP ${local_code}"
# 檢查容器內部服務
local internal_code
internal_code=$(check_container_internal)
log "容器內部檢查: HTTP ${internal_code}"
# 診斷邏輯
if [ "${internal_code}" = "200" ] && [ "${local_code}" != "200" ]; then
# 容器內部正常但外部端口不通 → Docker 網路問題
log "診斷結果: Docker 網路轉發失效"
send_telegram "🔴 MOMO Pro 服務異常
症狀: 502 Bad Gateway
診斷: Docker 網路轉發失效
動作: 正在重啟 Docker 服務...
時間: $(date '+%Y-%m-%d %H:%M:%S')"
if restart_docker_service; then
send_telegram "🟢 MOMO Pro 服務已恢復
問題: Docker 網路轉發失效
動作: Docker 服務重啟成功
時間: $(date '+%Y-%m-%d %H:%M:%S')"
else
send_telegram "🔴 MOMO Pro 自動修復失敗
問題: Docker 網路轉發失效
狀態: Docker 重啟後服務仍未恢復
需要: 人工介入處理
時間: $(date '+%Y-%m-%d %H:%M:%S')
SSH: ssh wooo@192.168.0.110"
fi
elif [ "${internal_code}" != "200" ]; then
# 容器內部服務異常 → 應用問題
log "診斷結果: 應用服務異常"
send_telegram "🔴 MOMO Pro 服務異常
症狀: 應用服務無回應
診斷: 容器內部服務異常
動作: 正在重啟容器...
時間: $(date '+%Y-%m-%d %H:%M:%S')"
if restart_container; then
send_telegram "🟢 MOMO Pro 服務已恢復
問題: 應用服務異常
動作: 容器重啟成功
時間: $(date '+%Y-%m-%d %H:%M:%S')"
else
# 容器重啟失敗,嘗試重啟 Docker
log "容器重啟失敗,嘗試重啟 Docker 服務..."
if restart_docker_service; then
send_telegram "🟢 MOMO Pro 服務已恢復
問題: 應用服務異常
動作: Docker 服務重啟成功
時間: $(date '+%Y-%m-%d %H:%M:%S')"
else
send_telegram "🔴 MOMO Pro 自動修復失敗
問題: 應用服務異常
狀態: 多次修復嘗試後服務仍未恢復
需要: 人工介入處理
時間: $(date '+%Y-%m-%d %H:%M:%S')
SSH: ssh wooo@192.168.0.110
日誌: kubectl logs -f deployment/momo-app -n momo"
fi
fi
else
# 無法判斷問題
log "診斷結果: 無法判斷問題原因"
send_telegram "🟠 MOMO Pro 服務異常
症狀: 服務無法存取 (HTTP ${external_code})
診斷: 無法判斷問題原因
本地端口: HTTP ${local_code}
容器內部: HTTP ${internal_code}
需要: 人工介入處理
時間: $(date '+%Y-%m-%d %H:%M:%S')
SSH: ssh wooo@192.168.0.110"
fi
log "========== 檢查完成 =========="
}
# 執行主程式
main "$@"