Prometheus 0.16: попробовали pull-модель мониторинга для Docker-контейнеров
SoundCloud открыл Prometheus - pull-based мониторинг с метками для контейнеров. PromQL непривычен после Zabbix, но labels для фильтрации метрик - именно то, чего не хватало.
Prometheus 0.16 вышел из внутреннего проекта SoundCloud в open source - pull-based мониторинг с многомерными метками, ориентированный на динамические контейнерные среды
SoundCloud выложил Prometheus в open source - системный мониторинг, который они писали внутри под свою контейнерную инфраструктуру. Версия 0.16, GitHub, Apache 2.0. Мы потратили несколько вечеров на то, чтобы разобраться что это вообще такое и зачем это нам - при том что Zabbix работает и особо не жалуется.
Коротко: Prometheus делает мониторинг принципиально иначе. После нескольких часов с ним ощущение двойственное - одновременно "наконец-то" и "придётся переучиваться".
Pull вместо push
Первое, что сбивает с толку после Zabbix: Prometheus сам ходит к сервисам и собирает метрики. Никаких агентов, которые шлют данные на сервер. Вместо этого - каждый сервис поднимает HTTP-эндпоинт (обычно /metrics) в текстовом формате, и Prometheus регулярно его опрашивает.
Для контейнерных сервисов это нетривиально переосмыслить. В Zabbix агент сидит на хосте и знает о контейнерах через Docker API - мы это настраивали в августе. Prometheus же ожидает, что каждый контейнер сам знает о своих метриках и умеет их отдавать. Для приложений это значит добавить клиентскую библиотеку (есть для Go, Python, Java, Ruby - список небольшой, но покрывает основное). Для инфраструктурных метрик - поднять отдельный node_exporter или cAdvisor.
cAdvisor от Google здесь ключевой компонент. Он запускается как контейнер рядом с остальными, мониторит всё что крутится на хосте и выдаёт метрики по каждому контейнеру в формате Prometheus. CPU, память, сеть, блочный I/O - и для каждой метрики автоматически добавляются labels с именем контейнера, образом, ID. Prometheus это забирает, и дальше можно спрашивать.
Почему labels - это не просто теги
В Zabbix контейнер - это хост. Хост имеет элементы данных. Чтобы сравнить CPU двух контейнеров - нужно выбрать оба хоста на графике или строить агрегирующий элемент вручную.
В Prometheus каждая метрика - это временной ряд с набором пар ключ-значение. Метрика container_cpu_usage_seconds_total для нашего тестового стенда выглядела примерно так:
container_cpu_usage_seconds_total{name="web_1",image="myapp:latest",id="abc123"} 42.3
container_cpu_usage_seconds_total{name="worker_1",image="myapp:latest",id="def456"} 18.7
container_cpu_usage_seconds_total{name="nginx_1",image="nginx:1.9",id="ghi789"} 3.1
Один запрос на PromQL - и можно получить суммарный CPU по всем контейнерам с образом myapp:latest, или сравнить потребление по отдельным контейнерам, или сгруппировать по хосту. Без заранее заготовленных агрегаций, без ручного создания элементов данных.
Для нашего Docker Swarm стенда это особенно ощутимо: контейнеры размазаны по нескольким хостам, имена повторяются (web_1 есть на хосте-1 и на хосте-2). В Zabbix пришлось бы городить префиксы в именах или отдельные хосты. В Prometheus добавляешь label instance - и автоматически знаешь откуда метрика, независимо от того на каком хосте контейнер.
PromQL: мощно, но порог входа реальный
Язык запросов Prometheus - это отдельная история. Синтаксис непохож ни на SQL, ни на что-то другое что мы регулярно используем.
Простое - понятно: container_memory_usage_bytes вернёт текущее потребление памяти по всем контейнерам. С фильтром по имени: container_memory_usage_bytes{name="web_1"}. Это осваивается за полчаса.
Сложнее - rate и производные. Чтобы получить скорость потребления CPU (не накопленные секунды, а проценты за последнюю минуту): rate(container_cpu_usage_seconds_total[1m]) * 100. Логика понятна, но когда это выражение начинает усложняться агрегациями типа sum by (name) - новичку легко запутаться.
Документация есть, она подробная, но примеры в основном для Go-разработчиков SoundCloud - инфраструктурные кейсы приходится искать отдельно.
Что не понравилось на старте
Алертинг. В Prometheus 0.16 он есть, но через отдельный Alertmanager. Это ещё один процесс, ещё одна конфигурация. Zabbix - монолит, всё в одном, настройки через UI. Тут - несколько сервисов, YAML-конфиги, перезапуск чтобы применить изменения. Для тестовой среды терпимо, для production-мониторинга нужно привыкнуть к этому подходу.
Хранение. Prometheus хранит данные локально в своей базе. Репликации нет, бэкапа из коробки нет. Для серьёзной эксплуатации это вопрос, который надо решать отдельно.
Авто-обнаружение контейнеров. cAdvisor метрики отдаёт, но если контейнер появился - Prometheus должен о нём знать. Конфигурацию targets надо либо обновлять вручную, либо настраивать service discovery. Docker-интеграция в 0.16 через file-based SD: Prometheus читает JSON-файл со списком таргетов, который кто-то должен поддерживать актуальным. Не так удобно как хотелось бы, но работает.
Где мы сейчас
Тестовый стенд - несколько Docker-хостов с cAdvisor на каждом, Prometheus собирает метрики, Grafana сверху рисует графики. Связка работает, контейнерные метрики с labels выглядят именно так как нужно.
В production пока не идём. Причины простые: Alertmanager надо настроить нормально, надо разобраться с хранением и надёжностью, надо обучить команду PromQL хотя бы на базовом уровне. Zabbix никуда не делся и справляется с тем что уже настроено.
Но для новых managed-проектов с контейнерами Prometheus выглядит убедительнее чем попытки адаптировать Zabbix к динамической инфраструктуре. Там метка на контейнер вместо отдельного хоста в базе - это не деталь реализации, это другой способ думать о мониторинге. И этот способ лучше ложится на то, как работают контейнеры.