Servlerless free cloud watchdog (telegram alerts).

Задача

При разработке пет-проекта Chipa bots одной из целей было достичь максимальной автоматизации: сделать рабочий SaaS самостоятельно (без инвестиций, помимо времени на выходных) и запустить его в формате “сделать и забыть”. Это требует автоматизации рутины везде где возможно. Дополнительно о проекте здесь.

Чтобы “сделать и забыть”, надо быть уверенным, что все работает, и что мы будем уведомлены, когда перестанет.

ТЗ:

  1. Watchdog должен быть размещен вне наблюдаемого сервера, на случай недоступности самого сервера.
  2. Watchdog должен отправлять уведомление в случае неуспешного health check системы.

Экономика пет-проекта

В нормальном проекте следовало бы положиться на решения мониторинга, например, prometheus alert manager. Однако пет-проект chipa запущен на сервере за 420 руб/мес (как говорил один мой знакомый, с деньгами любой может, а вы попробуйте сделать без денег!) Server

с мощностями в 2 vcpu и 2 gb ram, чего хватает только на запуск основных компонентов системы: Docker stats

Очевидно что покупка второго сервера для watchdog сделала бы проект на данной стадии финансово нежизнеспособным. К счастью, облака AWS и Яндекс предоставляют free tier для serverless функций, и эти фукнции отлично подходят чтобы сделать watchdog!

Итак, watchdog будет реализован как function Яндекс облака. В рамках free tier доступно 1 000 000 вызовов yandex free tier », а для проверки сервиса раз в минуту достаточно 44640 вызовов в месяц.

Решение

Health check

В сервис добавлен smallrye-health, открывающий метод https://chipa.archertech.ru/api/q/health, который возвращает http status 200 и статус сервиса:


{
    "status": "UP",
    "checks": [
        {
            "name": "SmallRye Reactive Messaging - liveness check",
            "status": "UP",
            "data": {
                "bot_csv_updated": "[OK]"
            }
        },
        {
            "name": "Reactive PostgreSQL connections health check",
            "status": "UP",
            "data": {
                "<default>": "UP"
            }
        },
        {
            "name": "SmallRye Reactive Messaging - readiness check",
            "status": "UP",
            "data": {
                "bot_csv_updated": "[OK]"
            }
        },
        {
            "name": "Database connections health check",
            "status": "UP",
            "data": {
                "<default>": "UP"
            }
        },
        {
            "name": "SmallRye Reactive Messaging - startup check",
            "status": "UP",
            "data": {
                "bot_csv_updated": "[OK]"
            }
        }
    ]
}

Что можно сказать о состоянии системы по этой информации:

  1. Сервер up
  2. Nginx up (т.к. nginx проксирует запросы https://chipa.archertech.ru/api на backend quarkus где запущен health check api)
  3. SSL сертификат ok
  4. Backend up
  5. Postgresql up
  6. Rabbitmq up

Для полной уверенности не хватает информации о keycloak, фронтенде и nlp системе, но это задел на будущее.

В случае недоступности подсистемы, healthcheck вернет http статус 503 (статус будет использован далее при проверках) и json:

{
    "status": "DOWN",
    "checks": [
        {
            "name": "SmallRye Reactive Messaging - liveness check",
            "status": "UP",
            "data": {
                "bot_csv_updated": "[OK]"
            }
        },
        {
            "name": "Reactive PostgreSQL connections health check",
            "status": "DOWN",
            "data": {
                "<default>": "UP"
            }
        },
        ...

Watchdog cloud function

Telegram bot

В телеграм необходимо настроить бота и группу, в которую бот будет писать уведомления. Инструкция ».

Токен и ChatID понадобятся далее в параметрах функции.

Function

Функция будет реализована на bash:

  1. curl вызывает api health check
  2. проверка http_code ответа
  3. curl отправки уведомления в телеграм, в случае ошибки

Curl запроса health check:

curl --connect-timeout 3 -s \  
    -w \nexitcode=%{exitcode}\nerrormsg=%{errormsg}\nhttp_code=%{http_code}' \
    https://chipa.archertech.ru/api/q/health

При помощи ключа -w выводим несколько важных для анализа проблем параметров. Пример вывода curl при здоровой системе:

{healthcheck json}
exitcode=0
errormsg=
http_code=200

Пример ошибки (таймаута сервера):


exitcode=28
errormsg=Resolving timed out after 1000 milliseconds
http_code=000

Но! К сожалению, данный вариант требует версии curl 7.75.0, а в yandex cloud установлен 7.58.0 (версия в Ubuntu 18.04 LTS), потому в финальном скрипте я оставил только http_code.

Для проверки что все системы запущены, достаточно проверки http_code:

  • 200 - сервис UP
  • другие коды http - что-то сломалось (например 503 - сервис DOWN)
  • код 000 означает что http ответ не получен, например, по таймауту вызова health check API, когда сервер недоступен

Полный скрипт watchdog:

#!/bin/bash

#https://core.telegram.org/bots/api#sendmessage
function sendTgAlert {
  curl -s -X POST -H "Content-Type: application/json" \
    -d "{\"chat_id\": \"$CHAT_ID\", \"text\": \"CHIP!!!\n\n$1\"}" \
    https://api.telegram.org/bot$TOKEN/sendMessage
}
# need version 7.75.0
#healthcheck=$(curl --connect-timeout 3 -s -w '\n%{json}\nexitcode=%{exitcode}\nerrormsg=%{errormsg}\nhttp_code=%{http_code}' $URL)

# version 7.58.0
healthcheck=$(curl --connect-timeout 3 -s -w '\nhttp_code=%{http_code}' $URL)

# extract http_code from last line
http_code=$(echo "$healthcheck" | tail -n1 | cut -d= --fields=2)

if [ $http_code == 200 ]; then
  echo "healthy"
elif [ $http_code == 000 ]; then
  sendTgAlert "http_code=$http_code => health check API unavailable\n\nsee $URL"
else
  sendTgAlert "http_code=$http_code\n\nsee $URL"
fi

Создаем яндекс функцию в консоли облака (см. инструкции Яндекс »), и сохраняем bash script: Bash functions

Указываем параметры функции: Function parameters

Timer

Функцию раз в минуту будет запускать timer.

Таймер можно создать в консоли здесь: Creating timer in console

Для таймера требуется создать сервисный аккаунт: Timer service account

Финальные настройки таймера: Timer service account

Проверки

  1. Недоступность сервера

Изменим URL на несуществующий: Wrong server

Алерт: Wrong server alert

  1. Backend не отвечает

Остановим контейнер: Stop container

Алерт: Backend down

  1. Одна из систем лежит

Например, остановим rabbitmq:

Healtcheck при этом отвечает статусом 503 с телом ответа:

{
    "status": "DOWN",
    "checks": [
        {
            "name": "SmallRye Reactive Messaging - liveness check",
            "status": "UP",
            "data": {
                "bot_csv_updated": "[OK]"
            }
        },
        {
            "name": "SmallRye Reactive Messaging - readiness check",
            "status": "DOWN",
            "data": {
                "bot_csv_updated": "[KO]"
            }
        },
        ...

Алерт: Subsystem down alert

Теперь можно быть уверенным что все работает, если телеграм молчит. The end. Happy chipa