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.
Это честный размен: меньше инфраструктуры, меньше движущихся частей, меньше точек отказа - за счёт меньшей гибкости в конфигурации балансировки. Для большинства наших клиентов это правильный размен.
- Docker Swarm mode в продакшне: три менеджера, шесть воркеров, rolling update · 15 августа 2016
- Kubernetes 1.4 и kubeadm: ставим кластер на bare-metal CentOS 7 за 30 минут · 19 сентября 2016