Предыстория
Исторически так сложилось, что я занимаюсь разработкой в digital‑агентстве полного цикла в центре столицы. Знаете, бывают такие компании, которые делают контекст, smm, seo, пилят или допиливают сайты, всяческие автоматизации, интеграции b2b, b2c и т. д.? Вот в такой компании и работаю.
У моей команды много сайтов на поддержке, а в нашей стране много праздников. В праздники интернет продолжает работать, реклама продолжает крутиться, люди продолжают покупать на сайтах, а значит и сайты должны функционировать 24/7 вне зависимости от цвета дня календаря. А как узнать, что все в порядке, если ты жаришь шашлык на даче в 100 км. от столицы? Все очевидно — нужен сервис, который будет мониторить сайты и пинговать дежурного программиста, если что‑то пошло не так.
Честно скажу, сперва я, как ленивый умный человек, решил воспользоваться сторонним сервисом. Погуглил, почитал обзоры на Хабре, посмотрел сервисы и не впечатлился. Не то, что бы ничего интересного не нашел. Но не нашел рабочего продукта, который бы меня устраивал на все 100%. Печально конечно, однако время было перед Новым Годом, я был в отпуске и мне пришла в голову мысль: «А почему бы мне не написать свой сервис для мониторинга сайтов с блекджеком и прочими радостями?» Что еще делать человеку в праздники?
Требования к сервису
Я посмотрел старые кейсы, в которых что‑то пошло не так и решил мониторить только то, что нужно мне, а именно:
HTTP ответ сервера (работает/не работает(и как именно не работает))
Срок действия сертификата (бывало заканчивался сертификат в самый неудобный момент)
Инфу о доменном имени (бывало, что и домен заканчивался внезапно)
Время отклика от сервера (достаточно часто на крупных высоконагруженных проектах эта метрика нужна)
Для минимально рабочей версии вполне достаточно. Алгоритм действий следующий: будем смотреть все это, логировать и класть в базу данных. Если что‑то пошло не так — напишем всем подписанным на этот сайт в телеграм. Ну и сделаем какой‑нибудь веб‑интерфейс с авторизацией в котором можно будет посмотреть логи. Фронт пусть будет Vue3+VUEX на фронте, а с бэком пусть по рест‑апишке общается. Бэк традиционный php+mySql. Звучит достаточно просто. Вперед!
Авторизация
В этом проекте, я мог делать все, что хочу, и не делать то, чего не хочу. Например, мне не хотелось писать свою регистрацию. Даже брать свою уже готовую не хотелось. «Прикрутить стороннюю — вот отличное решение!» — подумал я. Пусть какой‑нибудь другой сервис забирает на себя все эти истории с восстановлением пароля, заходов с непонятных мест и т. д. Я опросил коллег и мой выбор пал на Яндекс (у 100% людей опрошенных оказался аккаунт, который они используют для музыки/такси/шеринга или доставки еды).
Не буду сильно углубляться в детали реализации, официальная документация вполне понятна, хоть и разбросана среди всех документаций Яндекса. Просто основные моменты со ссылками:
Заходим в на страничку, заводим там новое приложение. Получаем ClientID, ClientSecret приложения и указываем адрес, на который перенаправить человека после авторизации.
При помощи ClientID получаем код подтверждения для получения токена пользователя пользователя (посылаем его по ссылке вида: https://oauth.yandex.ru/authorize?response_type=code&client_id=YOU_CLIENT_ID&redirect_uri=URL_TO_REDIRECT)
Имея код подтверждения (он приходит в виде гет-параметра после редиректа на URL_TO_REDIRECT), ClientID и ClientSecret, меняем их на токен пользователя при помощи POST-запроса
-
Теперь, когда у нас есть токен, поменяем его на данные о пользователе. В нашем случае это аватар и логин. Оформляем по вкусу. ( Я в тот вечер похоже пересидел в документации Яндекса и мои вкусы стали специфичными.)
База данных
Итак, пользователь есть, нам надо его где‑то хранить. Поэтому самое время подумать над структурой базы данных. У меня вышло 4 таблички:
users — хранит необходимые данные про пользователя;
sites — название сайта, когда домены/сертификаты заканчиваются;
siteToUser — чтобы понимать кто какие сайты смотрит;
errLog — если ошибка‑пишем, если исправилась тоже пишем.
В 1-ю табличку кладем то, что получили в результате авторизации. Осталось только прикрутить к юзеру телеграм.
Telegram
Про создание ботов для телеграм на php очень много всего написано, я взял 1-ю попавшуюся статью (вроде бы эту) и сделал так же, как написано в ней.
Теперь, когда у нас есть бот, нам надо как‑то связать его с пользователем, для этого юзер берет в ЛК число (которое идентифицирует его) и шлет боту.
Бот посмотрит есть ли он в базе и добавит нас, если будет совпадение.
Если честно, это лишнее движение мне не нравится. С точки зрения юзабилити «скопируй‑пошли» как то не очень. Однако, к моему сожалению, я не придумал другого механизма. Бот не умеет писать первый и надо как‑то понять, кто именно написал боту.
Теперь, когда юзер готов осталось сделать так, чтобы он добавил себе список сайтов, которые хочет мониторить.
Cписок сайтов
Реализация списка сайтов сводится к реализации обычного CRUD (CRD если быть точнее). Добавляем, если нет такого сайта, сразу смотрим его статус и пишем в базу. Если же есть, то просто линкуем юзера и сайт в таблице sitesToUsers. Удаляем просто отлинковкой (все-равно если за сайтом никто не смотрит, то он и не проверяется). Не забываем спросить, точно ли пользователь хочет удалить сайт.
Один момент мне запомнился на этом этапе - написание регулярки для валидации корректности написания доменного имени сайта. Регулярные выражения для меня подобны походу к стоматологу. Регулярная необходимость без которой хотелось бы обойтись. В этот раз вышло как-то так:
const reg = /^http([s]{0,1})\:\/\/([\wёa-я-]{2,}\.)+[\wёa-я-]{2,}$/i
Список сайтов есть. Осталось получить данные по ним.
Чтобы не превращать статью а лонгрид, я не буду вдаваться в подробности реализации, просто расскажу как получал данные и оставлю ссылки на документацию. Если по какому-то моменту появятся вопросы - я отвечу в комментариях, или сообщениях.
HTTP
сделаем массив со всеми возможными кодами ответов
получим ответ при помощи curl (CURLINFO_HTTP_CODE)
PING
По факту пинг — это время ответа сервера, как известно curl тоже умеет это делать, поэтому не будем ничего придумывать, а просто добавим в предыдущий запрос получение еще одного параметра (CURLINFO_CONNECT_TIME_T)
HTTPS
SSL сертификат получаем с помощью контекста потоков и разбираем его при помощи openssl_x509_parse. В итоге нам интересен параметр validTo_time_t который мы и получаем. Результат выглядит так:
WHOIS
Чтобы получить информацию о домене, посылаем TCP запрос (43-й порт) на WHIOS-сервер. Для разных доменных зон, бывают разные WHOIS сервера.
Логика следующая: мы берем домен смотрим какая у него там зона и шлем уже на нужный сервер. В ответе получаем текст, из которого в результате парсинга достаем значение paid-till. (практически для всех доменов этот параметр есть)
В тексте с ответом приходит еще ссылка на правила использования данного WHOIS сервера (для зоны ru выглядит так)
CRON
Теперь, когда мы научились получать данные, надо понять как часто их нужно актуализировать.
Количество дней до окончания сертификата и домена обновляется раз в сутки, поэтому проверяем все сайты раз в сутки на эти значения и если что-то обновилось - актуализирует в базе данных. Предупреждаем всех причастных за 5 дней до окончания сроков. Стараемся уложиться в лимиты для запросов к WHOIS серверам.
Яндекс проверяет http статус сайта раз в 15 минут и если сайт еще через 15 минут лежит - отключает рекламу (если верить техподдержке). Мы делаем быстрее. Статус обновляется раз в 11 минут и если что-то идет не так дежурный программист сразу приступает к решению вопроса. На практике, в 90% случаев сайт поднимается до того, как Яндекс успел среагировать.
Еще немного интерфейса
На этом можно было бы и закончить, но мне (да и нашим клиентам) порой интересна статистика, поэтому мы ее покажем.
-
текущее состояние сайта (данные актуализируются, когда мы выбираем сайт в списке сайтов)
-
данные за месяц (помечаем дни без ошибок зеленым, дни с ошибками - красным)
-
Ну и конечно же детализация по дню. Лог выводим просто в окошке, если что-то не так раскрашиваем.
Для отображения пинга используем обычный график от chart.js
Результат:
Помните в самом начале, я описывал требования к минимально рабочей версии? Так вот, все они выполнены. Время от времени выскакивают баги, но их все меньше и они достаточно быстро исправляются. В целом вышла достаточно удобная штука, которая мониторит и говорит, если что-то не так. Это решает 99% наших вопросов нашего отдела по мониторингу.
Однако есть еще и другие отделы, поэтому я планирую сделать несколько доработок:
Необходимо осуществлять проверку из разных точек (для начала возьмем города-миллионники в России)
Необходимо будет сделать возможность отслеживания статуса отдельных разделов сайтов (мы же живем в эпоху микросервисов)
Люди любят отчеты, надо добавить рассылку писем с еженедельным и ежемесячным отчетом.
Подумать над масштабированием базы данных. Сейчас все вертится на хостинге, который мы используем как песочницу. Однако, если возникнет необходимость придется поиграть с выделенным серверами и докерами-кубернетисами. (С другой стороны, кому интересно что там было с сайтом несколько месяцев назад? Важно то, что здесь и сейчас) Посмотрим по обстоятельствам.
Конечно же нужно адаптировать сервис под мобилку.
Итоги
Теперь нам гораздо проще отслеживать состояние и обеспечивать бесперебойную работу сайтов наших клиентов 24 часа 7 дней в неделю не взирая на праздники и прочие обстоятельства. Все довольны.
Для тех, кто дочитал до конца ссылка на результат с ограничением в 1 сайт для добавления. Пользуйтесь.
Комментарии (17)
aborouhin
00.00.0000 00:00+3А чем не устроил Zabbix? Все перечисленные задачи решает или из коробки или легко гуглящимися шаблонами / скриптами. Интеграция с Телеграм есть готовая. Ну и при последующем расширении объём велосипедостроения будет явно меньше. Разве что авторизации через Яндекс нет :) , но эта идея как-то и так не кажется самой удачной...
Ну или какой-нибудь exporter к Prometheus запилить, если стильно, модно... :) Всё-таки не полностью с нуля свой велосипед (P.S. комментом ниже подсказали готовый exporter для этого)
Kuznetsov_pa
00.00.0000 00:00Автор разработчик, и это ему было быстрее сделать чем заниматься с забиксом. В итоге все равно придут к системе мониторинга
babilonsuxx Автор
00.00.0000 00:00Ну и помимо моего коммента ниже про обучение джунов могу добавить, что конечный продукт будет проверять доступность из разных геолокаций. Поправьте меня, если я ошибаюсь, но на сколько я помню забикс не умеет так делать из коробки. Все-равно придется дописывать, но только чужой код.
aborouhin
00.00.0000 00:00А как Вы это собирались делать своими силами? Всё равно надо в каждой такой геолокации иметь сервер, с которого осуществляется проверка... Ну а на него и zabbix agent поставить можно.
babilonsuxx Автор
00.00.0000 00:00Тут тоже все просто. Моя команда растет и необходим проект, который был бы точкой роста для джунов. Не сильно объемный, но чтобы включал стек с которым им придется постоянно работать. Таким образом, помимо мониторинга, я решаю вопрос с обучением ребят. Мне кажется - это нормальный подход. Можно поиграть со сторонними апишками (например мы очень много работаем с апи директа, поэтому яндекс), пописать свою апишку, есть фронтенд (vue+vuex, который мы используем для внутренней разработки), есть бэкенд, есть немного join'ов в mySql и т.д. Zabbix конечно хорош, но он бы решил только задачу с мониторингом.
Kuznetsov_pa
00.00.0000 00:00Вот как обучение, да, согласен. Проходить повторный круг по мониторингу придётся, когда нужно будет делать графики, отчёты, монитринг ос и битрикса внутри и его интеграцией, алертирг на группы и прочее прочее прочее
gmtd
00.00.0000 00:00Согласен с автором, что лучше писать свой продукт для таких целей. Он не такой сложный, а всё равно рано или поздно полезет кастомная логика. Плюс потом возможно потребуется не только мониторить, но у управлять. Изучение и кастомизация чужого продукта иногда занимает больше времени, чем написание своего.
r0ck3r
00.00.0000 00:00Разрабатываю аналогичный проект, но список проверок немного отличается, включая в себя возможность мониторинга ресурсов сервера (память, диск, uptime, load average). Достигается это путем установки на сервер приложения-монитора. Также есть возможность мониторинга узлов за NAT'ом при помощи приложения-агента, которое связывается с основным сервером и получает от него задания. Вот тоже думаю не написать ли об этом проекте статью
gmtd
Вопрос только один - почему VUEX, а не Pinia?
babilonsuxx Автор
Тут все просто. Уже несколько лет для внутренних продуктов используем vue+vuex. Когда начинал, была глубокая ночь и править дефолтный конфиг мне не хотелось. Для маленьких приложений пинья лучше, тут вы правы. Наверное пора сделать отдельный конфиг с pinia.