Infra2: Consul Registrator
Пришло время рассказать про замечательный инструмент Consul Registrator. Давно его используем и очень довольны - никогда нас не подводил. Более того, в одном из проектов нам пришлось использовать не его, а упрощенный аналог 🚲 - и это оказалось очень легко реализовать. Но обо всём по порядку.
Infra1: Service Discovery, Cloud Native Proxy и деплой - первая статья цикла про различные современные штуки, которые мы используем для запуска и масштабирования приложений.
Infra2: Consul Registrator - вторая статья про замечательный инструмент.
Infra3: Мониторинг, Event Logging и сбор логов - третья статья про мониторинг.
Infra4: ...дальше видно будет...
Прелюдия
В прошлой статье мы рассказали как устроена наша внутренняя инфраструктура и общие подходы в наших продуктах. Остановились на том, как собственно происходит склейка Docker
->Consul
->Traefik
после деплоя.
Deploy
Как и полагается для хорошего 12 factor application наши приложения не знают ничего об инфраструктуре в которой они будут запускаться и работать. Их можно запустить в виде простого docker-контейнера, а можно с помощью оркестрации в многонодовом окружении, с масштабированием, избыточностью и прочими современными штучками. И конечно нам (как разработчикам, так и DevOps-направлению) очень не хочется настраивать вручную доменные имена, сертификаты, хелсчеки, мониторинг и прочую обвязку, которой обрастает каждый проект в продуктовом контуре. Вот что приходится настраивать:
- Доменные имена - то, как пользователи видят ваши приложения в этих самых интернетах
- Закрытые авторизацией внутренние и служебные адреса - метрики, админки...
- Service Discovery для разных компонентов системы
- Service Discovery для мониторинга (Prometheus)
- Хелсчеки - как liveness так и readiness для Zero downtime deployment и прочих green/blue деплоев
Вот для этого всего нам и помогает Consul Registrator
. При этом он просто запускается однажды на хосте и тихонько там работает и даже кушать не просит.
Consul Registrator
Registrator automatically registers and deregisters services for any Docker container by inspecting containers as they come online. Registrator supports pluggable service registries, which currently includes Consul, etcd and SkyDNS 2.
Основным понятием для данного инструмента является понятиеService
- это некоторая сущность, которая "слушает порт". Если сущность "слушает порт", то к ней можно обратиться извне. Если приложение/контейнер слушает 2 порта, то это 2 (два) сервиса и так далее. В жизни бывают ситуации, когда ваши сервисы не слушаю порт - например, они сами стучатся к брокеру RabbitMQ
и работают по постоянно открытому каналу, но о них чуть позже.
Service
, во вселенной регистратора, обладает стандартными атрибутами - уникальным идентификатором, именем, IP-адресом, портом и метаданными (Tags
иAttrs
). И регистратор умеет создавать (и удалять, что немаловажно) эти самые сервисы в нескольких бэкендах:
Consul
- тут всё просто.Consul
сам имеет first-class citizen под названиемService
, который проживает вService Catalog
и прозрачно понимает регистратора. Тут есть поддержка и метаданных и хелсчеков.Consul KV
- тут вместо каталога используется key-value store и вся информация о сервисе складывается там. Весьма ограниченный функционал для специфического использованияEtcd
- аналогичноConsul KV
, но есть поддержка TTLSkyDNS 2
- тот жеEtcd
, но информация пишется в подходящем дляSkyDNS 2
форматеZookeeper
- используетZookeeper
но складывает всю метаинформацию о сервисе в видеJSON
Исходя из этого списка мы выбрали Consul
, как наиболее подходящий под наши требования.
Данные для описания сервиса регистратор берёт из меток (label
) и переменных окружения (environment
) запущенного контейнера, а события о контейнерах через docker events
, для чего получает управляющий сокет докера при старте:
docker run -d --net=host \ --volume=/var/run/docker.sock:/tmp/docker.sock \ gliderlabs/registrator:latest consul://localhost:8500
Также он периодически сканирует уже запущенные контейнеры и обрабатывает случаи, когда они были запущены до самого регистратора.
Естественно, метки и переменные окружения являются "статикой" - то есть используются только те, которые были доступны на момент запуска контейнера. Когда нам понадобилось чуть больше динамики мы завели пулл-реквест, но он так и висит, а мы «пошли другим путём».
docker-compose.yml
Теперь приведём пример docker-compose.yml
файла, настоящего, который используется в проде и посмотрим как там всё описывается:
В результате мы видим, что у нас есть три контейнера - web
,jobs
, иrufus
. Собственно web-сервер, демон для выполнения отложенных задач и демон для шедулинга повторяющихся, периодических задач.
web
Этот сервис должен обслуживать HTTP-запросы пользователей, поэтому мы говорим, что его должен обслуживать Traefik
и при этом использовать TLS
и доменное имя web.example.com
. Кроме того, сюда должен наведываться Prometheus
и бдительно смотреть за состоянием. Всё это конфигурируется через метку SERVICE_TAGS
- именно на неё смотрит регистратор и всё, что в ней записано, крепит к записи в Consul
:
Далее идёт настройка liveness
хелсчеков: SERVICE_CHECK_*
- их может быть больше, но в данном случае достаточно одного. Эти проверки выполняет локально запущенный Consul-агент и "красит" состояние сервиса в красный 🔴 или зелёный 🟢 в зависимости от результата. А Traefik
наблюдает за сервисами и как только они "зеленеют" направляет трафик на них (или снимает если сервис "краснеет")
Далее мы говорим, что Docker-демон может использовать любой свободный порт на данной машине, а Consul Registrator
уже после запуска узнает, что же именно было назначено, и пропишет соответствующий порт в объект сервиса в Consul:
После этого идёт настройка readiness
проверок, которые выполняет уже сам Docker-демон, при запуске или обновлении контейнеров.
Вишенкой тут является монтирование tmpfs
в /tmp
для ускорения всяких действий, которые могут происходить внутри - масштабирование картинок и масса всего, что живет в /tmp
jobs
Если не собирать метрики с сервиса, выполняющего отложенные задачи, то для контейнера регистрация в Consul
не требуется. Но ведь мы очень хотим мониторить его с помощью Prometheus
и поэтому мы используем плагин к Delayed Job
, встраиваемся в его lifecycle
и выставляем наружу /metrics.
Мы работаем аналогично данному гему, но используем свой велосипед. Поскольку сервис теперь имеет HTTP
доступ, то его надо регистрировать в Consul
, и прометей до него доберётся самостоятельно. Для Sidekiq
в том же геме есть собственный плагин.
rufus
Rufus-scheduler (out of the box) is an in-process, in-memory scheduler. It uses threads.
It does not persist your schedules. When the process is gone and the scheduler instance with it, the schedules are gone.
Этот сервис работает аналогично предыдущему и выполняет функцииCron
, то есть обрабатывает постановку регулярных задач. Поскольку мы избегаем выполнять действия непосредственно в нём, то его мониторинг особо не нужен. Но чего не сделаешь ради унификации.
Бонус
В качестве ещё одного положительного качества данного инструмента хочу отметить его простоту. Однажды нам потребовалось добавить немного динамики в Consul Registrator
- некоторые данные сервиса мы могли вычислить только после запуска и для реализации это функционала сделали пулл-реквест. Однако на гитхабе жизнь замерла и мы решили полностью реализовать свой сервис, аналогичный Consul Registrator
, но с очень ограниченным и специфичным функционалом 🚲. Мы с чистой совестью подсмотрели реализацию в регистраторе и запилили свой сервис примерно за 2 дня. Это показательный момент. Если по какой-то причине вам не подойдет текущий функционал, или там появится баг, мешающий вашему проду, то вы без особых проблем сможете решить проблему собственными силами 💪.