Серверное оборудование для бизнеса — надёжные решения для любых задач Подробнее →
Статья

Prometheus + Grafana: мониторинг 100 серверов с нуля

Когда серверов становится больше десяти, мониторинг перестаёт быть опциональным. Когда их сто — он становится вопросом выживания. Prometheus + Grafana сегодня де-факто стандарт для метрик в Linux-инфраструктуре. Расскажу, как поднять полноценный стек с нуля, включая алерты в Telegram.

Архитектура стека

Наш мониторинг состоит из трёх компонентов:

  • Prometheus — собирает и хранит метрики, опрашивая экспортеры по HTTP
  • Grafana — визуализация, дашборды, графики
  • Alertmanager — маршрутизация алертов (Telegram, email, PagerDuty)

На каждом сервере запускается node_exporter, который отдаёт системные метрики на порту 9100.

Node exporter на серверах

Ставим через Ansible или вручную:

wget https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz
tar xzf node_exporter-1.7.0.linux-amd64.tar.gz
cp node_exporter-1.7.0.linux-amd64/node_exporter /usr/local/bin/

# Создаём systemd unit
cat > /etc/systemd/system/node_exporter.service << EOF
[Unit]
Description=Node Exporter
After=network.target

[Service]
User=nobody
ExecStart=/usr/local/bin/node_exporter
Restart=always

[Install]
WantedBy=multi-user.target
EOF

systemctl enable --now node_exporter

Проверяем: curl http://localhost:9100/metrics | head -20

Docker Compose для стека мониторинга

# docker-compose.yml
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:v2.50.0
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=30d'
      - '--storage.tsdb.path=/prometheus'
    ports:
      - "9090:9090"
    restart: unless-stopped

  grafana:
    image: grafana/grafana:10.3.0
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=strongpassword
    ports:
      - "3000:3000"
    restart: unless-stopped

  alertmanager:
    image: prom/alertmanager:v0.27.0
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
    ports:
      - "9093:9093"
    restart: unless-stopped

volumes:
  prometheus_data:
  grafana_data:

Конфигурация Prometheus

# prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['alertmanager:9093']

rule_files:
  - 'alerts.yml'

scrape_configs:
  - job_name: 'node'
    static_configs:
      - targets:
          - 'server-01:9100'
          - 'server-02:9100'
          # ... все 100 серверов
    relabel_configs:
      - source_labels: [__address__]
        target_label: instance
        regex: '([^:]+):.*'
        replacement: '$1'

Для 100 серверов лучше использовать file-based service discovery:

  - job_name: 'node'
    file_sd_configs:
      - files:
          - '/etc/prometheus/targets/*.yml'
        refresh_interval: 30s

Ключевые метрики для алертов

# alerts.yml
groups:
  - name: node
    rules:
      - alert: HighCPU
        expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Высокая нагрузка CPU на {{ $labels.instance }}"

      - alert: LowDiskSpace
        expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 < 10
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Мало места на диске: {{ $labels.instance }}"

      - alert: HighMemory
        expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100 > 90
        for: 5m
        labels:
          severity: warning

Alertmanager + Telegram

# alertmanager.yml
global:
  resolve_timeout: 5m

route:
  group_by: ['alertname', 'instance']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: 'telegram'

receivers:
  - name: 'telegram'
    telegram_configs:
      - bot_token: 'YOUR_BOT_TOKEN'
        chat_id: -1001234567890
        message: '{{ range .Alerts }}{{ .Annotations.summary }}{{ end }}'

Дашборды в Grafana

Не изобретайте велосипед — импортируйте готовый дашборд Node Exporter Full (ID: 1860). В Grafana: Dashboards → Import → введите 1860. Получите готовые графики CPU, RAM, disk, network по всем серверам с возможностью переключения между хостами.

Retention и хранилище

По умолчанию Prometheus хранит данные 15 дней. Мы передали --storage.tsdb.retention.time=30d. На 100 серверов с 15-секундным интервалом рассчитывайте примерно 2−3 ГБ в сутки. За 30 дней — около 70−90 ГБ.

Если нужно больше retention или HA — смотрите в сторону Thanos или VictoriaMetrics. Thanos добавляет object storage (S3) и дедупликацию метрик от нескольких Prometheus-инстансов.

Итог

Стек поднимается за полдня, Ansible на node_exporter пишется за час. Главное — сразу продумать алерты: мониторинг без алертов это просто красивые графики, которые никто не смотрит.

4 Ответа

  1. Работаю с Zabbix лет восемь, но Prometheus с Grafana реально удобнее для современной инфры. Zabbix хорош когда много legacy и Windows, а для Linux-кластеров — Prometheus однозначно.

    1. Можно ещё кастомный экспортер написать буквально за час на Python с prometheus_client, если нужны метрики из своего приложения или стороннего API.

  1. Для HA и долгосрочного хранения стоит добавить Thanos поверх Prometheus. У нас три инстанса Prometheus с Thanos sidecar, данные уходят в S3, всё работает без единой точки отказа уже год.

  1. А docker compose файл из статьи прямо так и запускать? Или надо что-то менять под себя перед первым запуском?