91 lines
6.7 KiB
Markdown
91 lines
6.7 KiB
Markdown
# Consul: от имени до ответа приложения
|
||||
|
|
|
|||
|
|
Consul хранит сведения об экземплярах сервисов: их идентификаторы, адреса и результаты проверок работоспособности. Клиент может найти экземпляр по имени сервиса, а затем отправить запрос непосредственно ему.
|
|||
|
|
|
|||
|
|
В стенде у сервиса `orders` два экземпляра: `app-a` и `app-b`. **Предскажите:** если остановить один из них, изменятся ли каталог Consul, список здоровых экземпляров и сохранённый клиентом адрес одновременно?
|
|||
|
|
|
|||
|
|
Все команды выполняются из каталога `seminar`; [подготовка стенда](../readme.md#самостоятельный-запуск-опытов).
|
|||
|
|
|
|||
|
|
## 1. Найти экземпляры
|
|||
|
|
|
|||
|
|
Запустите сервисы и дождитесь, пока оба экземпляра пройдут проверки:
|
|||
|
|
|
|||
|
|
~~~powershell
|
|||
|
|
docker compose up -d --wait consul app-a app-b
|
|||
|
|
docker compose run --rm -T tools python3 consul/client.py wait
|
|||
|
|
~~~
|
|||
|
|
|
|||
|
|
Сравните каталог регистраций и список здоровых экземпляров:
|
|||
|
|
|
|||
|
|
~~~powershell
|
|||
|
|
docker compose run --rm -T tools curl -fsS "http://consul:8500/v1/catalog/service/orders"
|
|||
|
|
docker compose run --rm -T tools curl -fsS "http://consul:8500/v1/health/service/orders?passing=true"
|
|||
|
|
~~~
|
|||
|
|
|
|||
|
|
Каталог содержит зарегистрированные экземпляры независимо от их текущего состояния. Второй запрос с `passing=true` возвращает только экземпляры, прошедшие проверки. В ответе каталога найдите `ServiceName`, `ServiceID`, `ServiceAddress` и `ServicePort`: это имя сервиса, ID экземпляра, его адрес и порт.
|
|||
|
|
|
|||
|
|
Адреса экземпляров можно получить и через DNS-интерфейс Consul:
|
|||
|
|
|
|||
|
|
~~~powershell
|
|||
|
|
docker compose run --rm -T tools dig "@consul" -p 8600 orders.service.consul A +short
|
|||
|
|
docker compose run --rm -T tools dig "@consul" -p 8600 orders.service.consul SRV +short
|
|||
|
|
~~~
|
|||
|
|
|
|||
|
|
Запись **A** содержит IPv4-адрес. Строка **SRV** имеет вид `приоритет вес порт имя-узла`, поэтому позволяет узнать и порт приложения — в нашем случае `8080`. Аргумент `-p 8600` задаёт порт самого DNS-сервера Consul.
|
|||
|
|
|
|||
|
|
**Вопрос:** откуда клиент узнает порт приложения, если запросил только A-запись?
|
|||
|
|
|
|||
|
|
## 2. Сохранить адрес и выполнить запрос
|
|||
|
|
|
|||
|
|
~~~powershell
|
|||
|
|
docker compose run --rm -T tools python3 consul/client.py save
|
|||
|
|
docker compose run --rm -T tools python3 consul/client.py cached
|
|||
|
|
~~~
|
|||
|
|
|
|||
|
|
Команда `save` выбирает первый здоровый экземпляр по ID — `app-a` — и сохраняет его адрес. Команда `cached` обращается по сохранённому адресу. В HTTP-ответе поле `instance` показывает, кто обработал запрос.
|
|||
|
|
|
|||
|
|
Таким образом, клиент сначала получает адрес через HTTP API Consul, затем обращается к приложению. DNS-запросы выше иллюстрируют другой способ поиска адреса.
|
|||
|
|
|
|||
|
|
## 3. Остановить приложение и сравнить результаты
|
|||
|
|
|
|||
|
|
Остановите `app-a` и дождитесь, пока Consul обнаружит сбой:
|
|||
|
|
|
|||
|
|
~~~powershell
|
|||
|
|
docker compose stop app-a
|
|||
|
|
docker compose run --rm -T tools python3 consul/client.py wait --ids app-b
|
|||
|
|
~~~
|
|||
|
|
|
|||
|
|
Теперь сравните каталог, список здоровых экземпляров и DNS-ответ:
|
|||
|
|
|
|||
|
|
~~~powershell
|
|||
|
|
docker compose run --rm -T tools curl -fsS "http://consul:8500/v1/catalog/service/orders"
|
|||
|
|
docker compose run --rm -T tools python3 consul/client.py list
|
|||
|
|
docker compose run --rm -T tools dig "@consul" -p 8600 orders.service.consul A +short
|
|||
|
|
~~~
|
|||
|
|
|
|||
|
|
В каталоге всё ещё есть `app-a`: остановка приложения сама по себе не удаляет регистрацию. Список здоровых экземпляров содержит только `app-b`, а DNS возвращает лишь его адрес.
|
|||
|
|
|
|||
|
|
Сравните запрос по сохранённому адресу с новым поиском:
|
|||
|
|
|
|||
|
|
~~~powershell
|
|||
|
|
docker compose run --rm -T tools python3 consul/client.py cached
|
|||
|
|
docker compose run --rm -T tools python3 consul/client.py fresh
|
|||
|
|
~~~
|
|||
|
|
|
|||
|
|
`cached` завершается с `REQUEST FAILED` и кодом 1 — это ожидаемый результат. `fresh` заново ищет здоровый экземпляр и получает ответ от `app-b`.
|
|||
|
|
|
|||
|
|
Проверки выполняются периодически, поэтому Consul замечает остановку с задержкой. Но даже после обнаружения сбоя сохранённый клиентом адрес не меняется сам. В этом опыте клиент хранит его в файле без срока действия; автоматическое истечение записей рассмотрим в [разделе DNS](../dns/readme.md).
|
|||
|
|
|
|||
|
|
**Вопросы для самопроверки:** гарантирует ли свежий поиск успех следующего запроса? Зачем клиенту тайм-аут и возможность выбрать другой экземпляр? Почему повтор операции с побочным эффектом требует отдельной защиты от повторного выполнения?
|
|||
|
|
|
|||
|
|
## 4. Восстановить исходное состояние
|
|||
|
|
|
|||
|
|
~~~powershell
|
|||
|
|
docker compose start app-a
|
|||
|
|
docker compose run --rm -T tools python3 consul/client.py wait
|
|||
|
|
~~~
|
|||
|
|
|
|||
|
|
В этом стенде один агент Consul и два приложения. Отказоустойчивость самого Consul здесь не проверяется.
|
|||
|
|
|
|||
|
|
Исходники: [приложение и регистрация](app.py), [клиент](client.py). Документация: [регистрация сервиса](https://developer.hashicorp.com/consul/api-docs/agent/service), [DNS-интерфейс](https://developer.hashicorp.com/consul/docs/discover/dns).
|