ADG Оставить заявку
Блог DevOps 4 мин чтения

Docker 1.12 routing mesh: балансировщик, которого не нужно ставить

Docker 1.12 Swarm mode принёс встроенный routing mesh - L4-балансировщик для сервисов без HAProxy и без лишней инфраструктуры. Разбираем как это работает на практике.

Контекст момента

Docker 1.12 Swarm mode ввёл routing mesh - встроенный балансировщик нагрузки для сервисов без внешнего LB

Когда мы в августе поднимали первый Swarm-кластер, routing mesh упомянули вскользь: «встроенный ingress, Nginx снаружи, всё работает». С тех пор прошло два месяца, мы сделали ещё несколько таких развёртываний, и пора разобрать этот механизм подробнее - потому что он реально меняет то, как мы думаем о балансировке для средних сервисов.

Что такое routing mesh

Это IPVS-based балансировщик, встроенный прямо в Docker 1.12. Механика простая: публикуешь порт у сервиса - этот порт открывается на всех нодах кластера одновременно. Запрос пришёл на любую ноду - Swarm сам перенаправит его на реплику, где бы она ни жила.

docker service create \
  --name web \
  --replicas 4 \
  -p 80:8080 \
  myregistry/web:2.1.0

После этого порт 80 отвечает на всех девяти нодах кластера. На какой из них реально живёт реплика - клиенту знать не нужно. DNS round robin по IP всех нод, или простейший keepalived - и у тебя балансировка с автофейловером без единой строки в конфиге HAProxy.

Почему это важно для наших задач

Классическая схема «Docker + HAProxy» выглядела так: сервисы на хостах, HAProxy с ручным или consul-template-driven конфигом смотрит куда перенаправлять трафик. При каждом деплое нужно обновить конфиг балансера, перечитать его, убедиться что upstream жив. При смерти реплики - то же самое в обратную сторону.

Это нормально работало, пока конфигурация была стабильной. Как только появлялось автомасштабирование или частые деплои - consul-template превращался в отдельный сервис с отдельными проблемами.

Routing mesh убирает этот слой полностью для типичного случая: stateless HTTP-сервис, несколько реплик, нужна балансировка по round robin. Swarm следит за репликами сам, IPVS-таблицы обновляет сам, клиент получает живой endpoint вне зависимости от того что происходит внутри.

Где мы это применяем

Сценарий, который повторялся несколько раз: управляемая инфраструктура для небольшого продакшна, 3-5 сервисов, автомасштабирование по нагрузке. Раньше схема выглядела примерно так:

  • L4-балансер - отдельная машина или пара машин с keepalived + HAProxy.
  • Consul - для service discovery, чтобы HAProxy знал об изменениях.
  • consul-template - чтобы перегенерировать конфиг HAProxy при изменениях.
  • Сами сервисы - на Docker, потом на Compose, теперь на Swarm.

Consul + consul-template + HAProxy - это три дополнительных компонента, каждый из которых надо обновлять, мониторить, отлаживать при проблемах. Для клиента с тремя разработчиками это заметная операционная нагрузка.

С routing mesh нижние три строки из списка исчезают. Остаётся простой Nginx или L4-балансер снаружи, который стреляет по IP нод - без знания о репликах, без consul, без шаблонов. docker service scale web=8 - и балансировка мгновенно учитывает новые реплики.

Ограничения, о которых надо знать

Routing mesh работает через ingress overlay network - это означает дополнительный сетевой хоп через VXLAN. На практике для HTTP-сервисов это незаметно, но если у вас latency-sensitive протокол или очень высокий RPS - стоит измерить накладные расходы в своей конкретной конфигурации.

По умолчанию балансировка - VIP-based round robin. Sticky sessions через routing mesh не работают из коробки. Если приложение держит состояние в памяти и требует закрепления клиента за репликой - это не ваш вариант без дополнительной обвязки. Но stateful-сервисы в принципе неудобно масштабировать горизонтально, это отдельная история.

Ещё одна тонкость: при docker service update с rolling update реплики временно выходят из ротации пока не пройдут healthcheck. Всё работает корректно, но важно чтобы healthcheck был прописан в Dockerfile - иначе Swarm считает контейнер готовым сразу после старта, что для приложений с долгой инициализацией неверно. Об этом мы писали в августе и с тех пор добавляем healthcheck в образы по умолчанию.

Куда это ведёт

Мы не убрали HAProxy полностью - для сложных случаев с SSL-терминацией, ACL по заголовкам и sticky sessions он по-прежнему стоит снаружи кластера. Но то, что раньше занимало у нас несколько часов настройки consul + consul-template + HAProxy для базового сценария, теперь решается одним флагом -p в docker service create.

Это честный размен: меньше инфраструктуры, меньше движущихся частей, меньше точек отказа - за счёт меньшей гибкости в конфигурации балансировки. Для большинства наших клиентов это правильный размен.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.