Очень легкая система мониторинга с Телеграмом и Консулом


    Всем счастья и добра!


    Эволюционно так получилось, что в моем личном владении оказался не маленький зоопарк различных серверов: от дешевого Supermicro до топового (на момент выпуска) HP Gen 8. Все конечно связано оптикой и прочими радостями жизни.


    Но сказ не про то, как сеть класть, и даже не про то, как сервера настраивать, а про то, как правильно просто на всем этом деле docker-compose сервисы поднимать и радоваться.


    ИМХО про сервера

    HP — классные ребята, мощная и надежная начинка, но только обслуживать с точки зрения физики ну очень не удобно после supermicro.
    Supermicro — дешевые, удобные ребята, но функционала (ILO, прошивки, Smart Array ...) сильно таки меньше.


    Казалось бы, что может быть проще: взял, сделал docker-compose.yaml, пару-тройку Dockerfile, запустил — профит. Но демон кроется в мелочах..


    Прелюдия про сервера дана не просто так: а что если в каждом сервер по десятку-другому виртуалок, а в каждой виртуалке по сотни сервисов из десяток compose файлов? В довесок, нельзя забывать, что часть компонент просто как независимые сервисы существуют.


    И вроде все работает. Но иногда наступает тот дивный чудный момент, когда приходит потребитель одного из сервисов с вопросом вида "а чего-то у меня уже неделю сервис такой-то немного не живой".
    И вроде как клиент лояльный (сервис-то для него бесплатный), и вроде как трагедии не произошло, но возникает странное ощущение надвигающегося шторма нежданчиков и звонков в три ночи.


    Поскольку важнейшим навыком любого программиста/девопсера/админа является способность вовремя реагировать на сигналы со стороны самой мягкой части тела чуть пониже спины, то я начал предпринимать соответствующие меры.


    Но я был бы не я и не инженером-математиком, если бы не постарался сформулировать причины и возможные решения проблемы.


    Дано


    • Зоопарк сервисов, запущенных как в докере, так и без него
    • Количество сервисов будет увеличиваться
    • Некоторые группы сервисов полностью изолированы (обычно в целях разграничения видимости/доступа)

    Задача


    • Сделать так, чтобы ничего не падало. Чтобы поднималось само при падении
    • Использовать решения, которые возможны как для малого количества сервисов, так и для большого
    • Знать когда и что упало. Желательно не позже клиента.
    • Не тратить на настройку много времени

    Решение


    Во-первых, соблазн запускать сервисы с restart=always был отмечен судрожными воспоминаниями о багнутых контейнерах с нулевой задержкой при старте.
    Во-вторых, курение docker-compose v3 показало, что что-то вроде такого есть, но при близком рассмотрении работает с большим количеством условностей.
    В-третьих, использование Kubernetus и co., выглядело как выстрел из СРЗО Смерч в комара на расстоянии 100 метров.


    После пары кружек крепкого рома кофе, в голову пришло воспоминание о Consul и consul-template.


    consul-template

    Изначально consul-template был сделан в качесве генерации конфигов на основе данных в Consul с авто обновлением, но сейчас его можно использовать в качестве некого аналога supervisord'a.


    Образовалась следующая цепочка:


    • consul-template запускает приложение,
    • регистрируется как сервис в Consul (Service Register),
    • а я прикручиваю мониторинг на том-же консуле за счет событий и мониторинга изменений

    Радуги, единороги и бабочки… Пока не осознал, что consul-template не умеет регистрироваться в Consul. 0_о
    ссылка на Issue, которая ведет на Issue 2016 года


    Однако идея все же была проста:



    Уважаемый основатель Microsoft завещал нам всем быть ленивыми, ну а поскольку кто я такой, чтобы с ним спорить, то пошел искать альтернативные решения.


    Внезапно оказалось, что легкого решения нет. Supervisord — тянет за собой питон (ничего против не имею, но как бы место жалко, особенно учитывая количество сервисов). Zabbix'ы и иже с ним — вроде хорошо, но либо тяжелые агенты, либо большая задержка.


    #яжепрограммист, так что за готовку. Рецепт простой: возьмем go (итоговые файлы небольшие и самодостаточные, а крос-компилиция элементарна), горсть знаний по unix-процессам и много-много чая.


    Хронология (Д — день старта):


    • Д+1 готовый, рабочий прототип
    • Д+2 исправлены все найденные баги
    • Д+3 отдано на растерзания коллегам
    • Д+4 аварийно исправлены найденные коллегами ошибки
    • Д+7 все было переписано заново
      ...

    Наши дни


    Сделан ультра легкий супервизор с возможностью конфигурирования количества перезапусков, интервалов между ними, автоматической (де)регистрацией в Consul, нотификацией в Telegram.
    Параметры запуска можно сохранить в конфигурационный файл. Корневая часть вынесена как отдельная библиотека, добавлена возможность простой разработки расширений.


    Пример


    Допустим, есть сервис (назовем его /usr/local/bin/dummy) с большим количеством флагов для настройки. Он может иногда падать (не он такой, жизнь такая =( ).


    Запускаем его с регистрацией в локальном агенте Consul:


    monexec run --consul -- /usr/local/bin/dummy -a 1 -b 2 -c 3 --foo bar --foo baz --foo etc

    Профит! По-умолчанию, monexec будет перезапускать его вечно с интервалом в 5 секунд.


    Далее, мы хотим передать это администраторам для дальнейшего использования. Километровую строку запуска отправлять как-то не комильфо.


    Генерируем скрипт запуска (все тоже самое, просто добавим флаг --generate):


     monexec run --generate --consul -- /usr/local/bin/dummy -a 1 -b 2 -c 3 --foo bar --foo baz --foo etc > dummy.yml

    dummy.yml
    services:
    - label: stinger-desert
      command: /usr/local/bin/dummy
      args:
      - -a
      - "1"
      - -b
      - "2"
      - -c
      - "3"
      - --foo
      - bar
      - --foo
      - baz
      - --foo
      - etc
      stop_timeout: 5s
      restart_delay: 5s
      restart: -1
    consul:
      url: http://localhost:8500
      ttl: 3s
      timeout: 1m0s
      register:
      - stinger-desert

    Это нам создаст конфигурационный файл для дальнейшего использования.
    Запускать его так:


     monexec start /path/to/dir/with/dummy

    Важно! /path/to/dir/with/dummy — именно директория, а не путь до файла. (Навеяно Dockerfile'ами)


    Теперь добавим счастливой жизни и грамма безумия: подключим оповещения в Telegram. Для этого нужно создать бота и узнать свой номер


    dummy with telegram
    services:
    - label: stinger-desert
      command: /usr/local/bin/dummy
      args:
      - -a
      - "1"
      - -b
      - "2"
      - -c
      - "3"
      - --foo
      - bar
      - --foo
      - baz
      - --foo
      - etc
      stop_timeout: 5s
      restart_delay: 5s
      restart: -1
    consul:
      url: http://localhost:8500
      ttl: 3s
      timeout: 1m0s
      register:
      - stinger-desert
    telegram:
      token: "123456789:AAAAAAAAAAAAAAAAAAAAAA_BBBBBBBBBBBB"
      services:
          - "stinger-desert"
      recipients:
          - 123456789
      template: |
        *{{.label}}*
        Service {{.label}} {{.action}}
        {{if .error}}️ *Error:*  {{.error}}{{end}}
        _time: {{.time}}_
        _host: {{.hostname}}_

    Итог


    Как говорил один человек, создание чего-либо нового состоит из трех этапов:


    1. Идея
    2. Реализация
    3. Публикация

    Хорошая или плохая идея и реализация (это решать вам) — все это не имеет ценности, если другие не могут этим пользоваться.


    Я постарался создать документированный исходный код, руководство к использованию и собрать бинарные файлы под большинство платформ


    Всем удачи!

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 15

      –1
      Supervisord — тянет за собой питон (ничего против не имею, но как бы место жалко, особенно учитывая количество сервисов)

      Куда тянет? Это на каком дистрибутиве нету питона из коробки?


      Zabbix'ы и иже с ним — вроде хорошо, но либо тяжелые агенты, либо большая задержка.

      И не тянет php?

        +1
        Куда тянет? Это на каком дистрибутиве нету питона из коробки?


        В образах для докера. Т.к. далеко не всем приложениям нужен питон для запуска, то большинство образов его в себя не включают. Например alpine.

        И не тянет php?


        Тут я вопроса не понял. Чутка деталей было бы отлично.

        Предполагаю, что речь шла про какой-то web UI, но зачем в мелкие контейнеры тянуть еще N утилит общего назначения?
          0

          А, в этом смысле. Тут согласен.

        0

        А что насчет docker swarm? Вроде не такой тяжелый.

          0
          К сожалению, не решает проблемы запуска одиночных сервисов
            0
            я не знаю вашей внутренней кухни, но не проще эти сервисы в докер тоже завернуть, чтоб было однообразно?
            • НЛО прилетело и опубликовало эту надпись здесь
          +1

          Спасибо, интересная статья. А вот можно прояснить следующий момент:


          Далее, мы хотим передать это администраторам для дальнейшего использования. Километровую строку запуска отправлять как-то не комильфо.

          Не очень ясна роль администратора в вашем воркфлоу, я так понимаю, что все происходит автоматически, без вмешательства человека, сервисы, если падают, поднимаются сами. Или все равно кто-то должен настаивать супервизор в запускаемых контейнерах… можете чуть подробнее этот момент описать?

            0

            Имелось ввиду, что мы хотим передать другим людям (например админам) для дальнейшей эксплуатации готовый набор параметров и настроек.
            Грубый пример: перенос между стендами разработки и тестирования.

              0

              Ок, а я правильно понимаю, что сгенеренные yam конфиги для monoexecl "зашиваются" через докерфайлы в докер образы? Или они позже уже деплоятся на зарущенных контейнерах ?

                0

                Идея была именно такая (зашивать). Для мониторинга запущенных контейнеров "из-вне" лучше использовать Consul as-is.

            +2

            А чем хуже вариант использовать существующие приложения?


            • в качестве надёжного супервизора взять что-то из семейства daemontools (напр. runit или s6)
            • аргументы запуска прописать в явном виде sh-скрипта, запускающего сервис
            • для регистрации в консуле тупо отправлять HTTP-запрос в консул любой тулзой из скрипта стартующего сервис
            • для репорта крешей опять же запускать что-то аналогичное (репорт по HTTP в какой-нить сервис вроде pushgateway для prometheus) из скрипта запускаемого супервизором при креше сервиса

            По сути, всё это разные задачи, которые нужны в разных комбинациях под разные ситуации. Тулзы, которые всё это делают — занимают ещё меньше, чем бинарник Go-приложения (супервизор из runit — runsv — занимает 30KB и не тянет никаких нестандартных динамических библиотек).

              0

              Во-первых, спасибо за s6.
              Во-вторых, понятно, что задачу можно решить более одним способом.
              В-третьих, все-же сравните затраты на запуск одной команды или на оркестрацию целого вороха утилит. Это как Docker: можно без него, напрямую с cgroups и bridge-utils, но с ним немного проще =)

              0

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

                0

                Вы завелосипедили nomad (ну и, если что, есть такая штука, как consul registrator).

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое