Pull to refresh

Новый L4 Load Balancer с нативной реализацией SRV record service discovery и Docker API service Discovery

Reading time 4 min
Views 8.9K

Как все начиналось


В ходе работы с микросервисами мы неоднократно сталкивались с проблемами сервис дискавери при автоскелинге, схлопывании лишних нод.


Были перепробованы почти все решения существовавшие или существующие на данный момент, но как водится — ничего не ложилось идеально на наши динамичные окружения (десятки остановок/запусков однотипных контейнеров в час). Наиболее близкое решение было NGINX+Consul+Consul templates, но оно было некрасивым, требовало перезапуска, не давало возможности использовать внешние хелсчеки иначе как через Consul.


В общем, как всегда бывает — было принято решение написать свое решение. В процессе обсуждения всплыли десятки вещей, которые хорошо было бы реализовать, из них были выбраны самые критичные для нас и интересные для общественности.


Заложенный функционал на первую итерацию


Типы балансировки:


Iphash
Leastconn
Roundrobin
Weight


Дискавери (определение пула бекендов для каждого фронтенда):


Static — просто список серверов в конфиге.
Docker — запрос в докер Docker / Swarm API фильтрованные по label и внутренним портам контейнера.
Exec — инициирование запуска внешнего скрипта, чтение из stdout и его разбор по регулярке (пока прописана жестко).
JSON — запрашивает через http-запрос URL и разбирает его по паттернам (поддерживает многоуровневый JSON).
Plaintext — запрашивает через http-запрос URL и разбирает его по заданному в конфиге регулярному выражению.
SRV — запрашивает у заданного DNS SRV записи по имени сервиса.


Хелсчеки


Так как изначально было совершенно понятно, что мы просто не потянем имплементировать хелсчеки в объеме того же haproxy, было принято решение отделаться малой кровью и сделать всего 2 типа хелсчеков.


Ping — простой TCP ping;
Exec — запуск произвольного бинарника с передачей ему параметров и чтение из stdout вывода.


Примеры использования


SRV Discovery


У нас есть произвольные сервисы, регистрирующие себя, к примеру, в Consul. Будем использовать Consul dns для определения пула серверов.


image


В этом примере мы определили тип балансировки как "srv", так же определен DNS-сервер и его порт, на который будут идти запросы на сервис дискавери. Определена частота обновления списка серверов, а так же немаловажная переменная — политика для случая, когда DNS-сервер не ответил. Для максимальной консистентности окружения нужно ставить failpolicy="setempty". В таком случае при отсутствии ответа от DNS весь пул бекенд серверов будет обнулен, а входящие соединения будут сбрасываться. В противном случае нужно использовать failpolicy = "keeplast", тогда балансировщик будет использовать последние данные, пришедшие до сбоя соединения с DNS.


toml
[servers.sample2]
bind = "localhost:3001"
protocol = "tcp"
balance = "weight"

  [servers.sample2.discovery]
  failpolicy = "keeplast"
  kind = "srv"
  srv_lookup_server = "66.66.66.66:8600" # dns server and port
  srv_lookup_pattern = "api.service.ireland.consul." # SRV service pattern 

  [servers.sample2.healthcheck]
  fails = 1                      
  passes = 1
  interval = "2s"                
  kind = "ping"
  timeout = "500ms" 

Docker / Swarm Балансировка.


По сути различий в API и способе настройки для Docker/Docker Swarm нет. Мы можем одинаково работать и с Docker хостом, и с Docker Swarm кластером. Рассмотрим работу с ними в одном примере.


image


Сейчас мы будем балансировать определенными сервисами, используя Docker Swarm, как более общий пример. Все нижеописанное работает и для отдельного Docker хоста. В данном примере мы определяем тип дискавери как "docker", определяем базовый docker url, лейблы и внутренний порт докер контейнера (со стороны сети самого контейнера) по которым балансировщик будет делать выборку, из которых формируется пул бекенд серверов.


Для данного примера мы будем использовать более "продвинутый" тип хелсчеков, а именно exec-хелсчеки. Помимо параметров частоты запуска чеков есть еще время отработки скрипта. Время между запусками должно быть больше времени отработки скрипта, чтобы не было "набегов". Команда запуска данного хелсчека формируется как /path/to/script [ip] [port]. После отработки скрипта, он должен выводить в stdout строку, которая сравнивается с положительным и отрицательным предполагаемым результатом.


[servers.sample3]
bind = "localhost:3002"
protocol = "tcp"
balance = "weight"

  [servers.sample3.discovery]
    interval = "10s"
    timeout = "2s"
    kind = "docker"
    docker_endpoint = "http://localhost:2377"  # Docker / Swarm API    
    docker_container_label = "api=true"  # label to filter containers
    docker_container_private_port = 80   # gobetween will take public container port for this private port

[servers.sample3.healthcheck] 
kind = "exec"
interval = "2s"  
exec_command = "/etc/gobetween/checks/exec_healthcheck.sh"
exec_expected_positive_output = "1"           
exec_expected_negative_output = "0"           
exec_timeout_duration = "1s"             

В последующих статьях я планирую привести несколько примеров более сложного использования других видов дискавери. Также будет описана специфика конфигурирования и установки под Windows.


Tags:
Hubs:
+12
Comments 19
Comments Comments 19

Articles