Сейчас возникли проблемы с исходящим трафиком (объём за два месяца вырос в 4 раза), никак не можем найти виновника.
Как один из вариантов поиска этого самого виновника — решили добавить сбор статистики по DNS-запросам, что бы посмотреть к каким URL выполняются обращения и попробовать найти корреляцию между OUT трафиком с хостов в AWS, и запросами к локальному dnsmasq.
dnsmasq записывает все запросы в локальный файл лога
лог тейлится promtail-ом, который отправляет их на сервер мониторинга в Loki
а Grafana на основании метрик из Loki будет отрисовывать красивенькие дашборды со статистикой
Описанный ниже сетап — больше Proof of Concept, так как и сама Loki ещё активно разрабатывается, и её поддержка в Grafana реализована не полностью.
Чего стоит только добавление Loki как datasource, но… как Prometheus O.o Звучит странно, выглядит ещё интереснее.
Зато, Explore в Grafana теперь поддерживает работу с логами используя функциии агрегации аналогично Prometheus — sum(), rate() и так далее.
Да и promtail за почти год, внезапно, тоже добавил много интересных возможностей, с которыми и ознакомимся сегодня.
Сначала поднимем стек Grafana + Loki + promtail, потом подключим сбор логов с помощью promtail с нашего Production-хоста, и посмотрим как работают функции агрегации, и какие дашборды теперь можно делать.
«Поняслася!»
Содержание
Запуск Loki
Запускать будем из Docker Compose, создаём файл loki-stack.yml:
Запускаем его просто без Docker Compose — у меня там полный стек мониторинга Prometheus, потом добавлю новый promtail нормально, так как сейчас просто смотрим как оно вообще будет работать:
root@bttrm-production-console:/opt/prometheus-client# docker run -ti -v /opt/prometheus-client/promtail-dev.yml:/etc/promtail/promtail.yml grafana/promtail:master-2739551 -config.file=/etc/promtail/promtail.yml
Unable to find image 'grafana/promtail:master-2739551' locally
master-2739551: Pulling from grafana/promtail
...
Status: Downloaded newer image for grafana/promtail:master-2739551
level=warn ts=2019-11-16T09:29:00.668750217Z caller=filetargetmanager.go:98 msg="WARNING!!! entry_parser config is deprecated, please change to pipeline_stages"
level=info ts=2019-11-16T09:29:00.669077956Z caller=server.go:121 http=[::]:9080 grpc=[::]:45421 msg="server listening on addresses"
A pipeline is used to transform a single log line, its labels, and its timestamp. A pipeline is comprised of a set of stages. There are 4 types of stages:
Parsing stages parse the current log line and extract data out of it. The extracted data is then available for use by other stages.
Transform stages transform extracted data from previous stages.
Action stages take extracted data from previous stages and do something with them. Actions can:
Add or modify existing labels to the log line
Change the timestamp of the log line
Change the content of the log line
Create a metric based on the extracted data
Filtering stages optionally apply a subset of stages or drop entries based on some condition.
То есть — строим пайплайн, который состоит из стейджев.
Стейджи бывают 4 типов:
Parsing stages: парсит лог и извлекает данные, которые потом можно передать в дальнейшие стейджи
Transform stages: трансформирует полученные от предыдущих стейджев данные
Action stages: получает данные от предыдущих стейдж и делает что-то:
добавляет или удаляет лейблы
меняет таймштамп
меняет содержимое строки лога
создаёт метрику на основании извлечённых данных
Typical pipelines will start with a parsing stage (such as a regex or json stage) to extract data from the log line. Then, a series of action stages will be present to do something with that extracted data. The most common action stage will be a labels stage to turn extracted data into a label.
Итак, вернёмся к началу — чего мы хотим?
Мы хотим получить от dnsmasq все запросы IN A записей, извлечь из этих запросов имена хостов, и отобразить графиком — к какому доменному имени сколько запросов выполняется.
Значит, надо:
получить все запросы IN A
сохранить каждый в label
и потом подсчитать их
Идём к promtail на Production, и добавляем стейдж в нашу джобу — обновляем конфиг promtail-dev.yml:
описываем стейдж regex, в котором выбираем все строки из лога, в которых есть строка query[A]
далее в запросе создаём регекс группу query, в которую сохраняем строку до первого пробела
оригинал строки: Nov 16 08:23:33 dnsmasq[17597]: query[A] backend-db3-master.example.com from 127.0.0.1
в группе query получим результат: backend-db3-master.example.com
описываем стейдж labels, в котором добавляем label query со значением backend-db3-master.example.com
Запускаем promtail:
root@bttrm-production-console:/home/admin# docker run -ti -v /opt/prometheus-client/promtail-dev.yml:/etc/promtail/promtail.yml -v /var/log:/var/log grafana/promtail:master-2739551 -config.file=/etc/promtail/promtail.yml
level=info ts=2019-11-16T11:56:29.760425279Z caller=server.go:121 http=[::]:9080 grpc=[::]:32945 msg="server listening on addresses"
sum (rate( ( {env="production",query=~".*\\..*"} )[5m] )) by (query)
В query=~".*\\..*" я немного накостылял, что бы убрать из вывода метрики в которых query нет, но должен быть более правильный вариант. Пока «И так сойдёт» (с)
Смотрим:
Агонь!
Так…
В именах хостов, например api.amplitude.com from — остаётся from из лога.