Zabbix на Docker-хостах: почему мы ушли на Prometheus и Grafana
Перевели мониторинг Docker-инфраструктуры клиента с Zabbix на Prometheus+Grafana: pull-модель сбора метрик органично ложится на среду с ephemeral-контейнерами.
Prometheus и Grafana 3.x набирают популярность как стек метрик для контейнерных сред в начале 2016 года
Несколько недель назад мы обновили Docker до 1.10 на инфраструктуре одного из клиентов на сопровождении. Параллельно копилась другая проблема: Zabbix, который мониторил эти хосты, начал вести себя странно - не в смысле падений, а в смысле того, что данные по контейнерам получались неполные и запоздалые. Это был хороший момент, чтобы пересмотреть подход к мониторингу в целом.
В чём конкретно ломался Zabbix
Zabbix работает по push-модели с агентом на каждом хосте. Агент собирает метрики и отправляет на сервер. Для классических физических и виртуальных серверов это нормально: хост живёт месяцами, у него постоянный IP, агент зарегистрирован и всё идёт по расписанию.
С Docker ситуация другая. Контейнеры запускаются и останавливаются в ходе деплоев, при автомасштабировании, в CI-пайплайнах. У контейнера нет постоянного IP - точнее, он есть внутри Docker-сети, но это не тот IP, по которому Zabbix умеет регистрировать агент. В итоге:
- Контейнер поднялся. Zabbix не знает о нём, пока не добавишь хост руками или через LLD-правило, которое срабатывает с задержкой.
- Контейнер упал и поднялся на другом хосте. В Zabbix висит старый хост со статусом unreachable, новый нужно добавлять заново.
- Метрики самих контейнеров. Через cAdvisor с Zabbix-интеграцией - можно, но кривовато. Нужны кастомные скрипты, шаблоны, которые надо поддерживать вручную.
Мы гоняли такую схему через Zabbix UserParameters и внешние скрипты несколько месяцев. Работало, но каждый раз при изменении инфраструктуры требовало ручного вмешательства. На инфраструктуре в 20-30 контейнеров это ещё терпимо. На 80+ - нет.
Почему Prometheus, а не InfluxDB+Telegraf
На момент, когда мы начали смотреть на альтернативы, популярны были два направления: InfluxDB с Telegraf как агентом-коллектором и Prometheus как самостоятельная система мониторинга со своей pull-моделью. Мы смотрели на оба.
InfluxDB + Telegraf - нормальный стек, Telegraf умеет собирать Docker-метрики через Docker Remote API. Но это всё та же push-схема: Telegraf-агент на хосте толкает данные в InfluxDB. Для нас это не решало основную проблему - регистрацию новых контейнеров.
Prometheus использует pull-модель: сервер сам ходит к экспортерам по HTTP и забирает метрики. Экспортер - это просто HTTP-эндпоинт, который отдаёт метрики в текстовом формате. Для Docker-хостов есть cAdvisor, который поднимается как контейнер и сразу экспортирует метрики всех контейнеров на хосте. Prometheus раз в 15 секунд ходит к cAdvisor - и получает актуальную картину по всем контейнерам, включая те, что только что запустились.
Ключевой момент: Prometheus не нужно знать о контейнерах заранее. Он знает о cAdvisor на хосте, а cAdvisor уже разбирается с контейнерами сам. Это принципиально меняет операционную нагрузку.
Что поставили и как это выглядит
Стек получился такой:
- node_exporter на каждом хосте - метрики CPU, памяти, дисков, сети на уровне ОС.
- cAdvisor на каждом хосте как контейнер - метрики по каждому контейнеру.
- Prometheus 0.17 как центральный сервер - хранение метрик и алертинг через Alertmanager.
- Grafana 2.6 как дашборд. (Grafana 3.0 пока в бете, стабильный релиз на подходе, но в продакшн ставить рано.)
Конфиг Prometheus для двух хостов выглядит примерно так:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'node'
static_configs:
- targets:
- 'host1.internal:9100'
- 'host2.internal:9100'
- job_name: 'cadvisor'
static_configs:
- targets:
- 'host1.internal:8080'
- 'host2.internal:8080'
cAdvisor поднимается одной строкой:
docker run -d \
--name=cadvisor \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:rw \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
google/cadvisor:latest
После этого http://host1.internal:8080/metrics сразу отдаёт метрики по всем контейнерам - без дополнительной настройки, без регистрации.
Grafana: вопросы к дашбордам
Grafana 2.6 работает, но дашборды для Prometheus/cAdvisor пришлось строить самим. Grafana.net с каталогом готовых дашбордов только появляется, и на русскоязычных проектах искать их не приходится. Потратили день на построение базовых дашбордов:
- Обзор кластера: загрузка CPU и памяти по хостам, количество контейнеров.
- Детальный вид по хосту: все контейнеры, потребление ресурсов в динамике.
- Алерты: CPU хоста выше 80%, свободная память ниже 512 МБ, контейнер в состоянии OOMKilled.
PromQL - язык запросов Prometheus - поначалу непривычный. Не SQL, не InfluxQL. Но базовые паттерны берутся быстро. Пример - топ-5 контейнеров по потреблению CPU за последние 5 минут:
topk(5, rate(container_cpu_usage_seconds_total{image!=""}[5m]))
Что не понравилось
Честно: Prometheus сейчас - молодой проект, версия 0.17, и это ощущается.
Alertmanager - отдельный бинарь, конфиг в отдельном файле. Логика группировки и дедупликации алертов есть, но документация местами скудная. Потратили время на разбор.
Долгосрочное хранение - Prometheus хранит данные локально, retention по умолчанию 15 дней. Для трендов на месяц и квартал нужно либо увеличивать retention и объём диска, либо смотреть в сторону remote storage. Решения для этого только начинают появляться.
Service discovery при добавлении новых хостов - пока ручная правка конфига и reload. Поддержка Consul и EC2 в Prometheus есть, но для нашей инфраструктуры мы её ещё не настроили.
Текущий статус
Перевели два кластера - итого около 90 контейнеров. Prometheus опрашивает cAdvisor каждые 15 секунд и никакой ручной работы при деплоях не требует. Когда при нагрузке поднялись дополнительные контейнеры, Prometheus просто начал собирать с них метрики - мы это заметили уже по дашборду, не по событию регистрации.
На Zabbix переводить обратно не планируем. Он остался на legacy-хостах без Docker, где push-модель нормально работает. Разные задачи - разные инструменты.