Ахтунг. Описанное в статье не является готовым решением. Здесь приведены только примеры того, как можно использовать связку инструментов для выполнения определенной цели.
Есть у меня одна очень больная проблема — мониторинг серверов. Существо я ленивое и заводить отдельный 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 и кучу подобных сервисов — а там каждый сделает как ему нравится.
Подробнее я остановлюсь на втором пункте.
Собственно, поехали.
Ставим все нужные пакеты:
Создаём конфиг для запуска нашего сервиса в файле /etc/xinetd.d/monitoring. Этим конфигом через xinetd мы будем запускать обертку для наших скриптов мониторинга:
{
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 на файл):
# дергаем курлом 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.
Сам скрипт в моём случае выглядит примерно так:
# создаём переменную $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:
Свои логи (по крайней мере в дебиане и убунтах) xinetd пишет в /var/log/syslog, так что если что-то не работает — смотрите куда-то в районе
Ну и проверяем то, что мы натворили. В моём случае nozdormu — это сервер, над которым я издевался:
...
< 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-сервер отдыхает =))
...
< 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)
...
< HTTP/1.0 404 Not Found
...
404; This module not found
Строго говоря, приведенный мною здесь скрипт полностью работает — его можно смело копипастить. Вам нужно только правильно описать свои урлы и скрипты мониторинга внутри esac.
Помните, что в описанном примере эта конструкция доступна снаружи всем желающем. Здесь нет никакой авторизации, проверки заголовка Host и прочих вкусностей. Конечно, из строчек вида «0; у нас тут всё хорошо» вряд ли можно сделать какие-то выводы о сервере, но если вы действительно сделаете публично доступным вывод команды top — это может дать атакующему ваш сервер некоторую полезную для него информацию. Поэтому подходите крайне аккуратно к доступным для запуска скриптам.
Так же в скриптах лучше настроить какие-либо таймауты на длительность выполнения. И не стоит запускать так скрипты, которые потенциально могут скушать много вычислительных ресурсов сервера (ddos-атаки, да).
Ну а вообще, само собой, всё это можно использовать не только для мониторинга. На некоторых серверах у меня написаны скрипты, которые перезапускают всё нужное на сервере, чтобы оживить его — я могу дернуть такой скрипт с любого компьютера или телефона, даже если мой ssh ключик где-то отдыхает вдали от меня. Само собой, такие скрипты у меня наглухо запаролены и доступны только по https.
На других серверах у меня просто написаны скрипты, которые парсят логи и выводят нужную информацию.
В общем, поле действия тут огроменное. Главное, не забывать предохраняться, да)
Ну и не забывайте, что эта штука никогда не заменит вам старый добрый ssh.
Комментариев пока нет.