OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

HAProxy discovery: DNS SRV и server-template на практике

Разбираем динамическое обнаружение бэкендов в HAProxy через DNS: SRV‑записи, секцию resolvers и директиву server-template. Настроим автопоиск инстансов без перезагрузок, разберём healthcheck, TTL, веса, отладку и типовые проблемы.
HAProxy discovery: DNS SRV и server-template на практике

Автодискавери через DNS в HAProxy закрывает типичные задачи DevOps: автоматически подцеплять появляющиеся/исчезающие инстансы приложения, выполнять healthcheck и балансировать трафик без перезапусков прокси. Ключевые кирпичики — секция resolvers, директива server-template и поддержка DNS SRV. В этой статье соберём боевую конфигурацию, разберёмся с TTL, весами, отладкой и практическими нюансами. Запускать HAProxy удобно на изолированном инстансе — подойдёт управляемый VDS.

Когда пригодится DNS-based service discovery

Классическая статическая конфигурация HAProxy неудобна в динамических средах: контейнеры перезапускаются, инстансы масштабируются, адреса меняются. С DNS-discovery HAProxy подписывается на DNS-имя или SRV-запись и периодически актуализирует пул серверов, создавая/удаляя их на лету. Перезагрузка не требуется — достаточно грамотной секции resolvers и server-template в backend.

Типичные источники записей:

  • Consul и CoreDNS отдают SRV с портами и весами.
  • Kubernetes headless Service отдает множество A/AAAA записей для pod-ов (SRV — для named ports).
  • Собственная зона DNS с A/AAAA/SRV для микросервисов.

Главное преимущество — без перезагрузок. HAProxy сам добавляет/удаляет серверы, обновляет порты и веса (при SRV) и не рвёт активные соединения.

Быстрый старт: resolvers и A/AAAA discovery

Начнём с простейшего: динамическое обнаружение множества адресов по одному имени. Секция resolvers описывает, к каким DNS-серверам обращаться и как кэшировать ответы. Затем в backend используем server-template для автосоздания серверов.

global
  log 127.0.0.1 local0
  stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
  daemon

resolvers dns_internal
  nameserver dns1 10.0.0.53:53
  accepted_payload_size 8192
  resolve_retries 3
  timeout resolve 1s
  timeout retry 1s
  hold valid 10s
  hold nx 30s
  hold refused 30s
  hold other 30s
  hold timeout 5s
  hold obsolete 30s

frontend fe_http
  bind :80
  default_backend be_app

backend be_app
  balance roundrobin
  option httpchk GET /health
  http-check expect status 200
  # Автоматически создать до 20 серверов из A/AAAA записей
  server-template app 20 app.internal.local:8080 resolvers dns_internal resolve-prefer ipv4 check inter 2s rise 2 fall 3 init-addr last,libc

Что происходит:

  • server-template app 20 app.internal.local:8080 — создаёт до 20 серверов, основываясь на количестве адресов в ответе A/AAAA по имени app.internal.local. Порт фиксирован (8080).
  • init-addr last,libc — при старте попытается взять последний известный адрес, затем — одноразово спросит системный резолвер, чтобы старт был быстрым даже при временных проблемах с DNS.
  • hold obsolete 30s — если резолвер недоступен, HAProxy ещё 30 секунд удержит последнюю валидную выборку адресов, что снижает флаппинг.
  • accepted_payload_size 8192 — полезно, когда список записей велик (EDNS0).

DNS SRV: порты и веса из DNS

SRV-записи удобны, когда у разных инстансов разные порты или нужно передавать веса из DNS. Формат имени SRV: _service._proto.name, например: _http._tcp.app.internal.local. Ответ SRV содержит целевой хост, порт, вес и приоритет.

backend be_app_srv
  balance roundrobin
  option httpchk GET /health
  http-check expect status 200
  # Автодискавери через SRV: порт и веса возьмутся из DNS
  server-template app 30 _http._tcp.app.internal.local resolvers dns_internal resolve-prefer ipv4 check inter 2s rise 2 fall 3 init-addr none resolve-opts allow-dup-ip

Ключевые моменты:

  • SRV требует A/AAAA для целевых имён. Резолвер должен уметь идти по цепочке SRV → A/AAAA.
  • allow-dup-ip допускает одинаковые IP на разных серверах (полезно, если несколько инстансов слушают разные порты одного IP).
  • Вес из SRV обычно маппится в server weight. Для управляемого сплита трафика задавайте веса в DNS. Если веса из DNS вам не нужны, используйте resolve-opts ignore-weight.

Про приоритеты SRV

Приоритет в SRV нужен для фейловера между группами инстансов. На практике многие предпочитают управлять приоритетом через разные backends или через внешний оркестратор, а SRV использовать прежде всего для портов и весов. Если вы опираетесь на приоритет из SRV, обязательно протестируйте поведение с отказами низкоприоритетной и высокоприоритетной групп, чтобы убедиться, что оно соответствует вашим ожиданиям.

Фрагмент конфигурации HAProxy с server-template и SRV

Healthcheck: TCP, HTTP и TLS к апстриму

В большинстве случаев достаточно option httpchk с проверкой кода ответа. Для SRV порт подтягивается из DNS, и чек автоматом попадает на правильный порт.

# TCP-чек (минималистичный)
backend be_tcp
  balance source
  server-template t 20 _tcp._tcp.service.local resolvers dns_internal check inter 2s fall 3 rise 2

# HTTP-чек по пути /health
backend be_http
  option httpchk GET /health
  http-check expect status 200
  server-template h 20 _http._tcp.app.local resolvers dns_internal check inter 2s

# TLS к апстриму с SNI и без проверки сертификата (внутренняя сеть)
backend be_https
  option httpchk GET /ready
  http-check expect status 200
  server-template s 20 _https._tcp.app.local resolvers dns_internal check inter 2s ssl verify none sni str(app.local)

Рекомендации:

  • Чеки делайте дешевыми для приложения: отдавайте 200 быстро и без тяжёлых зависимостей (БД, внешние API), если вам нужно проверять именно приём трафика, а не глубокое здоровье.
  • Интервалы inter, пороги rise/fall подбирайте так, чтобы снижение/поднятие не было слишком резким. Часто подходят inter 2s, rise 2, fall 3.

Тюнинг resolvers: стабильность и производительность

Секция resolvers критична для стабильности автодискавери. Вот набор опций, которые на практике закрывают большинство кейсов:

  • accepted_payload_size 4096..8192 — для длинных ответов (много SRV/A/AAAA).
  • timeout resolve и timeout retry — короткие таймауты уменьшают залипание на резолве.
  • resolve_retries — 2–3 обычно достаточно.
  • hold * — задают, как долго удерживать адреса при разных ошибках резолва, чтобы снизить флаппинг.

Пример «стрессоустойчивого» профиля:

resolvers dns_cluster
  nameserver ns1 10.10.0.10:53
  nameserver ns2 10.10.0.11:53
  accepted_payload_size 8192
  resolve_retries 3
  timeout resolve 1s
  timeout retry 1s
  hold valid 10s
  hold nx 30s
  hold refused 30s
  hold other 30s
  hold timeout 5s
  hold obsolete 45s

Практика показывает, что hold obsolete порядка 30–60 секунд часто спасает от лавинообразных отключений при перезагрузке/отказе резолверов, сохраняя последнюю валидную выборку на короткое время.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Лучшие практики для A/AAAA vs SRV

  • Если все инстансы на одном порту — используйте A/AAAA. Конфигурация проще.
  • Если порты и веса различаются — SRV удобнее и выразительнее.
  • Для Kubernetes headless Service чаще всего достаточно A/AAAA. SRV пригодится для named ports и когда важно хранить веса в DNS.
  • Избегайте слишком коротких TTL в источнике DNS: частые обновления увеличивают нагрузку и шум.

Миграция со статических серверов на server-template

Пошаговый план, который минимизирует риски:

  1. Заведите отдельный backend с server-template, подключите такой же healthcheck.
  2. Убедитесь, что все целевые имена резолвятся как ожидается (проверяйте через dig, лог HAProxy и Runtime API).
  3. Временно направьте долю трафика через новый backend (через ACL-ы, карту, сплит) и посмотрите метрики/логи.
  4. Переключите основной трафик после проверки и оставьте старый backend в резерве на короткое время.

Набор «повседневной» отладки

Команды помогут быстро понять, что происходит с резолвом и пулом:

# Посмотреть SRV и A/AAAA ручками
# На узле с HAProxy (или рядом)
dig +short _http._tcp.app.internal.local SRV
 dig +short app-01.node.internal A

# Runtime API: состояние резолверов и серверов
# Путь сокета определён в global: stats socket /run/haproxy/admin.sock
socat - UNIX-CONNECT:/run/haproxy/admin.sock <<< "show resolvers"
socat - UNIX-CONNECT:/run/haproxy/admin.sock <<< "show servers state"

# Временно вывести сервер из ротации (напр., для отладки)
socat - UNIX-CONNECT:/run/haproxy/admin.sock <<< "set server be_app/app1 state maint"

# Вернуть в работу
socat - UNIX-CONNECT:/run/haproxy/admin.sock <<< "set server be_app/app1 state ready"

Включайте информативный лог, чтобы видеть события резолва и изменения пула. В global и defaults задайте приёмник логов и формат, а затем анализируйте добавление/удаление серверов и результаты healthcheck.

Отладка discovery: dig и Runtime API HAProxy

Частые проблемы и решения

  • SRV есть, но бэкенд пуст: проверьте, что у целевых имён из SRV действительно существуют A/AAAA.
  • Флаппинг при проблемах с DNS: увеличьте hold obsolete и проверьте доступность резервного резолвера. Убедитесь, что сеть не режет фрагментированные UDP-пакеты.
  • Большой список инстансов: поднимите accepted_payload_size до 8192 и при необходимости разрешите TCP-запросы к резолверу.
  • Дубликаты IP при SRV: добавьте resolve-opts allow-dup-ip, если разные инстансы слушают разные порты одного адреса.
  • HTTP 503 при переключениях: смягчите rise/fall, уменьшите интервал чека и убедитесь, что /health доступен сразу после старта процесса.
  • Нужен управляемый трафик-сплит: задавайте веса в SRV или используйте отдельные записи/имена и разные server-template в одном backend.

Пример «собранной» конфигурации

global
  log 127.0.0.1 local0
  stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
  daemon

defaults
  mode http
  log global
  option httplog
  timeout connect 3s
  timeout client  30s
  timeout server  30s

resolvers dns_app
  nameserver ns1 10.0.0.10:53
  nameserver ns2 10.0.0.11:53
  accepted_payload_size 8192
  resolve_retries 3
  timeout resolve 1s
  timeout retry 1s
  hold valid 10s
  hold nx 30s
  hold refused 30s
  hold other 30s
  hold timeout 5s
  hold obsolete 45s

frontend fe_main
  bind :80
  bind :443 ssl crt /etc/haproxy/certs
  http-request set-header X-Request-Id %[unique-id]
  default_backend be_srv

backend be_srv
  balance roundrobin
  option httpchk GET /health
  http-check expect status 200
  http-reuse always
  # SRV discovery: порт и веса подтягиваются из DNS
  server-template app 40 _http._tcp.app.svc.local resolvers dns_app resolve-prefer ipv4 check inter 2s rise 2 fall 3 init-addr none resolve-opts allow-dup-ip

backend be_admin
  balance roundrobin
  # A/AAAA discovery (один порт у всех инстансов)
  server-template adm 10 admin.internal.local:8080 resolvers dns_app resolve-prefer ipv4 check inter 2s rise 2 fall 3 init-addr last,libc

Для HTTPS на фронтенде нужен валидный сертификат — удобнее сразу оформить и выпускать через SSL-сертификаты. Если доменов много и вы используете wildcard, посмотрите про автоматизацию DNS‑01 и выпуск wildcard‑сертов: автоматизация выпуска wildcard по DNS‑01.

Производительность и безопасная эксплуатация

  • DNS-запросы асинхронны и экономны, но не злоупотребляйте малыми интервалами чека и крошечными TTL.
  • Не указывайте публичные DNS для внутренней резолюции. Держите резолверы рядом с HAProxy.
  • Следите за логами резолвера и HAProxy: timeouts, truncated, refused, nx.
  • Поднимайте лимит дескрипторов и мониторьте количество серверов в пуле, ошибки чека и отказ резолва.
FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Когда SRV лучше не использовать

  • Нужна жёсткая фиксация портов и простота — A/AAAA читаются проще.
  • Резолвер не гарантирует своевременную цепочку SRV → A/AAAA или зоны разнородные.
  • Сложная логика приоритетов — прозрачнее держать отдельные backends и переключать их политиками.

Чек-лист внедрения

  • Версия HAProxy 2.x (для комфортной работы с server-template, SRV, Runtime API).
  • Здоровый резолвер-кластер, успешные тесты dig на SRV и A/AAAA.
  • Корректные hold и accepted_payload_size.
  • Понятный и быстрый /health с валидной семантикой.
  • Мониторинг: ошибки чека, изменения пула, показатели резолва, latency.

Итоги

Пара resolvers + server-template превращает HAProxy в полноценный участник сервисной сетки: он сам обновляет список апстримов, подхватывает порты и веса из SRV, грамотно переживает кратковременные сбои DNS и не требует перезагрузок. Критично аккуратно настроить резолверы, подобрать «держатели» на ошибки и выстроить лёгкие healthchecks — тогда автодискавери будет работать спокойно и предсказуемо.

Поделиться статьей

Вам будет интересно

systemd-run: ограничиваем CPU и RAM для одноразовых задач и интерактивных команд OpenAI Статья написана AI (GPT 5)

systemd-run: ограничиваем CPU и RAM для одноразовых задач и интерактивных команд

Как быстро ограничить CPU и память для разовых команд без unit-файлов: используем systemd-run, transient units в режимах --service ...
OpenSearch на VDS: практический гид по памяти JVM heap, ISM-политикам и снапшотам OpenAI Статья написана AI (GPT 5)

OpenSearch на VDS: практический гид по памяти JVM heap, ISM-политикам и снапшотам

Поднимем OpenSearch на VDS: настроим JVM heap без сюрпризов с GC, спроектируем ISM с rollover и удалением, организуем регулярные s ...
ACME DNS‑01 через RFC2136: свой DNS‑API без облаков OpenAI Статья написана AI (GPT 5)

ACME DNS‑01 через RFC2136: свой DNS‑API без облаков

DNS‑01 решает выпуск wildcard и закрытых сервисов, но нужен API к авторитетному DNS. Покажу, как поднять свой «API» на RFC2136: BI ...