Зачем нужен отдельный стек мониторинга

«Сервис упал — нам позвонил клиент» — это не мониторинг, это катастрофа. Prometheus + Grafana — де-факто стандарт для observability в 2026 году. Они бесплатны, хорошо интегрируются с Kubernetes и Docker, и у них огромная экосистема готовых экспортёров.

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

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

  • Prometheus — сбор и хранение метрик по pull-модели
  • Alertmanager — маршрутизация и отправка алёртов
  • Grafana — визуализация и дашборды
  • Экспортёры — node_exporter, blackbox_exporter, postgres_exporter и др.

Установка через Docker Compose

yaml# docker-compose.monitoring.yml
version: '3.8'
services:
  prometheus:
    image: prom/prometheus:v2.50.0
    restart: unless-stopped
    volumes:
      - ./prometheus:/etc/prometheus
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=30d'
      - '--web.enable-lifecycle'
    ports:
      - "127.0.0.1:9090:9090"

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

  grafana:
    image: grafana/grafana:10.3.0
    restart: unless-stopped
    environment:
      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
      GF_USERS_ALLOW_SIGN_UP: false
    volumes:
      - grafana_data:/var/lib/grafana
    ports:
      - "127.0.0.1:3000:3000"

  node_exporter:
    image: prom/node-exporter:v1.7.0
    restart: unless-stopped
    pid: host
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.rootfs=/rootfs'
      - '--path.sysfs=/host/sys'

volumes:
  prometheus_data:
  grafana_data:

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

yaml# 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: ['node_exporter:9100']

  - job_name: 'app'
    static_configs:
      - targets: ['app:8080']
    metrics_path: /metrics

  - job_name: 'blackbox-http'
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets:
          - https://myapp.example.com
          - https://myapp.example.com/api/health
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: blackbox:9115

Правила алёртов

yaml# prometheus/alerts/system.yml
groups:
  - name: system
    rules:
      - alert: HighCPUUsage
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Высокая нагрузка CPU на {{ $labels.instance }}"
          description: "CPU usage: {{ $value | printf \"%.1f\" }}%"

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

      - alert: ServiceDown
        expr: up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Сервис недоступен: {{ $labels.job }}"

Настройка Alertmanager со Slack

yaml# alertmanager/alertmanager.yml
global:
  slack_api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'

route:
  group_by: ['alertname', 'severity']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: 'slack-critical'
  routes:
    - match:
        severity: critical
      receiver: 'slack-critical'
    - match:
        severity: warning
      receiver: 'slack-warnings'

receivers:
  - name: 'slack-critical'
    slack_configs:
      - channel: '#alerts-critical'
        title: '🔴 {{ .GroupLabels.alertname }}'
        text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'

  - name: 'slack-warnings'
    slack_configs:
      - channel: '#alerts-warnings'
        title: '⚠️ {{ .GroupLabels.alertname }}'

Готовые дашборды Grafana

Не надо строить дашборды с нуля — импортируйте готовые из Grafana Dashboard Library:

  • Node Exporter Full — ID: 1860 — системные метрики сервера
  • Docker Containers — ID: 193 — мониторинг контейнеров
  • PostgreSQL — ID: 9628 — метрики базы данных
  • Nginx — ID: 9614 — метрики веб-сервера

Импорт дашборда: Grafana → Dashboards → Import → введите ID. Убедитесь, что выбрали правильный источник данных Prometheus при импорте.

101 оценка
Комментарии 5
ДФ
dfedorovСисадмин25 мин назад

Хорошая статья! Хотел бы добавить про VictoriaMetrics как замену Prometheus — потребляет в 5-7 раз меньше памяти, совместима с PromQL. Для небольших инсталляций отличный выбор.

Ответить
РК
r_kozlovSRE2 ч назад

Совет по алёртам: начинайте с малого числа алёртов, но реагируйте на каждый. Если в команде alert fatigue — всё игнорируют и система мониторинга теряет смысл.

Ответить
ОЗ
o_zaytsevTech Lead4 ч назад

Не забудьте про Loki для логов — отлично дополняет Prometheus+Grafana. Единый интерфейс для метрик и логов удобнее чем прыгать между инструментами.

Ответить
АМ
Алексей Морозов
DevOps-инженер · Москва

7 лет строю infrastructure as code. Последние 4 года — Kubernetes и Docker в production финтех-компаний. Эксперт по observability: Prometheus, Grafana, OpenTelemetry.