Итак, добро пожаловать во вторую часть серии, посвященную использованию Consul для обнаружения сервисов вместе с докером. Во второй статье мы рассмотрим, как вы можете использовать ряд инструментов, связанных с Консулом, так что упростите обнаружение сервисов и несколько других связанных функций.
Для других статей в этой серии вы можете посмотреть здесь:
Обзор архитектуры и что мы будем делать
В этой статье мы расширим настройки, которые мы создали в предыдущей статье . В этой статье мы создали следующую архитектуру микросервисов с использованием Docker и Consul:
Итак, если вы этого не сделали, пройдитесь по шагам в этой статье и убедитесь, что у вас есть настройка, которая может использовать Docker Swarm, Docker Compose и имеет правильную настройку сети Docker. Чтобы проверить, все ли настроено правильно, проверьте вывод следующих команд:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
# See the previous article for the definitions of these commands # # First, check Consul. If consul isn 't up, the swarm won' t come up or work. $ . dm-env nb-consul $ docker ps --format '{{ .ID }}\t{{ .Image }}\t{{ .Command }}\t{{ .Names}}' b5d55e6df248 progrium/consul "/bin/start -server -" clever_panini # if consul isn't up, make sure to start it, before trying any of the swarm # commands. $ . dm-env nb1 --swarm $ docker ps -a --format '{{ .ID }}\t{{ .Image }}\t{{ .Command }}\t{{ .Names}}' bf2000882dcc progrium/consul "/bin/start -ui-dir /" nb1/consul_agent_1 a1bc26eef516 progrium/consul "/bin/start -ui-dir /" nb2/consul_agent_2 eb0d1c0cc075 progrium/consul "/bin/start -ui-dir /" nb3/consul_agent_3 d27050901dc1 swarm:latest "/swarm join --advert" nb3/swarm-agent f66738e086b8 swarm:latest "/swarm join --advert" nb2/swarm-agent 0ac59ef54207 swarm:latest "/swarm join --advert" nb1/swarm-agent 17fc5563d018 swarm:latest "/swarm manage --tlsv" nb1/swarm-agent-master # this should at least list the swarm master, swarm agents, and the consul agents. # if not, see previous article on how to setup your environment. # the last thing we need to check is our network. When the swarm master is selected # run the following command: $ docker network ls | grep -i my-net 8ecec72e7b68 my-net overlay # if it shows an overlay network with my-net we're all set. |
Если вы видите какие-либо внешние или внутренние службы, возможно, лучше их остановить и удалить. Таким образом, вы можете следовать командам в остальной части этой статьи.
Итак, что мы будем делать в этой статье. Что ж, мы покажем вам, как использовать следующие два инструмента из вселенной Consul:
- Consultemplate : с Consultemplate вы можете прослушивать события от Consul (например, когда добавляется служба), и на основе этих обновлений переписать и перезагрузить файл конфигурации. Мы будем использовать это для автоматического обновления конфигурации обратного прокси-сервера на основе HAProxy с последним набором исправных служб.
- EnvConsul : С Envconsul вы можете легко читать переменные окружения напрямую из Consul, вместо того, чтобы передавать их вручную при запуске контейнера Docker. Мы покажем, как вы могли бы использовать это с услугами, которые мы используем в этих статьях.
Консультация, докер и HAProxy
В предыдущей настройке мы создали архитектуру, как показано на рисунке выше. Хотя это уже отлично работало благодаря использованию DNS-функций Consul для обнаружения служб и некоторого базового переключения при сбое, нам пришлось полагаться на DNS и время ожидания сокетов, чтобы определить, когда служба вышла из строя. Хотя это работало, оно не было таким надежным и предлагало лишь некоторые простые функции восстановления после сбоев и балансировки нагрузки. В этом сценарии мы собираемся создать следующее:
Таким образом, у нас будет следующий сценарий:
- Пользователь получит доступ к нашему веб-сервису через HAProxy.
- HAProxy перенаправит запрос в одну из исправных служб.
- Фронт-сервис, хочет получить доступ к бэкэнд-сервису. Это также делается через компонент HAProxy.
Консул удостоверится, что всякий раз, когда служба регистрируется в Консуле, она обновляет конфигурацию HAProxy.
Как это работает
Если вы извлекли хранилище для этих статей ( https://github.com/josdirksen/next-build-consul ), вы также можете найти каталог с именем extra / consul-template . В этом каталоге находится HAProxy, который мы будем использовать для этого примера. Я также добавил его в dockerhub ( https://hub.docker.com/r/josdirksen/demo-haproxy/) , что немного упрощает его использование. Прежде чем мы рассмотрим, как нам нужно определить наш шаблон, давайте посмотрим, что делает этот образ докера. Проще всего взглянуть на скрипт запуска:
01
02
03
04
05
06
07
08
09
10
11
|
#!/bin/bash HAPROXY= "/etc/haproxy" PIDFILE= "/var/run/haproxy.pid" CONFIG_FILE=${HAPROXY}/haproxy.cfg cd "$HAPROXY" haproxy -f "$CONFIG_FILE" -p "$PIDFILE" -D -st $(cat $PIDFILE) /usr/local/bin/consul-template -consul=${CONSUL_ADDRESS} -config=/consul.hcl |
Здесь нет ничего особенного, что происходит, когда мы запускаем этот контейнер, consul-template будет работать с указанным файлом конфигурации. Обратите внимание, что нам нужно предоставить переменную окружения CONSUL_ADDRESS, чтобы указать шаблон-консула одному из наших агентов или серверу консула. Интересный материал находится в файле consul.hcl :
01
02
03
04
05
06
07
08
09
10
|
max_stale = "10m" retry = "10s" wait = "5s:20s" template { source = "/etc/haproxy/haproxy.template" destination = "/etc/haproxy/haproxy.cfg" command = "/hap.sh" perms = 0600 } |
этот файл довольно очевиден. В основном происходит то, что всякий раз, когда что-то меняется в Consul, шаблон haproxy.template будет запускаться против информации в Consul, и в результате будет заменен файл haproxy.cfg . После этого запускается команда hap.sh для перезагрузки конфигурации. Для полноты картины файл hap.sh выглядит так:
1
2
3
|
#!/bin/bash haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -D -st $(cat /var/run/haproxy.pid) |
Что это делает, это перезагрузить файл конфигурации в чистом виде. Итак, что в шаблоне? Давайте посмотрим на haproxy.template :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
global log 127.0 . 0.1 local0 log 127.0 . 0.1 local1 notice chroot /var/lib/haproxy user haproxy group haproxy defaults log global mode http option httplog option dontlognull balance roundrobin timeout connect 5000 timeout client 50000 timeout server 50000 errorfile 400 /etc/haproxy/errors/ 400 .http errorfile 403 /etc/haproxy/errors/ 403 .http errorfile 408 /etc/haproxy/errors/ 408 .http errorfile 500 /etc/haproxy/errors/ 500 .http errorfile 502 /etc/haproxy/errors/ 502 .http errorfile 503 /etc/haproxy/errors/ 503 .http errorfile 504 /etc/haproxy/errors/ 504 .http listen stats bind *: 8001 stats enable stats uri / stats auth admin:123123q stats realm HAProxy\ Statistics frontend nb-front bind *: 1080 mode http default_backend nb-frontend frontend nb-back bind *: 1081 mode http default_backend nb-backend backend nb-frontend balance roundrobin{{range service "frontend-service" }} server {{.Node}} {{.Address}}:{{.Port}} check{{end}} backend nb-backend balance roundrobin{{range service "backend-service" }} server {{.Node}} {{.Address}}:{{.Port}} check{{end}} |
Первые пару строк не интересны. Становится интересным, где мы определяем внешний интерфейс и элементы внутреннего интерфейса . Здесь мы говорим о том, что мы указываем, что haproxy будет прослушивать запрос внешнего интерфейса на порту 1080 и перенаправлять эти запросы службам, определенным в внутреннем интерфейсе nb-frontend . В этом элементе мы настраиваем шаблон. В этом примере мы берем все сервисы с именем frontend-service от Consul, и для каждого сервиса мы записываем запись. Поэтому, когда мы вызываем haproxy через порт 1080, он перенаправляет запрос любой из служб с именем frontend-service, зарегистрированным в Consul. Мы делаем то же самое для бэкэнд-сервиса .
Запустить его!
Итак, теперь, когда мы знаем, как это работает, пришло время запустить этот haproxy. Для этого мы определили файл docker-compose, который будет запускать HAProxy на узле nb1 :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
version: '2' services: nb-proxy: image: josdirksen/demo-haproxy container_name: nb-haproxy ports: - 1080 : 1080 - 1081 : 1081 environment: - CONSUL_ADDRESS= 192.168 . 99.106 : 8500 - "constraint:node==nb1" networks: default : external: name: my-net |
Для этого выполните следующие команды:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
# make sure we're at the swarm master $ . dm-env nb1 --swarm # in the root of the nextbuild-consul project $ docker-compose -f ./docker-compose-haproxy.yml up -d Creating nb-haproxy $ docker ps -a --format '{{ .ID }}\t{{ .Image }}\t{{ .Command }}\t{{ .Names}}' dc28caa4c420 josdirksen/demo-haproxy "/startup.sh" nb1/nb-haproxy bf2000882dcc progrium/consul "/bin/start -ui-dir /" nb1/consul_agent_1 a1bc26eef516 progrium/consul "/bin/start -ui-dir /" nb2/consul_agent_2 eb0d1c0cc075 progrium/consul "/bin/start -ui-dir /" nb3/consul_agent_3 d27050901dc1 swarm:latest "/swarm join --advert" nb3/swarm-agent f66738e086b8 swarm:latest "/swarm join --advert" nb2/swarm-agent 0ac59ef54207 swarm:latest "/swarm join --advert" nb1/swarm-agent 17fc5563d018 swarm:latest "/swarm manage --tlsv" nb1/swarm-agent-master |
В моей настройке я вижу, что HAProxy запущен. Но поскольку у нас не запущены какие-либо серверные или внешние службы, конфигурация haproxy должна отражать это:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
$ docker exec -ti nb1/nb-haproxy cat /etc/haproxy/haproxy.cfg | tail -n 15 frontend nb-front bind *: 1080 mode http default_backend nb-frontend frontend nb-back bind *: 1081 mode http default_backend nb-backend backend nb-frontend balance roundrobin backend nb-backend balance roundrobin |
И если мы откроем порт 1080 (для внешнего интерфейса) или 1081 (для внутреннего API), мы увидим ошибку от HAProxy.
Этого и следовало ожидать, так как у нас не запущен ни один внешний или внутренний сервис. Итак, давайте предоставим HAProxy ряд сервисов для работы с:
1
2
3
4
|
$ docker-compose -f ./docker-compose-backend.yml up -d Creating Backend2 Creating Backend3 Creating Backend1 |
Теперь у нас должно быть несколько бэкэндов, работающих за HAProxy. Сначала давайте проверим, обновил ли Консул наш экземпляр HAProxy:
1
2
3
4
5
6
7
8
9
|
$ docker exec -ti nb1/nb-haproxy cat /etc/haproxy/haproxy.cfg | tail -n 8 backend nb-frontend balance roundrobin backend nb-backend balance roundrobin server a1bc26eef516 10.0 . 9.7 : 8081 check server bf2000882dcc 10.0 . 9.9 : 8081 check server eb0d1c0cc075 10.0 . 9.8 : 8081 check |
Круто, верно! В Haproxy теперь определены три сервиса. Это должно позволить нам вызвать http: //nb1.local: 1081 и вернуть API одного из внутренних сервисов:
Если вы обновляете пару раз, вы должны увидеть, как он переключается между различными службами.
И если мы убьём одного, мы увидим, что он автоматически пропустит убитого:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
$ docker stop nb1/Backend1 nb1/Backend1 $ curl nb1.local: 1081 { "result" : { "servername" : "Server2" , "querycount" : 80 } } $ curl nb1.local: 1081 { "result" : { "servername" : "Server3" , "querycount" : 86 } } |
Теперь давайте посмотрим, могут ли наши веб-службы использовать это таким же образом. Для этого мы запускаем компоненты внешнего интерфейса, как это:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
$ docker-compose up -f ./docker-compose-frontend-proxy # remember we killed one of the backend services, so we only see two backend ones $ docker exec -ti nb1/nb-haproxy cat /etc/haproxy/haproxy.cfg | tail -n 10 backend nb-frontend balance roundrobin server a1bc26eef516 10.0 . 9.11 : 8090 check server bf2000882dcc 10.0 . 9.9 : 8090 check server eb0d1c0cc075 10.0 . 9.10 : 8090 check backend nb-backend balance roundrobin server a1bc26eef516 10.0 . 9.7 : 8081 check server eb0d1c0cc075 10.0 . 9.8 : 8081 check |
И похоже, что HAProxy корректно обновляется с помощью новых сервисов. Теперь мы должны иметь возможность вызывать порт 1080 на haproxy, чтобы получить один из сервисов внешнего интерфейса, и использовать кнопку для вызова одного из доступных сервисов внутреннего интерфейса (еще раз через HAproxy).
И все работает как положено! Если вы обновите эту страницу, вы увидите, что она циклически переключается между внешними службами, а когда вы несколько раз нажмете кнопку, она будет вызывать только доступные службы. И, как и следовало ожидать, как только мы снова запустим бэкэнд-сервис, он будет отображаться в списке при нажатии кнопки:
1
2
|
$ docker start nb1/Backend1 nb1/Backend1 |
Результаты в:
HAProxy и консул шаблон Выводы
Это было очень быстрое введение в использование Docker вместе с Consultemplate и HAProxy. Как вы видели, заставить все это работать довольно легко. После того, как вы настроили докер и консул, связать дополнительные компоненты стало намного проще. В реальном сценарии мы также должны зарегистрировать HAProxy в Consul, чтобы другие службы могли легко найти экземпляр HAProxy.
В последней части этой статьи мы кратко рассмотрим некоторые функции, предоставляемые EnvConsul.
EnvConsul, легко предоставить свойства среды при запуске приложения.
Обычный способ передачи данных конфигурации в приложение (особенно в архитектуре докера / микросервисов) — использование переменных среды. Это простой, ненавязчивый, независимый от языка способ настройки ваших служб. Это даже одна из тем приложения 12 фактор .
«Приложение с двенадцатью факторами сохраняет конфигурацию в переменных среды (часто сокращается до env vars или env). Env vars легко переключать между развертываниями без изменения кода; в отличие от конфигурационных файлов, существует небольшая вероятность того, что они случайно попадут в репозиторий; и в отличие от пользовательских файлов конфигурации или других механизмов конфигурации, таких как Java System Properties, они являются независимым от языка и ОС стандартом ».
Однако, это становится очень громоздким, когда вы имеете дело с большими приложениями или большими конфигурациями, особенно когда вам приходится иметь дело с экранированием кавычек / переносов строк и т. Д.
К счастью, мы можем решить эту проблему с Консулом. Как вы, наверное, уже знаете, Consul также является распределенным хранилищем Key-Value:
С EnvConsul мы можем использовать информацию из хранилища KV в Консуле в качестве параметров среды перед запуском нашего приложения. Так как это будет работать? Мы можем проверить это очень легко, поскольку EnvConsul — это просто исполняемый файл golang, который мы можем запустить. Я добавил версию для Mac в хранилище (в каталоге extras ), но вы можете скачать сборки для вашей ОС здесь: https://releases.hashicorp.com/envconsul/0.6.1/
Мы просто запустим его и посмотрим, что произойдет:
1
2
3
4
5
6
|
./envconsul -consul=nb-consul.local: 8500 -prefix docker -once env ... network/v1. 0 /endpoint/815dd44b77f391bd9a63f4e107aa1a7d3f371c91427abcf4be34493aa7ec25cd/= nodes/ 192.168 . 99.112 : 2376 = 192.168 . 99.112 : 2376 swarm/nodes/ 192.168 . 99.110 : 2376 = 192.168 . 99.110 : 2376 ... |
Я пропустил большую часть результатов, но в основном то, что мы здесь делаем, это использование env-consul, чтобы получить все ключи, которые он сохранил в дереве докеров , и добавить их в качестве переменных среды. После того, как они установлены, мы запускаем команду env , которая просто выводит все переменные окружения, которые у нас есть. Если вы запустите это самостоятельно, вы увидите множество информации, связанной с docker-network и docker-swarm, установленной в качестве переменных среды.
Конечно, мы также можем сами установить несколько пар KV:
И когда мы получаем их, мы видим, что значения передаются непосредственно в нашу команду как переменные среды:
1
2
3
|
$ ./envconsul -consul=nb-consul.local: 8500 -prefix smartjava -once env | tail -n 2 key2=The value of key 2 key1=The Value of Key 1 |
Это, однако, не все, что вы можете сделать с envconsul. Он также предоставляет простой способ реагировать на изменения в парах ключ-значение. Представьте, что у вас запущена служба, настроенная через свойство env. И если это свойство env изменяется, вам следует перезапустить службы. Это то, что EnvConsul может сделать для вас:
01
02
03
04
05
06
07
08
09
10
11
|
$ cat env.sh #!/bin/bash env tail -f /dev/ null $ ./envconsul -consul=nb-consul.local: 8500 -pristine -prefix=smartjava ./env.sh PWD=/Users/jos/dev/git/nextbuild-consul/extra/envconsul SHLVL= 1 key2=The value of key 2 key1=The Value of Key 1 _=/usr/bin/env |
В этот момент процесс продолжит работу, и envconsul будет ожидать обновления хранилища ключей Консула. Поэтому, когда мы что-то там обновляем, это результат:
Как вы можете видеть на этом изображении, всякий раз, когда мы меняем значение в хранилище KV, наш скрипт перезапускается с новой конфигурацией, передаваемой как переменные env.
Выводы
В этой статье мы показали, что использовать HAProxy очень просто. Вы можете включить его в свою архитектуру, используя те же концепции и идеи, которые мы видели в предыдущей статье. Объедините это с ConsulTemplate, и получить легко настраиваемую программную настройку балансировки нагрузки — это просто.
Еще одна интересная технология — EnvConsul, которая прекрасно интегрируется с распределенным хранилищем KV, предоставляемым Consul. Он даже предоставляет функциональные возможности для перезапуска вашего приложения при изменениях конфигурации, что является действительно мощной функцией.
И это завершает вторую статью в этой серии. В следующей части этой серии мы рассмотрим, как вы можете упростить регистрацию услуг в Консуле. Поэтому замените пользовательский скрипт, который мы показали в предыдущей статье, более продвинутым решением.
Ссылка: | Обнаружение услуг с Docker и Consul: часть 2 от нашего партнера JCG Йоса Дирксена из блога Smart Java . |