Consul: Service Discovery это просто, или прощаемся с конфиг-файлами
Что здесь интересного:
Обзорная статья о Consul (http://consul.io) — системе для поддержания обнаружения сервисов и распределенного хранилища ключ-значение. Кроме самого Consul, рассмотрим Consul-Template — средство для управления конфигурациями сервисов автоматически отражающее изменения в топологии. Статья будет интересна DevOps инженерам, системным архитекторам, тим-лидам проектов и прочим интересующимся микросервисными архитектурами.
Естественно я не могу осветить все аспекты функционирования и использования Consul но в статье будет описано достаточно, чтобы пытливый читатель заинтересовался и продолжил изучение глубже.
Consul: «что за птица — с чем едят?»
Лирическое отступление, но по теме.
В текущем мире огромных объемов данных, где распределенные системы их обработки становятся не чем-то из мира недостижимой фантастики но обыденными вещами, вопросы их правильного проектирования и реализации становятся очень важным моментом в последующем развитии этих систем. Каждый, кто хотя бы раз принимал участие в разработке архитектур автоматически масштабируемых, распределенных систем, знает что этот процесс очень трудоемкий и требующий достаточно серьезного стека знаний систем из которых можно строить подобные архитектурные решения. С учетом бурного развития облачных вычислений и появления IaaS платформ — разворачивание масштабируемых систем стало достаточно простым делом. Однако взаимодействие компонентов таких систем (интеграция новых компонентов, удаление неиспользуемых частей и т.д.) всегда вызывает головную боль у архитекторов, devops инженеров и программистов. Для этих целей можно придумывать свой велосипед (шаблоны конфигурационных файлов, поддержка саморегистрации со стороны приложения и т.д.), можно использовать локальные или распределенные системы хранения данных «ключ-значение» (redis, zookeeper, etcd и др.) а можно использовать системы обнаружения сервисов (Service Discovery).
Часто термин Service Discovery (в дальнейшем я буду использовать сокращение — SD) относится к системам сетевого обнаружения (протокол SDP, к примеру) но в последнее время SD используется и в программной части архитектур для взаимного обнаружения связанных компонентов систем. Особенно это касается микросервисного подхода к разработке программных комплексов. MSA (Micro Services Architecture), одними из первопроходцев и популяризаторов которой является Netflix, все чаще становится стандартом для разработки распределенных, авто-масштабируемых, высоко нагруженных систем. И Consul уже много где используется для обеспечения SD в подобного рода системах. К примеру Cisco использует его в своем движке для MSA — Cisco MI.
Собственно, Consul и есть удачное объединение K/V хранилища и SD функционала. Ну а теперь подробнее.Consul: Чем он лучше?
Достаточно резонный вопрос «Зачем нам Consul, если у нас есть Zookeeper и он прекрасно справляется с задачей SD?». Ответ на поверхности — Zookeeper, и подобные системы (etcd, doozerd, redis, etc) не предоставляют функционала SD — их задача всего-лишь хранить данные в том или ином формате и гарантировать их доступность и консистентность в каждый отдельный момент времени (при условии правильной настройки и использования, конечно). Естественно такой модели будет вполне достаточно для обеспечения SD, но вот удобство использования (настройки, обслуживания, и т.д.) частенько оставляет желать лучшего.
К примеру, Zookeeper: это постоянная возня с его кластером, — начиная с первичной настройки (автоматизированная установка zk кластера средствами Ansible или SaltStack может доставить немало хлопот даже продвинутому специалисту), заканчивая передачами софту, использующему Zookeeper, ссылок на кластер вида zk://10.10.1.2:2181,10.10.1.3:2181,10.10.1.5:2181/app (необходимо предварительно знать где расположен кластер, все его ноды). Мало того, — если кластер Zookeeper по какой-то причине «переедет» на другие адреса (очень актуально в облачных средах, MSA архитектурах), придется перезапускать все использующие этот кластер приложения и сервисы.
С Consul все проще: ребята из HashiCorp сделали «все для людей». Consul распространяется как 1 бинарный файл (нет надобности следить за зависимостями, использовать пакетные менеджеры) и любой софт использующий Consul всегда делает запросы к нему на localhost (нет надобности хранить ссылку на кластер или master ноду сервиса), — Consul все берет на себя. Использование Gossip в качестве протокола обмена данными делает Consul быстрым, отказоустойчивым и не требующим выделенного мастера для нормального функционирования. На самом деле мастер как таковой формально имеется (даже кворум мастеров) но это необходимо по большей части для того, чтобы пережить полную остановку всех нод кластера (мастера обеспечивают периодическое сохранение оперативных данных на диск тем самым гарантируя персистентность данных). В итоге, для приложения (микросервиса) использующего Consul вся работа с SD сводится к общению с localhost:8500 — куда бы не переехало приложение — там всегда будет агент Consul. Мало того, для работы с Consul не нужно иметь каких-либо клиентских библиотек (как в случае с Zookeeper) — для этого используется простой и понятный HTTP REST API (простые данные, не более 20 разных API функций), либо DNS сервисы с SRV записями (да, — одна из функций Consul — предоставление DNS интерфейса к зарегистрированным сервисам).
Более подробно можно почитать тут.Consul: Как поставить, и начать работу?
Сразу скажу, что останавливаться подробно на установке и настройке мы не будем — для читающих статью, думаю, это будет достаточно простым упражнением. Лишь одна проблема достойная внимания, — не прозрачность в поиске документации по установке на сайте, потому вот ссылки: начальная установка (как домашнее задание — разработка start/stop скриптов для своего любимого init.d/upstart/systemd — ненужное — вычеркнуть), запуск агентов и инициализация кластера.
Пара замечаний по поводу выбора топологии кластера. Не лишним будет отметить, что Consul не имеет обособленного мастера, который единолично принимал и распространял бы конфигурации сервисов и данные между нодами, — абсолютно любой агент может быть использован для регистрации сервисов и данных. Вообще-то говоря, мастер (точнее кворум мастов) как таковой имеется, и его основная роль — обеспечение персистентности данных при рестартах кластера.Consul: Регистрируем сервис, используем запросы
Итак, имея готовый кластер (или одну ноду для тестов) начнем регистрировать сервисы. Для начала сгенерируем гипотетический сценарий на базе которого будем дальше разбираться с работой Consul: предположим у нас есть классическое web приложение состоящее из нескольких frontend сервисов, нескольких backend сервисов и хранилища данных — пусть будет mongodb. Оговорим сразу же, что инфраструктура тестовая и вопросы наподобие: почему MongoDB не кластеризован?, почему HAProxy, а не Nginx? и т.д. оставляю пытливому читателю в качестве домашнего задания.
При работе с Consul мы будем различать 2 вида сервисов — активные (использующие http rest api для собственной регистрации и внедрения проверок доступности) и пассивные (требующие предварительно приготовленных конфигурационных файлов для Consul). К первым будем относить сервисы разрабатываемые локально (продукт компании и его компоненты), ко вторым: сторонние приложения (необязательно поддерживающие работу с Consul, или не поддерживающих ее вообще, — к примеру MongoDB).
Итак, введем регистрацию для MongoDB сервиса — создадим файл /etc/consul.d/mongodb.json:
{
"service": {
"name": "mongo-db",
"tags": ["mongo"],
"address": "123.23.34.56",
"port": 27017,
"checks": [
{
"name": "Checking "
"script": "/usr/bin/check_mongo.py --host 123.23.34.56 --port 27017",
"interval": "5s"
}
]
}
}
Самое важное тут:
1. address/port — собственно именно эти данные будут получать клиенты Consul в ответ на запрос информации о сервисе «mongo-db». Публикуемый адрес должен быть доступен
2. секция «checks» — список проверок позволяющих идентифицировать жив ли сервис. Это может быть любой скрипт (возвращающий 0 в случае нормального функционирования сервиса; 1 в случае warning статуса сервиса и любое другое значение в случае недоступности сервиса), http проверка (запрашивается некий URL и на основании ответа генерируется состояние сервиса — HTTP/2XX — сервис жив, HTTP/4XX, HTTP/5XX — сервис недоступен)
Подробнее на сайте: описание сервиса, описание проверок.
Последующий рестарт агента (с указанием /etc/consul.d/ как каталога с конфигурациями) примет этот файл и зарегистрирует MongoDB как сервис доступный для SD. Скрипт указанный в секции checks делает подключение к MongoDB на указанном хосте (тестируя доступность сервиса) и, к примеру, делает запрос к какой-то коллекции для проверки доступности данных.
В последствии проверить регистрацию можно при помощи curl:
~/WORK/consul-tests #curl -XGET http://localhost:8500/v1/catalog/service/mongo-db
[{"Node":"mpb.local","Address":"192.168.59.3","ServiceID":"mongo-db","ServiceName":"mongo-db","ServiceTags":["mongo"],"ServiceAddress":"123.23.34.56","ServicePort":27017}]
или с помощью встроенного в Consul DNS сервера:
~/WORK/consul-tests #dig @127.0.0.1 -p 8600 mongo-db.service.consul SRV
; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8600 mongo-db.service.consul SRV
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50711
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
;mongo-db.service.consul. IN SRV
;; ANSWER SECTION:
mongo-db.service.consul. 0 IN SRV 1 1 27017 mbp.local.node.dc1.consul.
;; ADDITIONAL SECTION:
NEST.local.node.dc1.consul. 0 IN A 123.23.34.56
;; Query time: 1 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: Thu Sep 17 17:47:22 2015
;; MSG SIZE rcvd: 152
Использование того или иного способа получения данных из Consul зависит от архитектуры запрашивающего компонента (для скриптов удобнее использовать DNS интерфейс, для компонентов написанных на ЯП высокого уровня — REST запросы или специализированные библиотеки).
Все сервисы, которые могут поддерживать саморегистрацию должны использовать библиотеки для необходимых ЯП: python, java, go, ruby, php. Необходимо не забывать помимо, собственно регистрации сервисов, грамотно разрабатывать скрипты проверки доступности того или иного сервиса чтобы не получить систему с зарегистрированными но не работающими сервисами.Consul: Прощайте конфигурационные файлы.
Собственно добрались до самой сути, — дочитавшим посвящается… Итак в какой-то определенный момент времени мы получили среду в которой зарегистрированы сервисы (mongodb, backend, — к примеру) какую же выгоду можно получить?
В традиционных распределенных системах (без внедренного SD) используются в основном такая техника для добавления нового компонента в систему (скажем при росте нагрузки необходимо создать еще один backend):
1. создается инстанс backend сервиса (зачастую при помощи систем оркестровки типа SaltStack/Puppet/Ansible/Hand-Made scripts/etc)
2. Система оркестровки по шаблонам генерирует новые конфигурационные файлы для сервисов использующих backend (load balancers, frontends, etc)
3. Та же система оркестровки генерирует конфиг файл для этого нового backend сервиса, указывая в нем контактную информацию о mongodb и прочих зависимых компонентах
4. Все зависимые сервисы перечитывают конфигурацию (или рестартуют) пересоздавая соединения между собой
5. Система дожидается конвергенции и переходит в рабочее состояние.
Подобный подход очень затратен — необходимо сделать генерации конфиг файлов, их распространение, перезапуски сервисов и т.д. Ко всему — в процесс вовлечена система оркестровки (сторонний по отношению к рабочей системе компонент) за доступностью которой тоже нужно следить.
SD позволяет существенно упростить этот процесс (как именно, пытливый читатель уже думаю догадался), но требует изменения поведения самих сервисов входящих в систему. И это не только поддержка SD (регистрации сервиса и обнаружения сервисов), но и Fail Tolerance (способность сервиса безболезненно переживать изменения в топологии подчиненных сервисов), активное использование KV хранилищ для обмена конфигурационной информацией, и т.д.
Единственный внешний компонент, который придется использовать в таких конфигурациях — Consul-Template — средство для подключения к Consul разнообразных, не поддерживающих SD, систем, к примеру: HAProxy. Задача этого программного средства отслеживать регистрации/дерегистрации сервисов и изменять конфигурации подчиненных сервисов, т.е. при регистрации нового backend автоматически будет перестроен конфиг HAProxy для включения этого нового инстанса в процесс балансировки нагрузки. Подробнее об этом можно почитать тут.
Собственно применение SD на базе Cunsul, Consul-Template, Consul-KV в принципе может помочь полностью избавится от каких-либо конфигурационных файлов и оставить все на откуп Consul.Как заключение.
В целом, из-за того, что Consul находится в фазе активной разработки возможны некоторые проблемы (из замеченного мной — проблемы с развалом кластера при рестарте всех нод с Consul), но базовый функционал SD работает нормально и каких-либо нареканий незамечено. Напомню еще о поддержке Consul'ом множества дата-центров для обеспечения распределенности.