Стек мониторинга: Prometheus + Alertmanager + Grafana + node_exporter + cAdvisor

Самодостаточный docker compose стек с деплоем через deploy.sh,
bootstrap-установкой с нуля и конфигурацией через .env.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
ShiZa039 2026-07-23 12:54:40 +02:00
commit 74b6f92cb8
15 changed files with 17242 additions and 0 deletions

141
bootstrap.sh Normal file
View file

@ -0,0 +1,141 @@
#!/usr/bin/env bash
# Установка «с нуля» одной командой: ставит зависимости (git, curl, docker,
# compose, htpasswd), клонирует/обновляет репозиторий, создаёт .env (интерактивно
# при первом запуске) и запускает deploy.sh. Идемпотентен — повторный запуск
# просто подтянет свежий код и переприменит конфигурацию.
#
# Использование (на чистом сервере, от root):
# curl -fsSL https://git.sab-core.ru/ShiZa/server-monitoring/raw/branch/main/bootstrap.sh \
# | sudo bash -s -- --repo https://git.sab-core.ru/ShiZa/server-monitoring.git
#
# Или из уже склонированного репозитория:
# sudo bash bootstrap.sh
#
# Флаги: --repo <url> URL git-репозитория (обязателен вне клона)
# --dir <path> куда клонировать (по умолчанию /opt/monitoring)
# --branch <br> ветка (по умолчанию ветка по умолчанию репо)
set -euo pipefail
C_RED=$'\033[31m'; C_GREEN=$'\033[32m'; C_YELLOW=$'\033[33m'; C_RESET=$'\033[0m'
say() { echo "${C_GREEN}==>${C_RESET} $*"; }
warn() { echo "${C_YELLOW}[WARN]${C_RESET} $*"; }
die() { echo "${C_RED}[ERR]${C_RESET} $*" >&2; exit 1; }
REPO_URL=""
TARGET_DIR="/opt/monitoring"
BRANCH=""
while [ $# -gt 0 ]; do
case "$1" in
--repo) REPO_URL="${2:?}"; shift 2 ;;
--dir) TARGET_DIR="${2:?}"; shift 2 ;;
--branch) BRANCH="${2:?}"; shift 2 ;;
-h|--help) grep '^#' "$0" | head -20; exit 0 ;;
*) die "неизвестный аргумент: $1" ;;
esac
done
[ "$(id -u)" = 0 ] || die "нужны права root: запусти через sudo"
command -v apt-get >/dev/null 2>&1 || die "поддерживается только Debian/Ubuntu (нужен apt-get)"
# --- 1. Базовые пакеты -------------------------------------------------------
declare -A CMD_PKG=([curl]=curl [git]=git [htpasswd]=apache2-utils)
MISSING=()
for cmd in "${!CMD_PKG[@]}"; do
command -v "$cmd" >/dev/null 2>&1 || MISSING+=("${CMD_PKG[$cmd]}")
done
if [ "${#MISSING[@]}" -gt 0 ]; then
say "Ставлю пакеты: ${MISSING[*]}"
apt-get update -qq
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq ca-certificates "${MISSING[@]}"
fi
# --- 2. Docker + compose -----------------------------------------------------
if ! command -v docker >/dev/null 2>&1; then
say "Docker не найден — ставлю через get.docker.com"
curl -fsSL https://get.docker.com | sh
fi
if ! docker compose version >/dev/null 2>&1; then
say "Плагин docker compose не найден — ставлю docker-compose-plugin"
apt-get update -qq
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq docker-compose-plugin \
|| die "не удалось поставить docker-compose-plugin — поставь вручную"
fi
systemctl enable --now docker >/dev/null 2>&1 || true
docker info >/dev/null 2>&1 || die "docker-демон не запущен (systemctl status docker)"
# --- 3. Репозиторий ----------------------------------------------------------
if [ -z "${REPO_URL}" ] && [ -f ./deploy.sh ] && [ -f ./docker-compose.yml ]; then
# запущен из уже склонированного репозитория
TARGET_DIR="$(pwd)"
say "Использую текущий клон: ${TARGET_DIR}"
if [ -d .git ] && git remote get-url origin >/dev/null 2>&1; then
git pull --ff-only || warn "git pull не удался (локальные изменения?) — продолжаю с текущим кодом"
fi
elif [ -d "${TARGET_DIR}/.git" ]; then
say "Обновляю ${TARGET_DIR}"
git -C "${TARGET_DIR}" fetch --all --prune
if [ -n "${BRANCH}" ]; then git -C "${TARGET_DIR}" checkout "${BRANCH}"; fi
git -C "${TARGET_DIR}" pull --ff-only || warn "git pull не удался — продолжаю с текущим кодом"
else
[ -n "${REPO_URL}" ] || die "укажи --repo <url> (или запусти скрипт из клона репозитория)"
say "Клонирую ${REPO_URL}${TARGET_DIR}"
if [ -n "${BRANCH}" ]; then
git clone --branch "${BRANCH}" "${REPO_URL}" "${TARGET_DIR}"
else
git clone "${REPO_URL}" "${TARGET_DIR}"
fi
fi
cd "${TARGET_DIR}"
# стек может лежать в подкаталоге monitoring/ репозитория
[ -f deploy.sh ] || { [ -f monitoring/deploy.sh ] && cd monitoring; } || die "deploy.sh не найден в репозитории"
# --- 4. .env: интерактивное создание при первом запуске ----------------------
if [ ! -f .env ]; then
cp .env.example .env
chmod 600 .env
if [ -r /dev/tty ] && [ -w /dev/tty ]; then
say "Первый запуск — настрою .env (значения можно потом поменять: nano .env && bash deploy.sh)"
DEFAULT_IP=""
if command -v tailscale >/dev/null 2>&1; then
DEFAULT_IP="$(tailscale ip -4 2>/dev/null | head -1 || true)"
fi
[ -n "${DEFAULT_IP}" ] || DEFAULT_IP="$(hostname -I 2>/dev/null | awk '{print $1}')"
echo "Адреса на интерфейсах:" >/dev/tty
ip -o -4 addr show scope global 2>/dev/null | awk '{print " " $2 ": " $4}' >/dev/tty || true
read -r -p "BIND_IP (tailnet или публичный IP) [${DEFAULT_IP}]: " BIND_IP </dev/tty
BIND_IP="${BIND_IP:-${DEFAULT_IP}}"
[ -n "${BIND_IP}" ] || die "BIND_IP обязателен"
DEFAULT_NAME="$(hostname -s)"
read -r -p "SERVER_NAME [${DEFAULT_NAME}]: " SERVER_NAME </dev/tty
SERVER_NAME="${SERVER_NAME:-${DEFAULT_NAME}}"
GRAFANA_ADMIN_PASSWORD=""
while [ -z "${GRAFANA_ADMIN_PASSWORD}" ]; do
read -r -s -p "Пароль admin для Grafana: " GRAFANA_ADMIN_PASSWORD </dev/tty; echo >/dev/tty
done
read -r -s -p "METRICS_PASSWORD (basic auth на Prometheus/Alertmanager/node_exporter; ПУСТО допустимо только для tailnet-серверов): " METRICS_PASSWORD </dev/tty
echo >/dev/tty
[ -n "${METRICS_PASSWORD}" ] || warn "METRICS_PASSWORD пуст — метрики будут без аутентификации"
sed -i \
-e "s|^BIND_IP=.*|BIND_IP=${BIND_IP}|" \
-e "s|^SERVER_NAME=.*|SERVER_NAME=${SERVER_NAME}|" \
-e "s|^GRAFANA_ADMIN_PASSWORD=.*|GRAFANA_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}|" \
-e "s|^METRICS_PASSWORD=.*|METRICS_PASSWORD=${METRICS_PASSWORD}|" \
.env
say ".env создан. Списки CRITICAL_CONTAINERS / CRITICAL_UNITS и Telegram-токены — правь в $(pwd)/.env"
else
warn "Нет терминала для вопросов: создан $(pwd)/.env из шаблона."
warn "Заполни его (nano .env) и запусти: bash deploy.sh"
exit 0
fi
fi
# --- 5. Деплой ---------------------------------------------------------------
say "Запускаю deploy.sh"
bash deploy.sh