Files
clickstream-data-platform/scripts/stand-common.sh
T
ddadmin c5dd9c2d34 feat(monitoring): подготовлена основа мониторинга Kafka и ClickHouse
- Зачем:
  - подготовлен пол мониторинга для SQL-панелей и метрик отставания Kafka.
- Что:
  - добавлены отдельная роль ClickHouse, источник Grafana и Kafka exporter.
  - образ Grafana собирается с закреплённым плагином вне тома данных.
  - Prometheus, смоук и документация обновлены под четыре цели.
- Проверка:
  - make config-test; make lint.
  - make smoke; make check-clickhouse; make check-services.
  - make -C generator lint typecheck test.
2026-08-21 09:56:56 -04:00

109 lines
4.8 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Общая часть проверок на поднятом стенде: счёт проверок, обращение к Compose,
# зависимости машины и вопрос Docker, пережили ли контейнеры прогон. Файл не
# запускается сам — его подключают через source из stand-smoke.sh и
# stand-services.sh.
readonly ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
read -r -a COMPOSE_CMD <<<"${COMPOSE_BIN:-docker compose}"
readonly -a LONG_LIVED_SERVICES=(
clickhouse-keeper clickhouse-01 clickhouse-02 kafka kafka-exporter postgres-metadata
airflow-apiserver airflow-scheduler airflow-dag-processor
superset prometheus grafana
)
passed=0
failed=0
compose() {
"${COMPOSE_CMD[@]}" --project-directory "$ROOT_DIR" "$@"
}
pass() {
passed=$((passed + 1))
printf 'ЗЕЛЁНО: %s.\n' "$1"
}
fail() {
failed=$((failed + 1))
printf 'ОШИБКА: %s.\n' "$1" >&2
}
published_port() {
local binding
local service="$1"
local container_port="$2"
binding="$(compose port "$service" "$container_port" 2>/dev/null || true)"
printf '%s\n' "${binding##*:}"
}
# Отвечает, есть ли на машине всё, без чего проверкам не с чем работать.
# Засчитывать ли этот ответ проверкой, решает вызывающий: смоук печатает за него
# ЗЕЛЁНО, потому что вопрос к машине стоит рядом с «стенд собран»; для
# check-services это условие запуска, и своего ЗЕЛЁНО у него там нет.
require_host_dependencies() {
local command
local -a missing=()
for command in docker curl jq awk grep sed tail sleep timeout; do
command -v "$command" >/dev/null 2>&1 || missing+=("$command")
done
if [[ "${#missing[@]}" -gt 0 ]]; then
fail "на машине не хватает команд: ${missing[*]}"
return 1
fi
if ! docker compose version >/dev/null 2>&1; then
fail 'Docker Compose недоступен; установите модуль compose для Docker'
return 1
fi
if ! docker info >/dev/null 2>&1; then
fail 'Docker недоступен; запустите Docker и проверьте доступ к его сокету'
return 1
fi
return 0
}
# Убитый за память контейнер Docker поднимает сам, и проверка здоровья об этом
# промолчит. Порога здесь нет: это «да или нет», а не бюджет памяти (ADR 0004).
# Проверка стоит в конце обеих целей: нагружает стенд check-services, а увидеть
# последствия нужно и тому, кто гонял один смоук.
check_containers_survived() {
local container_id
local service
local state
local problems=0
for service in "${LONG_LIVED_SERVICES[@]}"; do
container_id="$(compose ps --all --quiet "$service" 2>/dev/null || true)"
if [[ -z "$container_id" || "$container_id" == *$'\n'* ]]; then
fail "не удалось получить контейнер ${service} для проверки перезапусков"
return
fi
state="$(docker inspect --format '{{.State.OOMKilled}}/{{.RestartCount}}' "$container_id" 2>/dev/null || true)"
case "$state" in
false/0) ;;
# OOMKilled встаёт и когда убит процесс внутри живого контейнера.
true/*)
fail "в контейнере ${service} ядро убило процесс из-за нехватки памяти"
problems=$((problems + 1))
;;
false/*)
fail "контейнер ${service} перезапускался, счётчик Docker — ${state#*/}"
problems=$((problems + 1))
;;
*)
fail "Docker не рассказал о состоянии контейнера ${service}"
problems=$((problems + 1))
;;
esac
done
if [[ "$problems" -eq 0 ]]; then
pass 'ни в одном долгоживущем контейнере ядро не убивало процессы за память, и никто не перезапускался сам'
fi
}
# Время печатается как замер, а не как порог: смотрит на него человек.
print_total() {
printf 'ИТОГ: пройдено %d, ошибок %d, время %d с\n' "$passed" "$failed" "$SECONDS"
}