Debian.pro

Блог для пользователей и администраторов Debian


Мониторинг всея сервера over http через сервисы мониторинга сайтов. Пример полезнейшего использования xinetd

Ахтунг. Описанное в статье не является готовым решением. Здесь приведены только примеры того, как можно использовать связку инструментов для выполнения определенной цели.

Есть у меня одна очень больная проблема — мониторинг серверов. Существо я ленивое и заводить отдельный zabbix/nagios/etc под каждого отдельного заказчика я не хочу. Тем более, что мне хочется оперативно узнавать о том, что сломалось, а не таращиться в nagios/zabbix-клиент (а уж тем более — прикручивать отправку sms к каждому инстансу заббикса).
Тем временем в сети валяется:
1) куча сервисов, которые умеют слать смс и письмо, если наш «сайт» внезапно отдал код, отличный от 200-ки.
2) куча скриптов для мониторинга, умеющих выводить свой результат на консоль в подходящем формате.
3) валяющиеся на каждом шагу примеры использования xinetd для отдачи ответа скрипта по http.

Если подумать — то легко понять, что всё это можно скрестить. Делать мы будем следующее:
1) заводим скрипты мониторинга, которые возвращают нам свой результат в формате «0; ok», «2; error text»
2) запускаем эти скрипты через xinetd с доступом по http
3) вспоминаем свой любимый сервис, который может дергать http-ручки и ругаться на результат, отличный от 200-ки. Например, hetzner для своих серверов такой сервис даёт бесплатно. Ну и дружим этот сервис с нашими http-ручками.

В качестве бонуса мы сможем выдавать по http вывод любой захардкоженной заранее в скрипте команды.
Небольшой дисклеймер — мониторинг вещь интимная, поэтому не отдавайте через эти ручки любой ценной информации. Так же я не буду рассматривать первый пункт подробно, потому что скрипты мониторинга стоит писать самостоятельно для своих серверов (примеры тем не менее приведу).
Ещё не имеет смысла описывать 3й пункт — упомяну лишь, что можно использовать мониторинг от hetzner’a, ping-admin и кучу подобных сервисов — а там каждый сделает как ему нравится.

Подробнее я остановлюсь на втором пункте.

Собственно, поехали.

Ставим все нужные пакеты:

root@server:~# apt-get install xinetd bash coreutils

Создаём конфиг для запуска нашего сервиса в файле /etc/xinetd.d/monitoring. Этим конфигом через xinetd мы будем запускать обертку для наших скриптов мониторинга:

service http-monitoring
{
  socket_type = stream
  protocol = tcp
    # сервис будет слушать 1500-й порт:
  port = 1500
    # сервис сможет запускать несколько скриптов параллельно (например, если сделать одновременно 2 запроса):
  wait = no
    # скрипты будут запускаться от пользователя nobody:
  user = nobody
    # при запросе будет запускаться скрипт /usr/bin/http-monitoring.sh (мета-скрипт нашего мониторинга, который генерирует http-ответ):
  server = /usr/bin/http-monitoring.sh
    # максимум 5 параллельных скриптов/запросов
  instances = 5
    # наш сервис не указан в /etc/services:
  type = UNLISTED
    # разрешаем доступ только из определенных подсетей (если мы можем их формализовать - то замените на свои хосты и уберите символ комментария # в начале строки):
  #only_from = 127.0.0.0/8 192.168.0.0/24
}

Дальше нам нужно создать несколько скриптов мониторинга. Я приведу здесь самый примитивный скрипт — он проверяет локальный web-сервер — дергает запрос курлом, и если сервер ответил за 3 секунды — значит всё ок. Если не ответил — он напишет «2; error» (а наш мета-скрипт уже обработает это как нам нужно и изменит код ответа на 500 Internal Server Error).

Сам скрипт я положу в /usr/bin/http-check.sh (не забудьте сделать chmod +x на файл):

#!/bin/bash
# дергаем курлом localhost с таймаутом в 3 секунды.
# таймаут нужен для того, чтобы xinetd не ждал бесконечно, пока скрипт выполнится.
# если получилось - пишем "0; ok"
# если нет - "2; error"
curl -m 3 -s -o /dev/null http://localhost/ && echo "0; ok" || echo "2; error"

Само собой это примитивный скрипт (при помощи него вы даже не сможете проверить код ответа сервера). Возможно, я опишу в будущем более сложные скрипты (а может и зарелизю свой http-checker с блэкджеком под такой мониторинг), но именно из-за простоты он вам должен дать представление о том, что должны делать ваши скрипты мониторинга.

Ну а теперь главная магия — скрипт /usr/bin/http-monitoring.sh
Так же не забываем сделать на него chmod +x.
Сам скрипт в моём случае выглядит примерно так:

#!/bin/bash
# создаём переменную $http_body, в которой будет содержаться текст, который мы будем отдавать по http после запроса:
http_body=$(
    x=0;
# парсим заголовки, пришедшие от HTTP-клиента. Нас интересуют http-метод и урл запроса:
    while read I[$x] ; [ ${#I[$x]} -gt 1 ]; do
        METHOD=$(echo $I[0] |cut -d" " -f1)
        REQUEST=$(echo $I[0] |cut -d" " -f2)
# работаем только если к нам пришли с GET:
        if [[ ${METHOD} = "GET" ]]; then
# обрабатываем содержимое переменной REQUEST (по сути - урла, который у нас спросили):
            case "$REQUEST" in
# для корня отдаём список всех мониторингов, которые мы завели (сам собой, мы описываем этот список ручками):
                "/")
                    echo "Available modules are: /who, /test, /top"
                    ;;
    
# для урла /who запускаем команду who:
                /who)
                    who
                    ;;
    
# для /top выводим один раз содержимое top'a:
                /top)
                    top -b -n 1
                    ;;
    
# для урла /test запускаем наш скрипт http-мониторинга:
                /test)
                    /usr/bin/http-check.sh
                    ;;
    
# для всех остальных урлов выводим специально отформатированный текст, который потом будет обработан как 404-я страница:
                *)
                    echo "404; This module not found"
                    ;;
# завершаем наши циклы:
            esac
        fi
# tr здесь нужен для того, чтобы многострочный вывод команд отправлялся по http как многострочный.
    done | tr "\r\n" "\n" )

# обрабатываем первый символ вывода команды:
# если первый символ "2" - то страница будет отдана со статусом 500 Internal Server Error
# если первый символ "4" - то страница будет отдана со статусом 404 Not Found
# если первый символ любой другой - то отдаём контент с кодом 200 OK
status_indicator=$(echo $http_body | head -c 1)
if [[ ${status_indicator} == "2" ]]; then
    echo "HTTP/1.0 500 Internal Server Error"
elif [[ ${status_indicator} == "4" ]]; then
    echo "HTTP/1.0 404 Not Found"
else
    echo "HTTP/1.0 200 OK"
fi

# выводим нужные для обработки ответа нашего сервера http-клиентом (в том числе с этими заголовками страница будет корректно работать в почти любом браузере).
# Название нашего сервера, content-type, чтобы браузер знал, что мы посылаем ему именно текст без html-верстки, заголовок закрытия соединения (само собой, наша конструкция не поддерживает keep-alive) и заголовки, запрещающие любое кеширование на стороне браузера:
echo -e "Server: bash-mon
Content-Type: text/plain
Connection: close
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
"

# собственно, выводим содержимое переменной $http_body в которой у нас содержится вывод команды, которую мы запустили для запрошенного урла.
echo -e "$http_body"

Когда мы создадим 3 нужных файла, нужно перезапустить xinetd:

root@server:~# /etc/init.d/xinetd restart

Свои логи (по крайней мере в дебиане и убунтах) xinetd пишет в /var/log/syslog, так что если что-то не работает — смотрите куда-то в районе

root@server:~# grep xinetd /var/log/syslog | tail -20

Ну и проверяем то, что мы натворили. В моём случае nozdormu — это сервер, над которым я издевался:

inky@laptop:~$ curl -v http://nozdormu:1500/test
...
< HTTP/1.0 500 Internal Server Error
< Server: bash-mon
< Content-Type: text/plain
< Connection: close
< Cache-Control: no-cache, no-store, must-revalidate
< Pragma: no-cache
< Expires: 0
<
2; error
* Closing connection #0

(да, мой web-сервер отдыхает =))

inky@laptop:~$ curl -v http://nozdormu:1500/who
...
< HTTP/1.0 200 OK
...
<
root pts/1 Sep 7 13:46 (censored)
root pts/0 Sep 7 13:44 (censored)
root pts/3 Sep 7 14:37 (censored)
root pts/4 Sep 7 15:52 (censored)
inky@laptop:~$ curl -v http://nozdormu:1500/foo
...
< HTTP/1.0 404 Not Found
...
404; This module not found

Строго говоря, приведенный мною здесь скрипт полностью работает — его можно смело копипастить. Вам нужно только правильно описать свои урлы и скрипты мониторинга внутри esac.
Помните, что в описанном примере эта конструкция доступна снаружи всем желающем. Здесь нет никакой авторизации, проверки заголовка Host и прочих вкусностей. Конечно, из строчек вида «0; у нас тут всё хорошо» вряд ли можно сделать какие-то выводы о сервере, но если вы действительно сделаете публично доступным вывод команды top — это может дать атакующему ваш сервер некоторую полезную для него информацию. Поэтому подходите крайне аккуратно к доступным для запуска скриптам.
Так же в скриптах лучше настроить какие-либо таймауты на длительность выполнения. И не стоит запускать так скрипты, которые потенциально могут скушать много вычислительных ресурсов сервера (ddos-атаки, да).

Ну а вообще, само собой, всё это можно использовать не только для мониторинга. На некоторых серверах у меня написаны скрипты, которые перезапускают всё нужное на сервере, чтобы оживить его — я могу дернуть такой скрипт с любого компьютера или телефона, даже если мой ssh ключик где-то отдыхает вдали от меня. Само собой, такие скрипты у меня наглухо запаролены и доступны только по https.
На других серверах у меня просто написаны скрипты, которые парсят логи и выводят нужную информацию.

В общем, поле действия тут огроменное. Главное, не забывать предохраняться, да)
Ну и не забывайте, что эта штука никогда не заменит вам старый добрый ssh.


Комментариев пока нет.

Написать комментарий