Zabbix отлично закрывает классический мониторинг серверов по модели «агент присылает данные на сервер», но когда в игру вступают контейнеры, микросервисы и приложения с собственными бизнес-метриками, удобнее становится другой подход — Prometheus. Он тянет метрики сам (pull-модель), хранит их во встроенной time-series базе, а визуализацию отдаёт Grafana, которая умеет рисовать по-настоящему красивые и информативные дашборды. В этой статье поднимем связку на выделенном сервере srv-mon01 в сети 192.168.10.0/24 и подключим первые цели для сбора метрик.

Основная идея Prometheus в том, что не источники метрик присылают данные на сервер, а сам Prometheus периодически опрашивает (scrape) HTTP-эндпоинты вида /metrics у каждой цели. Это делает его отличным выбором для Kubernetes и микросервисной архитектуры: приложение просто отдаёт метрики в текстовом формате, а Prometheus сам решает, когда и как часто их забирать.

Шаг 1. Установка Prometheus на srv-mon01

Разворачиваем Prometheus как systemd-сервис на Ubuntu-сервере srv-mon01. Официальные бинарники не требуют пакетного менеджера — скачиваем архив с релизами и распаковываем.

hostnamectl set-hostname srv-mon01
useradd --no-create-home --shell /usr/sbin/nologin prometheus
mkdir /etc/prometheus /var/lib/prometheus

cd /tmp
wget https://github.com/prometheus/prometheus/releases/download/v2.53.0/prometheus-2.53.0.linux-amd64.tar.gz
tar xvf prometheus-2.53.0.linux-amd64.tar.gz
cd prometheus-2.53.0.linux-amd64

cp prometheus promtool /usr/local/bin/
cp -r consoles console_libraries /etc/prometheus
chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus /usr/local/bin/prometheus /usr/local/bin/promtool

Шаг 2. Конфигурация: кого опрашивать

Все цели для сбора метрик описываются в /etc/prometheus/prometheus.yml в формате YAML. Базовая конфигурация с несколькими серверами в домене itpages.lab.local выглядит так:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]

  - job_name: "node_exporter"
    static_configs:
      - targets:
          - "192.168.10.21:9100"
          - "192.168.10.22:9100"
          - "192.168.10.10:9100"
        labels:
          env: "lab"

Здесь job_name — логическая группа целей, а targets — конкретные адреса с портами, где крутится exporter. Обрати внимание на блок labels: он добавляет метку env ко всем метрикам этой группы, что удобно, когда позже нужно будет фильтровать данные по окружению в Grafana.

Шаг 3. Node Exporter — метрики самих серверов

Сам Prometheus метрики CPU или диска не собирает — для этого на каждый сервер ставится node_exporter, маленький агент, который отдаёт системные метрики по HTTP. Ставим его, например, на srv-web01 (192.168.10.21):

useradd --no-create-home --shell /usr/sbin/nologin node_exporter

wget https://github.com/prometheus/node_exporter/releases/download/v1.8.1/node_exporter-1.8.1.linux-amd64.tar.gz
tar xvf node_exporter-1.8.1.linux-amd64.tar.gz
cp node_exporter-1.8.1.linux-amd64/node_exporter /usr/local/bin/
chown node_exporter:node_exporter /usr/local/bin/node_exporter

Создаём unit-файл systemd, чтобы экспортёр запускался автоматически и переживал перезагрузку:

cat > /etc/systemd/system/node_exporter.service <<'EOF'
[Unit]
Description=Node Exporter
After=network.target

[Service]
User=node_exporter
ExecStart=/usr/local/bin/node_exporter

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now node_exporter

После запуска метрики доступны по адресу http://192.168.10.21:9100/metrics — это обычный текстовый вывод, который Prometheus и будет забирать каждые 15 секунд согласно scrape_interval.

Шаг 4. Запуск Prometheus как сервиса

cat > /etc/systemd/system/prometheus.service <<'EOF'
[Unit]
Description=Prometheus
After=network.target

[Service]
User=prometheus
ExecStart=/usr/local/bin/prometheus   --config.file=/etc/prometheus/prometheus.yml   --storage.tsdb.path=/var/lib/prometheus   --web.listen-address=0.0.0.0:9090

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now prometheus

Веб-интерфейс Prometheus поднимается на http://192.168.10.10:9090. Загляни в раздел Status → Targets — там сразу видно, какие цели опрашиваются успешно (зелёный UP), а какие недоступны. Это первое место, куда стоит смотреть при отладке: если экспортёр не отвечает, причина обычно в firewall или в том, что сервис попросту не запущен.

Шаг 5. Установка Grafana

Grafana ставим либо на тот же srv-mon01, либо на отдельный сервер — для лабораторного стенда проще держать всё в одном месте.

apt install -y apt-transport-https software-properties-common
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor -o /usr/share/keyrings/grafana.gpg
echo "deb [signed-by=/usr/share/keyrings/grafana.gpg] https://apt.grafana.com stable main"   > /etc/apt/sources.list.d/grafana.list

apt update
apt install -y grafana

systemctl enable --now grafana-server

Интерфейс открывается на http://192.168.10.10:3000, логин и пароль по умолчанию — admin/admin, при первом входе система попросит сменить пароль.

Шаг 6. Подключаем Prometheus как источник данных

В Grafana идём в Connections → Data sources → Add data source, выбираем Prometheus и указываем URL http://localhost:9090 (если Grafana стоит на том же srv-mon01) или полный адрес сервера. Сохраняем и тестируем подключение кнопкой Save & Test — Grafana должна сообщить, что источник данных доступен.

Шаг 7. Дашборд без нуля — готовые шаблоны

Не обязательно рисовать графики руками с нуля. У Grafana есть каталог готовых дашбордов, и для node_exporter есть проверенный временем вариант с ID 1860 («Node Exporter Full»). Импортируется он за пару кликов: Dashboards → New → Import, вводим номер 1860, выбираем источник данных Prometheus — и получаем готовую панель с загрузкой CPU, памятью, дисками и сетью сразу по всем серверам из job node_exporter.

Для собственных метрик приложений дашборд, конечно, придётся собирать вручную: добавляешь панель, пишешь PromQL-запрос вроде rate(http_requests_total[5m]), чтобы увидеть скорость запросов в секунду, выбираешь тип визуализации (график, gauge, таблица) — и сохраняешь.

Немного PromQL: язык запросов Prometheus

PromQL — это то, ради чего в итоге стоит разбираться с Prometheus: язык запросов, который позволяет не просто смотреть на сырые числа, а вычислять из них осмысленные показатели. Несколько базовых примеров, которые пригодятся почти в любом дашборде:

# Загрузка CPU в процентах по каждому серверу
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# Свободное место на диске в процентах
node_filesystem_avail_bytes / node_filesystem_size_bytes * 100

# Количество серверов, у которых Prometheus не может собрать метрики
count(up == 0)

Метка instance здесь — это адрес цели (например, 192.168.10.21:9100), а функция rate() считает скорость изменения counter-метрики за указанный интервал времени. Это ключевое отличие Prometheus от привычных снапшотов: большинство метрик — это счётчики, которые растут монотонно, а осмысленные графики строятся именно через производную от них.

Другие экспортёры экосистемы

node_exporter закрывает только системные метрики. Для остального есть отдельные готовые экспортёры, которые работают по тому же принципу — отдают метрики по HTTP, а Prometheus их забирает:

  • mysqld_exporter — метрики MySQL: количество соединений, медленные запросы, репликация.
  • blackbox_exporter — проверка доступности сайтов и служб снаружи, аналог simple check в Zabbix, но с поддержкой HTTP, TCP, ICMP и DNS проверок.
  • cadvisor — метрики контейнеров Docker: использование CPU, памяти и сети по каждому контейнеру отдельно.

Каждый добавляется в prometheus.yml отдельным блоком job_name — принцип конфигурации всегда один и тот же, меняются только адрес и порт цели.

Безопасность доступа

По умолчанию и Prometheus, и Grafana поднимаются без TLS и с открытым портом на всю сеть 192.168.10.0/24. Для лабораторного стенда это приемлемо, но для прод-окружения стоит как минимум закрыть порт 9090 firewall-ом снаружи сегмента мониторинга (сам Grafana обращается к нему по localhost или внутри VPN), а на Grafana включить аутентификацию через LDAP или OAuth вместо локальных учёток, если в компании уже есть корпоративный домен itpages.lab.local с централизованной авторизацией.

Правила алертинга

Начиная с Prometheus версии 2.x, у него есть встроенный механизм алертов через Alertmanager, но для старта можно обойтись и алертами на стороне Grafana — это проще для небольшой команды. В разделе Alerting → Alert rules создаётся правило с условием, например «средняя загрузка CPU выше 85% в течение 5 минут», и указывается контакт-пойнт — Telegram, email или webhook. Если нужен полноценный Alertmanager с группировкой и подавлением дублей алертов, его стоит развернуть отдельным systemd-сервисом рядом с Prometheus на srv-mon01 и прописать адрес в блоке alerting файла prometheus.yml.

Альтернативный, более «нативный» для Prometheus путь — описывать правила прямо в отдельном YAML-файле и подключать его директивой rule_files в prometheus.yml. Так выглядит правило, которое сработает, если сервер не отвечает на scrape дольше двух минут:

groups:
  - name: instance_alerts
    rules:
      - alert: InstanceDown
        expr: up == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "{{ $labels.instance }} недоступен"
          description: "Цель не отвечает на scrape уже более 2 минут"

Такие правила версионируются вместе с остальной конфигурацией и удобно живут в git-репозитории рядом с плейбуками Ansible, которыми ты разворачиваешь сам мониторинг — при накатке новой версии конфига правила алертов обновляются автоматически, без ручного редактирования через интерфейс.

Организация папок и переменные в Grafana

Когда дашбордов становится много — отдельно по серверам, по базам данных, по каждому приложению — их стоит раскладывать по папкам (Dashboards → New folder) и группировать по правам доступа так же, как host groups в Zabbix. Ещё один приём, который сильно экономит время: переменные дашборда (Dashboard settings → Variables). Вместо того чтобы делать отдельный дашборд под каждый сервер, создаётся один шаблон с переменной $instance, значения которой подтягиваются прямо из Prometheus запросом вроде label_values(node_uname_info, instance) — и наверху дашборда появляется выпадающий список, где можно переключаться между srv-web01, srv-db01, srv-mon01, не создавая копии графиков под каждый сервер.

Частые ошибки и как их избежать

  • Забыли, что Prometheus сам ничего не собирает без exporter’а. Многие ожидают, что достаточно поставить сам Prometheus, и метрики появятся сами. На деле для каждого источника данных — сервера, базы, очереди — нужен свой exporter (node_exporter, mysqld_exporter, redis_exporter и так далее), который переводит внутренние показатели в формат, понятный Prometheus.
  • Слишком короткий scrape_interval на большом количестве целей. Если поставить интервал в 1-2 секунды на полсотни хостов, база данных Prometheus (TSDB) начнёт разрастаться очень быстро, а сам сервер — упираться в диск и память. Для серверных метрик 15-30 секунд обычно достаточно; более частый опрос имеет смысл только для узкоспециализированных задач.
  • Хранение «вечно» без ретеншена. По умолчанию Prometheus хранит данные 15 дней, но если увеличить это значение флагом --storage.tsdb.retention.time и забыть проконтролировать место на диске srv-mon01, можно однажды получить полный диск и упавший сервис. Для долгого хранения лучше подключить внешнее хранилище вроде Thanos или VictoriaMetrics, а не просто наращивать retention на локальном диске.
  • Дашборд с десятками панелей и запросом без агрегации. Если построить панель, которая на каждый tick тянет сырые метрики по всем инстансам без функций вроде avg by или sum by, при росте числа серверов такой дашборд начнёт открываться заметно дольше, а сам Prometheus — тратить больше ресурсов на обработку запроса. Привычка сразу группировать метрики по нужным меткам экономит проблемы в будущем, когда серверов станет не три, а тридцать.

Что дальше

Мониторинг имеет смысл продолжить автоматизацией конфигураций: