Новий L4 Load Balancer з нативною реалізацією SRV record service dicovery і Docker API service Discovery

Як все починалося
У ході роботи з микросервисами ми неодноразово стикалися з проблемами сервіс діскавері при автоскелинге, схлопуванні зайвих нсд.
Були випробувані майже всі рішення існували або існують на даний момент, але як водиться — нічого не лягало ідеально на наші динамічні оточення (десятки зупинок/запусків однотипних контейнерів на годину). Найбільш близьке рішення було 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.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.