#!/bin/bash # docker-health-check.sh # Scans all running containers, reports unhealthy ones, # and sends a Telegram alert if anything is wrong. # # Usage: bash docker-health-check.sh # Cron: */5 * * * * /usr/local/bin/docker-health-check.sh # # Config: set TELEGRAM_TOKEN and TELEGRAM_CHAT_ID below, # or export them as environment variables before running. set -euo pipefail TELEGRAM_TOKEN="${TELEGRAM_TOKEN:-}" TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID:-}" ALERT_ON_MISSING_HEALTH="${ALERT_ON_MISSING_HEALTH:-false}" # ── Collect container status ───────────────────────────────────── unhealthy=() missing_health=() while IFS= read -r name; do [[ -z "$name" ]] && continue status=$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{end}}' "$name" 2>/dev/null) case "$status" in unhealthy) unhealthy+=("$name") ;; "") [[ "$ALERT_ON_MISSING_HEALTH" == "true" ]] && missing_health+=("$name") ;; esac done < <(docker ps --format '{{.Names}}' 2>/dev/null) # ── Build message ──────────────────────────────────────────────── issues=0 message="" if [[ ${#unhealthy[@]} -gt 0 ]]; then issues=1 message+="🔴 *Unhealthy containers:*\n" for c in "${unhealthy[@]}"; do message+=" • ${c}\n" # Grab last 5 log lines for context logs=$(docker logs --tail 5 "$c" 2>&1 | tail -5 || true) message+=" \`${logs}\`\n" done fi if [[ ${#missing_health[@]} -gt 0 && "$ALERT_ON_MISSING_HEALTH" == "true" ]]; then message+="⚠️ *No healthcheck defined:*\n" for c in "${missing_health[@]}"; do message+=" • ${c}\n" done fi # ── Send Telegram alert if issues found ────────────────────────── if [[ $issues -eq 1 && -n "$TELEGRAM_TOKEN" && -n "$TELEGRAM_CHAT_ID" ]]; then curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage" \ -d "chat_id=${TELEGRAM_CHAT_ID}" \ -d "parse_mode=Markdown" \ -d "text=${message}" \ > /dev/null fi # ── Exit code for cron/systemd monitoring ──────────────────────── if [[ $issues -eq 1 ]]; then echo "[$(date)] UNHEALTHY: ${unhealthy[*]}" exit 1 else echo "[$(date)] All containers healthy" exit 0 fi