Как построить Observability для инфраструктурной платформы
Можно ли сделать классный и удобный мониторинг не для галочки, а с пользой для всех участников разработки? Инженерный опыт подсказывает, что Observability как процесс идеально построить не получится. Но стремиться к этому стоит.
Статья подготовлена на основе доклада Владимира Дроздецкого о вопросах, методах, практиках и в целом подходе к Observability для инфраструктурной платформы Magnit Online Services. Внутри — о том, как пришли к идее нового процесса, о настройке мониторинга от helm upgrade до gitops-подхода, опыте интеграций с Grafana в работе с визуализацией и метриками и политике алертов, которая не пропускает критичные угрозы.
Статья будет полезна инженерам платформенных команд и эксплуатации, а также всем, кто внедряет у себя DevOps-практики.
Контекст: для чего понадобилось строить новый процесс
Около трёх лет назад руководство «Магнита» отказалось от разработки мобильного приложения на аутсорсе. Всё перенесли внутрь компании. В результате к концу 2020 года в руках команды эксплуатации появился OpenShift одной из старых версий и работающие внутри него Prometheus и ELK Stack.
Было много проблем. В частности, с метриками, потому что их Retention соответствовал базовой конфигурации Prometheus DB. А в случае с ELK Stack терялось большое количество логов, так что разработка не могла ими пользоваться.
Чтобы избежать подобных проблем в будущем и обеспечить более эффективную работу, в Magnit Online Services решили строить свою платформу на базе Yandex Cloud и процесс мониторинга для неё. Сердцем инфраструктуры стал Kubernetes, а основным стеком — Prometheus, Grafana, Loki, Promtail.
Принципы построения процесса Observability
Observability как процесс — это танго для двоих. Командам эксплуатации и разработки предстоит плотно взаимодействовать и много договариваться о том, что и как строить. Без этого хорошее Observability вряд ли получится.
У команды в процессе таких переговоров рождается целый ряд внутренних соглашений. Например:
Использование twelve factor app: все приложения, запущенные в Kubernetes, должны соответствовать правилам для создания cloud native приложений.
Метрики: формат пригодный для Prometheus, базовые метрики, возможность добавлять кастомные метрики.
Логи: все логи должны храниться в JSON-формате с определёнными полями, такими как time stamp, месседжи, специфичные для сервиса поля.
Благодаря такой стандартизации появляется универсальный апчарт для всех внутренних приложений, и новые сервисы запускаются быстрее.
Когда разработчик впервые деплоит своё приложение в dev-контур, он автоматически получает сервисы мониторинга и базовые алерты. Это означает, что приложение начинает мониториться и логироваться. Логи можно просматривать через Grafana, а информацию о сервисах, такую как потребление ресурсов процессора и памяти, можно увидеть, переключаясь между панелями на предварительно настроенных дашбордах. Для более узких кейсов и специфичных бизнес-метрик можно использовать отдельные дашборды.
Конфигурирование компонентов платформы
Prometheus — центр мониторинга и компонент платформы. Для развертывания применяется kube prometheus stack helm chart, включающий в себя все необходимые компоненты. Всё конфигурирование проходило по схеме: есть инженер, отдельный репозиторий в GitLab и Kube Prometheus Stack со всеми манифестами. Чтобы внести изменения, достаточно было использовать «helm upgrade –install…».
Конфигурирование компонентов платформы
Из-за такого подхода возникло несколько проблем, связанных с человеческим фактором:
Ошибки в процессе конфигурирования. Иногда члены команды вносили изменения в кластер руками при помощи команды «kubectl» и забывали запушить это в репозиторий.
Конфликты во время слияния разных веток, когда в них работали разные люди.
Решение проблемы нашли в подходе GitOps и начали использовать Flux CD.
Flux CD
Вначале всё хорошо настроили, и Flux применял изменения, которые были в репозитории. Его использовали только для настройки Prometheus, но потом решили управлять и другими ресурсами, такими как: Nginx Ingress Controller, Prometheus Rules, etc. Первоначальный бутстрап кластера тоже был интересен. С первой большой проблемой столкнулись далее.
Проблема зависимости ресурсов
Первая большая проблема, с которой команда столкнулась при реализации, — зависимость ресурсов. Flux из коробки рекурсивно перебирал всю свою директорию и находил сущность Prometheus Service Monitor, которая не могла быть добавлена, потому что отсутствовал нужный CRD и весь деплой «залипал». Решение нашли в переходе на кастомизацию и использовали Kustomization Controller. Определили зависимости в спеке, установили таймауты и описали health check для компонентов, которые деплоим. После этого стало возможным управлять зависимостями ресурсов при бутстрапинге кластера с нуля.
Проблема мониторинга других ресурсов
Не все ресурсы, которые нужны, находились внутри кластеров Kubernetes. Некоторые были за пределами и запущены на виртуальных машинах. Их нужно было как-то мониторить. Для этого на виртуалках установили экспортеры и Promtail для логов. Но возник вопрос как добавлять в мониторинг новые виртуалки с сервисами? И можно ли это автоматизировать? В качестве решения пришли к Service Discovery, с которым работает Prometheus.
Service Discovery
Источником ресурсов, которые нужно было мониторить, стал HashiCorp Consul. А для управления инфраструктурой, виртуальными машинами и кластерами использовали Terraform и его модули.
Когда базовая виртуальная машина со всеми обновления разворачивается, на ней уже стоит Node Exporter. Для регистрации сервиса в Consul добавили отдельный ресурс в Terraform. Prometheus уже знал, на какой сервис ему смотреть, и благополучно добавлял нужный ресурс в мониторинг.
Особенность таких виртуальных машин в том, что на них может быть установлено несколько экспортеров, и каждый предоставляет метрики для конкретной задачи. Например, на виртуалке с VMware Harbor могут быть установлены экспортеры для метрик Harbor и других задач. В модуле Terraform — дополнительные ресурсы, которые регистрируют новые сервисы в Consul. Так можно добавлять новые ресурсы, соответствующие этим экспортерам, и Prometheus будет успешно добавлять таргеты для сбора метрик.
Управление метриками
Теперь о том, как работали с метриками внутри Kubernetes-кластеров.
По запросу о мониторинге в Kubernetes поисковой сервис выдаст что-то подобное:
Хранение метрик
В кейсе Magnit Online Services рабочий набор включал dev, uat, prod-стенды. В качестве хранилища данных использовали Victoria Metrics и визуализировали при помощи Grafana. Remote_write был важен как механизм Prometheus. Он позволял использовать отдельное хранилище для записи метрик и так называемые external labels, когда по лейблу метрики можно понять, из какого она кластера. Всё это было нужно, чтобы формировать дашборды, которые дадут разработчику полную картину, возможность переключать окружение и просматривать метрики для dev, uat, prod и так далее.
Victoria Metrics использовали в Single Node-инсталляции. Этот способ выбрали потому, что на тот момент было не так много метрик. Виртуальная машина с 8 ядрами, 16 гигабайтами оперативной памяти и диском была способна справиться с задачей. Тестирование кластерной инсталляции внутри Kubernetes тоже проводили. Всё работало отлично, но потребляло больше ресурсов. Поэтому решили отложить вопрос на будущее.
Технические и бизнес-алерты
Теперь об алертах. В Magnit Online Services выделяют два типа:
технические — алерты о дисках, процессорах, оперативке и прочем;
бизнес — алерты, которые срабатывают в случае наступления какого-то бизнес-события, например, в мобильном приложении.
Как формировали алерты
Для создания технических и бизнес-алертов применяли правила Prometheus, которые разработчики хранили рядом с приложением в репозитории. Создать технический или бизнес-алерт мог любой сотрудник, не важно, это команда инфраструктуры или разработки. Например, разработчики могли создать alert о том, что диски базы данных заполнились на 50%.
Бизнес-алерты, в отличие от технических, более критичны. Их нужно писать внятно и более внимательно из-за прямого импакта на пользователей. В нашем случае людей, которые используют приложение «Магнит акции и скидки».
Каналы оповещений об алертах
Основной канал оповещений о событиях работает через Microsoft Teams.
Если бизнес-алерт срабатывает, команде приходит оповещение, и алерту сразу присваивается статус Critical. Это значит, нужно срочно разобраться, что произошло.
Алерты с разными статусами приходят в отдельный канал нотификации, где уже есть люди, ответственные за эту часть задач в продукте. Ещё есть Notification channel — буквально мусорка для алертов, куда попадает вообще всё. Например, алерты, которые притянул за собой Prometheus Stack.
Дальше каналы делятся по важности и времени реакции:
на Critical алерт — в течение 15 минут;
на Pre Critical — в ближайший час, так как этот алерт может в скором времени стать критичным;
на Non-critical не нужно реагировать мгновенно, но обязательно завести задачу в Jira и начать что-то делать. Любое Non-critical событие также может перерасти в критичное.
По Critical алерту в канале и по решению кейса, который произошёл, формируется постмортем. Для этого в Confluence заведен отдельный раздел. В нем есть полное описание того, что случилось: название и тип инцидента, на кого и в каком масштабе он влияет (начало, конец, что было, как починили). И последний пункт — набор тасок в Jira, которые нужно выполнить, чтобы ситуация больше не повторялась.
Когда в команде поняли, что возможностей Microsoft Teams недостаточно для задач с оповещениями, то воспользовались дополнительной системой для интеграции алертов, сначала с помощью Pager Duty, затем с Aletrops.
Более подробная схема оповещений о событиях выглядит так:
Основная задача Alertops — отправка сообщений на электронную почту, смс и телефонный звонок. При этом телефонный звонок — это не просто очередной способ донести информацию. Когда звонит Alertops, инженер слушает сообщение и должен нажать определённую цифру. Это будет означать, что алерт принят в работу, отклонен или эскалирован.
Политика эскалации алертов
Бывают ситуации, когда инженер, которому приходят алерты, недоступен. Для этого в Alertops настроена политика эскалации.
С алертами в Magnit Online Services работают две команды: платформенная и саппорт. Последняя оказывает круглосуточную поддержку всей компании. Инженеры платформенной команды дежурят с 10:00 до 19:00, с понедельника по пятницу. Внутри есть ротация, чтобы распределить нагрузку между инженерами. Политика эскалации срабатывает, если дежурный инженер получил Critical alert и по какой-то причине на него не ответил. Если первый не ответил, звонок поступает второму. Если не ответил второй, звонок идёт лиду команды. Если никто из инженеров не ответил, звонок направляется руководителю разработки, и тот точно кого-нибудь найдёт.
Со второй командой инженеров схема такая же. Отличаются только часы дежурств: их расписание с 00:00 до 10:00 и с 19:00 до 00:00. Саппорт работает 365 дней в году и 24 часа в сутки без выходных. Если они не могут отработать оповещение, то обращаются к платформенной команде.
Проблемы визуализации
Типичная ошибка визуализации — дашборд со множеством цифр и графиков, в котором разработчик не сможет быстро найти то, что нужно. Например, узнать, сколько ресурсов процессора и оперативной памяти потребляет приложение, которое только что задеплоили в Kubernetes.
Разработчик, который ничего не может найти, начинает грустить. А польза от дашборда — минимальна. Поэтому лучше формировать плюс-минус универсальные дашборды. Ниже та же самая задача.
В верхнем углу видим namespace и название приложения (APP). Их переключение позволяет указать разработчику нужный namespace и приложение. Соответственно, на данном графике он увидит свои поды и то, как они потребляют ресурсы. И верхняя отсечка — это лимиты, указанные при деплое приложения.
Некоторые запросы, с которыми разработчики приходят к инженерам, на первый взгляд кажутся банальными. Но это не так. Если сделать дашборд удобным, вопросов будет меньше, и воспользоваться им смогут быстрее.
Визуализация и мониторинг состояния соседних сервисов
Приложения не живут в вакууме, они взаимодействуют между собой. Случаются кейсы, когда разработчик вносит изменения, деплоит приложение, а оно не работает так, как задумано, или не работает вообще. Потому что сервис, с которым он взаимодействует, полностью не функционирует.
Понять, работает ли соседнее приложение, помог дашборд, который показывает жизнеспособность сервиса в том или ином окружении.
Существует отдельный плагин для Grafana, который появился в версии 8.5: называется Status History, он поможет визуализировать доступность сервиса. В команде Magnit Online Services используется стандартизация, включающая известные порты для приложений и определенные эндпоинты для проверки состояния приложения. Например, эндпоинт health, который должен отдать ответ ready. Если в деплойменте есть хотя бы один запущенный и работающий под, то считается, что приложение работает. Чтобы получить данные о работе приложения, был добавлен Blackbox Exporter в кластер и настроен на проверку нужных эндпоинтов. В итоге все данные отображаются в Grafana.
Аннотации в Grafana
Итак, у нас есть метрики и графики, которые показывают, живо ли приложение и как себя чувствует пользователь. Фактически отображается количество пятисотых и других ошибок. Из CI/CD пайплайна отправляем аннотацию в Grafana при помощи того же cURL с определёнными параметрами. Получаем тот же график, но с отсечкой о том, что, например, был деплой. Такие отсечки полезно сделать для деплоя в прод.
Предположим, мы заметили на графике резкий спад числа пользователей и рост числа пятисотых ошибок на бекенде. Чтобы понять причины, включаем аннотации и просматриваем, какие изменения происходили в системе в момент, когда возникла проблема. Например, видим, что 15 минут назад разработчик провёл деплой, и в параметрах видно, что именно он задеплоил и какой коммит использовал. Дальше можем принять решение: откатить изменения или быстро выпустить фикс.
Визуализация и Drill Down подход
Ещё глубже погрузиться в анализ проблем, происходящих в системе, помогает Drill Down-подход. В работе с дашбордом он помогает переходить от общей картины к частным вещам.
На рисунке ниже пример, как формировали Drill Down дашборд для инфраструктуры и виртуальных машин Magnit Online Services.
Переключатель сверху — указание окружения (например, dev, uat и так далее) и список из виртуальных машин с какими-то параметрами (количество CPU, оперативная память, загрузка, диски).
Чтобы понять, что происходит с диском, подсвеченным красным, нажимаем на имя инстанса и попадаем в более детализированный дашборд.
Иметь такие данные разработчику очень полезно. Дальше о том, как это сделать.
Настройки дашбордов в Grafana Drill Down
Открывая дашборд в Grafana, видим, что ссылка на него статическая. Она не меняется в зависимости от контекста, а значит, в неё можно передавать параметры.
Например, параметр var node может быть передан из имени инстанса предыдущего дашборда, а var site — переменной ENV. Это позволяет открыть нужный нам детализированный дашборд с нужным инстансом и окружением. Такой подход позволяет создавать дашборды с высокой детализацией на нижнем уровне, когда нужно добраться до целевого инстанса.
Логирование и трейсинг
Основная проблема при построении Observability заключается в слишком большом количестве инструментов мониторинга, трейсинга, логирования и других. Разработчик получает в своё распоряжение сразу несколько интерфейсов, может, и больше десяти. И когда случается какое-то событие, становится сложно переключиться из метрик в трейсы, логи и сопоставить с ними это событие.
В качестве основного инструмента для логирования удобно использовать компоненты Gap Stack, потому что он отлично интегрируется с Grafana. Хранилищем для логов выступает Grafana Loki, а хранилищем трейсов — Grafana Tempo. В такой связке получаются удобные дашборды.
Grafana Loki
Ниже пример дашборда с логами, которым пользуются разработчики в «Magnit Online Services».
Здесь можно переключить namespace, выбрать приложение и через строку поиска найти нужные логи.
Подводные камни Grafana Loki:
Нуждается в тюнинге, если нужно работать с большим объёмом данных — 600–800 Гб и более. Придётся куда-то вынести индексы, например, в Apache Cassandra. Также желательно, чтобы диски были побыстрее.
Не подходит как долгосрочное хранилище логов. Loki удобно использовать как краткосрочное хранилище — до двух недель, чтобы разработчик мог быстро посмотреть какую-то информацию. Дальше нужна автоматическая ротация. Если нужно работать с периодом в два-три месяца, Loki зависает, и лучше использовать другое решение.
В Magnit Online Services эту задачу решает ELK. В Elasticsearch хранятся логи только определенных сервисов. Доступ к Kibana имеет ограниченный круг разработчиков, которые сделали запрос на логирование своих сервисов и доступ. ELK используется ограниченно для построения более гибкой и сложной аналитики.
Grafana Tempo
Grafana Tempo используется для хранения трейсов. Согласно конвенции Magnit Online Services, трейсы должны быть сквозными, чтобы разработчик всегда мог видеть, как ушёл запрос, как он прошёл через gateway и с каким результатом.
Инструмент легко устанавливается, но из-за большого объёма данных также нуждается в тюнинге. Для этого в Magnit Online Services добавили локальное кэширование, кластерную инсталляцию в Tempo и основное хранилище в S3 от Yandex.Cloud.
Grafana Loki + Tempo
Один из важных моментов интеграции Grafana, Loki и Tempo — возможность формирования вычисляемых полей, называемых derived field.
В логе есть поле с уникальным идентификатором трейса — TraceID. Можно настроить источник данных в Grafana, чтобы парсить это поле, и, нажав на кнопку Tempo или Tempo Prod, разработчик может легко найти нужный ему трейс в интерфейсе Grafana. Это улучшает процесс отладки и позволяет быстро находить нужные данные.
Ниже видим два варианта визуализаций. Справа — классическая, а слева — Node View, — бета-версия одной из новых фич. Она уже хорошо работает и рисует графы взаимодействия сервисов.
Возвращаясь к Flux и вопросу настройки и управления кластерами в среде Kubernetes с его помощью. Команда, которая работала над процессом Observability, создала публичный репозиторий с описанием настроек, кастомизаций и минимальной документацией. Любой, кому это нужно, может зайти, посмотреть на готовую реализацию и начать использовать Flux для бутстрапинга своих кластеров.
Пример структуры репозитория, используемый для базового бутстрапа кластеров k8s
Итоги
Удобный процесс Observability — это всегда результат совместной работы команд эксплуатации и разработки. Здесь хочется учесть все запросы, сделать работу мониторинга прозрачной, понятной, быстрой и с теми инструментами, которые подходят лучше всего. Возможно, идеальный процесс построить не получится, но к этому стоит стремиться.
В этой статье мы подробно разобрали опыт настройки процесса мониторинга командой Magnit Online Services. Ниже краткие выводы о том, из чего исходили авторы, какие проблемы решали и с помощью каких инструментов реализовали решения:
Упростили и стандартизировали процесс мониторинга приложений — сформировали набор внутренних соглашений и понятных стандартов разработки. Так уменьшили число ошибок.
Сделали мониторинг прозрачным — подключили сервисы мониторинга и базовых алертов при деплое приложения на dev-контур.
Систему алертов и политику их эскалации настроили исходя из приоритетов и бизнес-требований, специфики приложения и расписания работы команд. Связка из инструментов — Microsoft Teams, система для интеграции алертов Aletrops.
Настроили работу с метриками с помощью Grafana, Victoria Metrics и настраиваемых дашбордов. Разработчикам стало удобно анализировать метрики и логи приложений.
Решили проблему зависимости ресурсов внутри кластера Kubernetes с помощью Kustomization Controllers и проблему мониторинга других ресурсов, запущенных на виртуальных машинах, через экспортеры, Prometheus и Service Discovery с использованием HashiCorp Consul.
Решили проблему визуализации ресурсов и памяти, состояния соседних сервисов и множественности неудобных графиков и цифр, в которых трудно что-то быстро найти. Реализовали с помощью плагинов и аннотаций Grafana, а также универсальных дашбордов.
Сделали мониторинг более гибким и настраиваемым, с высокой детализацией на нужных разработчику уровнях с помощью Drill Down подхода в разработке дашбордов и настройках в Grafana. Стало возможным погружаться в анализ проблем инфраструктуры глубже.
Решили проблему мониторинга, логирования и трейсинга с помощью интеграции инструментов: Gap Stack для логирования в связке с Grafana, Grafana Loki для хранения логов и Grafana Tempo — для хранения трейсов.