Содержание статьи
Сегодняшние сети нельзя назвать статичными. Распределенные системы, облачные сервисы, системы виртуализации и микросервисы привели к тому, что управлять при помощи традиционных инструментов становится невозможно. Серверы могут перемещаться, сервисы появляются и отключаются. Вручную отследить очень сложно. На выручку придут системы обнаружения сервисов (Service Discovery), предлагающие дополнительные возможности для управления инфраструктурой.
Возможности Consul
Можно хранить информацию о расположении служб в конфигурационных файлах или использовать DNS, но это не очень подходит в динамической среде или при запуске микросервисов. Если служба выйдет из строя и окажется необходимым быстро подключиться к другому серверу, будут возникать задержки. Системы обнаружения сервисов автоматизируют процесс, позволяя получить ответ на вопрос, где работает нужный сервис, и изменить настройки в случае появления нового или отказа. Обычно под этим подразумевают набор сетевых протоколов (Service discovery protocols), обеспечивающих нужную функцию, хотя в современных реализациях это уже часть архитектуры, позволяющей обнаруживать связанные компоненты. На сегодня существует несколько решений, реализующих хранение информации об инфраструктуре, — как относительно сложных, использующих key/value-хранилище и гарантирующих доступность (ZooKeeper, Doozer, etcd), так и простых (SmartStack, Eureka, NSQ, Serf). Но, предоставляя информацию, они не слишком удобны в использовании и сложны в настройках.
Consul, разработанный в HashiCorp, также известной своими инструментами вроде Vagrant и Packer, вобрал лучшее, что есть у аналогов. При этом он очень прост в развертывании, может легко масштабироваться на несколько дата-центров, дружественен в использовании и поддержке, что делает его идеальным для современных инфраструктур. К тому же он мультисистемный. В отличие от многих подобных решений, он работает на Windows, OS X, FreeBSD, Solaris и Linux.
Consul предоставляет ряд функций, обеспечивающих доступность информации об инфраструктуре. Service Discovery позволяет обнаружить сервисы и заносить их в базу, называемую каталогом. Любые приложения, использующие Consul, обращаются к нему через localhost, то есть приложению не нужно знать, где хранятся данные, Consul все берет на себя. Для поиска предлагается API, реализованный через HTTP и DNS. Последний вариант дает возможность работать с Consul приложениям, которые о нем ничего не знают. Поддерживается два вида DNS-запроса: поиск узлов (node lookups) и сервисов (service lookups).
<node>.node[.datacenter].<domain>
[tag.]<service>.service[.datacenter].<domain>
Как видим, в запросе также можно конкретизировать дата-центр и, используя тег, указать нужный тип сервиса/узла. В случае если запросу соответствует несколько IP, они возвращаются случайным образом, чем обеспечивается простая балансировка нагрузки.
Служба регистрируется при помощи установки агента и настройки его параметров или через HTTP API. Последний вариант позволяет регистрировать любой внешний сервис, не принадлежащий дата-центру.
Установленные агенты собирают более 200 метрик и могут предоставлять любое количество проверок состояния системы и сервиса, которое необходимо. Администраторы самостоятельно определяют правила проверок. Полученная информация может быть использована для мониторинга, и Consul вполне заменяет системы мониторинга вроде Nagios. Обнаружив проблему с сервисом, Consul автоматически перенаправляет запрос к другому работающему узлу. При этом реализовано два сценария. Если узел уведомляет Consul, что он выключается и будет недоступен (left), его сервисы и проверки удаляются из каталога. Однако когда узел или сервис пропадает без предупреждения (failed), он помечается как критический, но информация некоторое время в каталоге сохраняется, а Consul пытается периодически проверить его доступность.
Также Consul реализует иерархическое key/value-хранилище, которое может быть использовано для любых целей: динамической конфигурации, обмена данными, маркировки, координации доступа к сервисам, выбора лидера и так далее. Доступ к данным производится при помощи HTTP API. Тут нужно отметить, что Consul скорее не заменяет, а дополняет средства конфигурации вроде Puppet и Chef.
Написан на Go и доступен под Mozilla Public License 2.0.
Архитектура Consul
Построен Consul по клиент-серверной схеме, использована децентрализованная архитектура. Агенты устанавливаются на все узлы Consul, позволяют ими управлять, обнаруживают сервисы, собирают данные о состоянии, реализуют интерфейсы DNS, API HTTP и RPC CLI. Агент может быть запущен в одном из двух режимов — клиентском или серверном. Клиентская часть собирает данные об узле и сервисе и отсылает их серверу. Компоненты инфраструктуры в поиске серверов или сервисов обращаются с запросом к любому агенту сети Consul, который пересылает его доступному серверу. Если сервер не может ответить на запрос, он направляет его на другие кластеры и возвращает полученный ответ.
Агент с функциями сервера имеет расширенный список возможностей: сбор данных от агента, обмен сообщениями о состоянии с другими серверами, автоматический выбор лидера в кластере (по алгоритму Raft), репликация данных. Сеть Consul может использовать один сервер, но сами разработчики из HashiCorp рекомендуют, чтобы избежать потери данных, использовать от трех до пяти серверов в дата-центре (особенности Raft: кластер из трех узлов сохраняет работоспособность при выходе одного сервера). Серверы образуют кластер и самостоятельно выбирают лидера, отвечающего за координацию. Первый/единственный сервер обычно запускается в так называемом bootstrap-режиме, то есть назначается лидером вручную, но в последующем можно убрать эту «привилегию». Кворум для проведения операций и обеспечения согласованности требуется в каждом дата-центре. При наличии нескольких ДЦ в каждом создается отдельный кластер.
Для обмена данными между агентами используется протокол gossip, позволяющий не только транслировать события и запросы, но и обнаруживать неработающие узлы и уведомлять об этом остальную часть кластера. Обмен между агентами по gossip происходит в LAN — 8301/TCP/UDP, в WAN — 8302/TCP/UDP, RPC клиента с сервером и репликация между серверами — 8300/TCP, CLI RPC — 8400/TCP, HTTP API — 8500/TCP, DNS-интерфейс — 8600/TCP/UDP.
Для защиты подключения может быть использован ключ, уникальный для всех членов кластера и TLS. Кроме управления через API и CLI, для удобного просмотра параметров реализован веб-интерфейс. Поддерживается интеграция с Atlas — еще одним решением HashiCorp, позволяющим разработчикам быстро развертывать приложения.
Установка Consul
Исходный код доступен на GitHub, поставляются готовые ZIP-архивы, собранные для 32/64-битных и ARM-версий Windows, OS X, FreeBSD, Solaris и Linux. Отдельно доступны ссылки на вспомогательные инструменты, в том числе разработанные комьюнити, SDK и интерфейс. Здесь есть полезные решения. Например, Consul Template позволяет отслеживать шаблоны и распространять их, если обнаружены изменения. C его помощью можно легко обновлять конфигурационные файлы. На GitHub поиском можно найти библиотеки для разных языков программирования, позволяющих создавать совместимые с Consul приложения. Также доступны готовые образы, дающие возможность развернуть Consul-кластер на базе Docker. Для Ubuntu есть два PPA: ppa:jbboehr/consul и ppa:bcandrea/consul. Но в них не самая актуальная версия, хотя для простого знакомства вполне достаточная. Кроме того, мы получаем сразу нужные конфигурационные файлы и в последующем можем просто подменить бинарник более новой версией.
Рассмотрим развертывание при помощи официального архива. Чтобы познакомиться со всеми возможностями и командами Сonsul, желательно использовать три сервера и один клиент, минимально подойдет сервер + клиент.
Для форматирования вывода в JSON-формате понадобится утилита jq:
$ sudo apt-get instal jq unzip
$ wget -c https://releases.hashicorp.com/consul/0.6.3/consul_0.6.3_linux_amd64.zip
Архив содержит единственную утилиту consul, реализующую агент. В зависимости от параметров можем запускать как клиент, так и сервер. Для удобства использования разархивируем файл в каталог, видимый переменной PATH. В идеале следует создать учетную запись, из-под которой в последующем и запускать Сonsul, но для экспериментов достаточно и того, что есть:
$ sudo unzip consul_0.6.3_linux_amd64.zip -d /usr/bin
Запускаем клиент
Список всех ключей можно узнать, запустив Consul без параметров, подробно они раскрыты в документации, значение некоторых понятно из описания. Стоит их изучить, чтобы затем проще было ориентироваться в возможностях.
Xakep #207. Дистанционное банковское ограбление
Например, ключ -dev позволит запустить агент в development-режиме, в котором будут выводиться основные параметры среды, — очень полезно при знакомстве:
$ consul agent -dev -bind 192.168.86.10
Как правило, на сервере имеется несколько сетевых интерфейсов, Consul может определить нужный для работы автоматически, но это не всегда получается. Поэтому лучше сразу указывать на интерфейс при помощи -bind
. По умолчанию агентом используется DNS-имя узла, но можно задать произвольное при помощи -node
. Также, если не указать, будет создан дата-центр dc1, но при необходимости его можно переопределить. Еще один важный параметр, -join
, позволяет указать на сервер, к которому нужно подключиться. После подключения информация о других агентах будет получена автоматически. Но пока у нас сервера нет.
Кроме -dev
, есть еще один полезный ключ, позволяющий просмотреть все текущие установки:
$ consul info
Параметры на период знакомства и отладки можно указывать в строке запуска, но в дальнейшем лучше использовать конфигурационные файлы в формате JSON, в которых прописывать параметры работы агента, сервисы, проверки и прочее.
Создадим каталог для описания настроек:
$ sudo mkdir /etc/consul.d
Внутри при желании можно создать еще подкаталоги, например для анонса определенных сервисов, мониторинга и проверки. Анонсируем сервисы. Для этого создадим файл, в котором пропишем веб-сервис (будем считать, что он настроен):
$ echo '{"service": {"name": "web", "tags": ["nginx"], "port": 80}}' > /etc/consul.d/web.json
Здесь анонсирован сервис на локальном узле, но таким же образом мы можем прописать любой другой узел, указав его имя или IP. Плюс можем задать другие ключи:
$ nano /etc/consul.d/search.json
"service": {
"name": "google",
"Datacenter": "dc1",
"tags": ["search"],
"Service": "search"
"address": "www.google.com",
"port": 80
}
Cервис можно добавить, используя API:
$ curl -X PUT -d '{"Datacenter": "dc1", "Node": "google", "Address": "www.google.com", "Service": {"Service": "search", "Port": 80}}' http://127.0.0.1:8500/v1/catalog/register
Протестировать правильность конфигурационных файлов позволяет ключ configtest, можно указать конкретный файл или каталог:
$ consul configtest -config-dir /etc/consul.d
Если ошибок нет, используем конфигурационные файлы при запуске агента:
$ consul agent -config-dir /etc/consul.d
В отладочном выводе будет иметься информация о сервисах Web и Google. При помощи DNS можем получить запрос всех узлов, предоставляющих сервис Web:
$ dig @127.0.0.1 -p 8600 web.service.consul
Добавим тег:
$ dig @127.0.0.1 -p 8600 nginx.web.service.consul
Такой же запрос можем сделать, используя API:
$ curl http://127.0.0.1:8500/v1/catalog/service/web
Проверки доступности реализуются при помощи любых возможных механизмов и команд. Например, узел проще проверить при помощи ping:
$ echo '{"check": {"name": "ping", "script": "ping -c1 google.com >/dev/null", "interval": "30s"}}' > /etc/consul.d/ping.json
Веб-сервис проверяется доступностью определенной страницы. Если в ответ получаем статус ОK, значит, все нормально. При этом Consul берет на себя всю последующую обработку запроса:
$ echo '{"service": {"name": "web", "port": 80, "check": {"script": "curl localhost >/dev/null 2>&1", "interval": "10s"}}}' >> /etc/consul.d/web.json
Перезапускаем агент и проверяем:
$ curl -s http://127.0.0.1:8500/v1/health/service/web
Клиентская часть готова.
Запускаем сервер
Запуск агента в режиме сервера отличается добавлением одного параметра -server
. Дополнительно можем указать старт в bootstrap-режиме, то есть сами назначаем его главным. Если сервер один, то так и поступаем. Есть еще один похожий параметр — -bootstrap-expect
, после него указывается количество серверов, подключение которых ожидаем. В этом варианте лидер выбирается автоматически, но при условии, что будет доступен кворум для указанного числа серверов:
$ sudo consul agent -server -bootstrap-expect 3 -data-dir /var/consul -bind=192.168.86.1 -config-dir /etc/consul.d
Аналогичным образом запускаются все остальные серверы. Если использовался параметр bootstrap, то он, естественно, указывается только для одного. Проще сразу записать все параметры в JSON-файл, который распространить на все серверы и клиенты (фактически клиент — это "server": false
, и его можно легко сделать сервером, изменив один параметр):
{
"bootstrap_expect": 3
"server": true,
"datacenter": "first",
"data_dir": "/var/consul"
}
Запущенный агент по сути представляет собой кластер из одного узла, так как не знает о других системах. Поэтому его нужно подключить к существующему кластеру. Открываем терминал и вводим, указывая через пробел IP одного или нескольких серверов:
$ sudo consul join 192.168.86.1
В JSON-файле это соответствует параметру start_join
. В ответ должны получить сообщение о подключении к кластеру. Сразу можем просмотреть список всех членов кластера:
$ consul members
Через API:
$ curl http://localhost:8500/v1/catalog/nodes | jq .
Список серверов через DNS:
$ dig @127.0.0.1 -p 8600 server.node.consul
Список всех серверов в кластере и текущий лидер:
$ curl -s http://localhost:8500/v1/status/peers | jq .
$ curl -s http://localhost:8500/v1/status/leader | jq .
Подробная информация об агенте:
$ curl -s http://localhost:8500/v1/agent/self | jq .
Это простой вариант подключения. Для защиты можно сгенерировать ключ consul keygen, который затем указывать при подключении агентов к кластеру в параметре encrypt. Опять же проще создать файл и распространять его среди остальных агентов:
$ nano /etc/consul.d/encrypt.json
{"encrypt": "Yuoo8956.....UinT=="}
Для определения времени запроса между двумя узлами используется команда consul rtt
. Для выполнения команд на удаленных узлах — consul exec. Узлы можно указать в привязке к конкретному дата-центру, тегам, сервисам и маске имени. Так же несложно использование key/value-хранилища. Чтобы занести пару key1/value1, выполняем команду
$ curl -X PUT -d 'value1' http://localhost:8500/v1/kv/group1/key1
Данные расходятся по кластеру, и их можно просмотреть на любом агенте:
$ curl -s http://localhost:8500/v1/kv/group1/key1
В ответ получим массив, в котором параметр "Value": будет закодирован при помощи Base64, чтобы раскодировать, следует использовать утилиту base64 -d
. В реализации Consul key/value поддерживает две дополнительные опции acquire и release, обеспечивающие блокировку (показывается как LockIndex) и модификации значения ключа (ModifyIndex и CreateIndex). Блокировку часто используют в сессиях для реализации механизма выбора лидера.
В ранних версиях Consul веб-интерфейс нужно было ставить отдельно. Теперь он является частью агента, поэтому достаточно при запуске добавить ключ -ui
, и затем можно входить, набрав в браузере http://localhost:8500/ui. Здесь четыре вкладки, позволяющие просмотреть сервисы, узлы и ACL, просмотреть и создать пару в хранилище key/value. По умолчанию пароль не требуется, но его можно установить в Settings.
Заключение
Как видим, Consul — это, скорее, фреймворк, на основе которого можно реализовать решение для распределенных систем, позволяющее определять сервисы, отслеживать события, мониторить системы, конфигурировать приложения и многое другое.