Улучшаем сообщения от мониторинга с помощью cAdvisor-companion

2015/04/21

Слышали ли вы когда-нибудь о такой практике, как “Monitoring Events Enrichment”? Если вкратце, то это практика наполнения дополнительной информацией сообщений от мониторинга, так что на выяснение причины проблемы уходит меньше времени и телодвижений.

Есть даже контора, которая помогает внедрять эту практику на коммерческой основе, у них на сайте есть неплохие примеры того, что и зачем можно добавить к обычному сообщению от Nagios.

Сама эта идея мне очень нравится, и вот после очередного неинформативного сообщения от мониторинга, которое пришло тогда, когда я был далеко от компьютера, и гласило CheckDockerStats CRITICAL: 91% CPU Used!, я решил добавить таким сообщениям полезного контекста.

Конечно, очевидным кандидатом на добавление к сообщению от мониторинга в данном случае является список процессов в контейнере, отсортированных по использованию CPU. Если это не кажется очевидным, то представьте, что вам приходит сообщение от мониторинга, что в каком-то контейнере превышен порог использования CPU/памяти, а вы не у компьютера, и к тому моменту, как вы можете проверить, что же там случилось, контейнер уже вернулся к своему нормальному потреблению ресурсов.

Для обычных проверок check_load и check_memory из пакета Nagios-plugins я добавил топ-5 потребителей ресурсов достаточно легко - обернул стандратные плагины в простенький wrapper на bash, получилось примерно так:

#!/bin/bash
# check_memory wrapper
output=$(/usr/lib/nagios/plugins/check_memory "$@")
status=$?
message=$(echo "$output" | cut -d\| -f 1)
perfdata=$(echo "$output" | cut -d\| -f 2)
echo -n "$message"
if [ 0 -ne "$status" ]; then
  echo
  ps aux --sort -pmem | head -n 5
fi
echo " | $perfdata"
exit $status

При превышении заданных лимитов вывод этого wrapperа получается такой:

root@host:~# /usr/lib/nagios/plugins/check_memory_wrapper.sh -f -C -w 15 -c 10
CRITICAL - 4.9% (1198364 kB) free!
USER       PID %CPU %MEM    VSZ   RSS      TTY  STAT START   TIME COMMAND
traffic+ 28086 11.3 91.7 25970900 22651436 ?    Sl   Mar18 5553:57 /usr/bin/traffic_server -M --httpport 8080:fd=9
haproxy  26404  7.0  0.2 85832    59364    ?    Ss   Mar19 3332:04 /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -D -sf 25137
syslog   25077  0.5  0.1 332568   29764    ?    Ssl  Apr06  109:24 rsyslogd
root     15342  0.1  0.0 84124    15212    ?    S    Mar08   95:21 /usr/bin/perl -w /usr/sbin/ldirectord /etc/ldirectord.cf start
 | TOTAL=24678520KB;;;; USED=23480156KB;20976742;22210668;; FREE=1198364KB;;;; CACHES=980600KB;;;;

и сразу из сообщения о проблеме видно, кто сожрал всю память на сервере.

Для контейнера получить такую информацию сложнее, поскольку:

Поскольку информацию об использовании памяти/CPU я беру по HTTP из cAdvisor, я решил следовать этому же сценарию и для обогащения сообщений о проблемах, и написать свой мини-сервис для получения информации о том, какие процессы запущены в контейнере.

Поскольку сервис получался комплиментарным к cAdvisor, я назвал его cAdvisor-companion.

В общем, алгоритм решения задачи оказался не сложным - достаточно всего лишь пройтись по файловой системе /proc на родительском хосте, собрать данные по всем процессам, и фильтровать их по cgroup.

Поскольку мой сервис должен был собирать в отдельном потоке данные, и при этом отвечать на HTTP-запросы к API, да еще делать все это быстро, я выбрал для реализации не привычный Python, а “стильный, модный, молодежный” Golang.

Сразу скажу, что это решение оказалось удачным, и позволило мне достаточно быстро и просто написать этот небольшой сервис, уложившись меньше чем в 500 строк кода вместе с тестами.

Итогом нескольких дней разработки в свободное от работы время стал сервис, пригодный к разворачиванию в контейнере, которому для работы требуется только read-only доступ к /proc, и который по HTTP API отдает в виде JSON историю запущенных процессов для указанного контейнера.

Подробнее о том, как этот сервис запускать, что из себя представляет API, почему я не стал использовать Docker API, и прочие полезные вещи можно почитать на Github-страничке cAdvisor-companion, ну а я хочу рассказать как я использую этот самописный сервис, и какие у него есть недостатки.

Использую я его как и планировал - получаю список процессов в контейнере в случае сообщений от мониторинга, и вывожу вместе с алертом. Теперь сообщение из начала статьи, которое и побудило меня к написанию своего сервиса, выглядит примерно так:

CheckDockerStats WARNING: 83.32% CPU used!
 USER   PID  %CPU  %MEM      VSZ      RSS   STAT COMMAND
65534  1285  18.3   0.0    18396     1632      S /usr/sbin/nutcracker -v 11 -c /etc/twemproxy/config.yml
 1000 24891   7.5   1.4   299524    99200      S python /path/to/program.py
 1000  4474   7.4   1.4   303356   103416      S python /path/to/program.py
 1000  4468   7.4   1.4   301416   101228      S python /path/to/program.py
 1000  4475   7.4   2.5   382636   181792      S python /path/to/program.py

Проверки использования ресурсов в контейнерах, пример вывода которых я привел выше, я делаю все тем же скриптом check_cadvisor.py, только слегка доработанным для получения данных о процессах от cAdvisor-companion.

Ну а теперь о недостатках:

Несмотря на перечисленные недостатки, сервис со своей задачей справляется, так что если хотите обогатить сообщения от мониторинга полезным контекстом

Tags: Golang CAdvisor CAdvisor-Companion Программирование Monitoring

Categories: IT Russian