Назад | Перейти на главную страницу

Haproxy - динамический выбор бэкэнда из поддомена

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

 use_backend %[req.hdr(host),lower]

Тем не мение, Кто-нибудь знает, как я мог бы использовать поддомен заголовка хоста запроса для соответствия бэкэнду?

Например. что-то в этом роде:

backend one
backend two

use_backend %[<SUBDOMAIN OF HOSTHEADER>,lower]

который будет соответствовать так:

 one.example.com -> backend one
 two.example.com -> backend two

Добавление и удаление записей DNS позволяет вам на лету маршрутизировать поддомены на различные серверные ВМ, но вам все равно необходимо определить эти серверные ВМ, чтобы перезапустить службу. Таким образом, я не совсем уверен в полезности этой конфигурации.

В любом случае вот как вы это сделаете.

Мы знаем, что можем найти содержимое host заголовок, используя req.hdr (req.hdr(host)), но это дает нам полное доменное имя запроса, а не субдомен.

К счастью, есть regsub конвертер мы должен иметь возможность обращаться в req.hdr образец, чтобы вырезать базовый домен и TLD.

regsub (<regex>, <subst> [, <flags>])
Применяет к входной строке подстановку на основе регулярного выражения. Он делает то же самое
операция как хорошо известная утилита "sed" с "s / <regex> / <subst> /". По
по умолчанию он заменит во входной строке первое вхождение
наибольшая часть, соответствующая регулярному выражению <regex> с заменой
строка <подстрока>. Вместо этого можно заменить все вхождения, добавив
флаг «g» в третьем аргументе <flags>. Также возможно сделать
regex нечувствителен к регистру, добавив флаг "i" в <flags>. Поскольку <flags> - это
строка, она состоит из конкатенации всех желаемых флагов. Таким образом, если
желательны и «i», и «g», использование «gi» или «ig» будет иметь тот же эффект.
Важно отметить, что из-за текущих ограничений
парсер конфигурации, некоторые символы, такие как закрывающая скобка или запятая
нельзя использовать в аргументах.
Первое использование этого конвертера
для замены определенных символов или последовательности символов на другие.

Акцент в этой цитате мой и нацелен на то, чтобы показать, что в этом случае, когда вам понадобится регулярное выражение, ^(.*)(?:\..*){2}$, это не сработает из-за скобок.

Таким образом, вам нужно будет использовать поле конвертер.

поле (<индекс>, <разделители>)
Извлекает подстроку по заданному индексу с учетом заданных разделителей из
входная строка. Индексы начинаются с 1, а разделители представляют собой строку в формате
список символов.

field(1,'.')

Если собрать весь образец трубопровода вместе, use_backend строка выглядит так:

use_backend BE:subs-%[req.hdr(host),lower,field(1,'.')]

Теперь это открывает тот факт, что one.*.* перейдет к тому же бэкэнду и может привести к очень странным ситуациям.

Возможно, имеет смысл проверить базовый домен и TLD, чтобы убедиться, что они соответствуют вашим ожиданиям. Если у вас всего два (example.com и foo.com) из них вы бы использовали req.hdr_end(host) чтобы проверить их, сделав ACL похожим на:

 acl is_valid_base_domain  req.hdr_end(host) -i example.com foo.com

А если собрать все вместе, то весь конфиг будет выглядеть примерно так:

frontend FE:subs
  ...
  acl is_valid_base_domain  req.hdr_end(host) -i example.com foo.com
  use_backend BE:subs-%[req.hdr(host),lower,field(1,'.')] if is_valid_base_domain

  default_backend BE:subs:default

backend BE:subs-one
  #matches one.example.com, one.foo.com
  ...

backend BE:subs-two
  #matches two.example.com, two.foo.com
  ...

backend BE:subs-three
  #matches three.example.com, three.foo.com
  ...

backend BE:subs:default
  #matches *.example.com, *.foo.com 
  ...

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

Насколько мне известно, HAProxy не поддерживает регулярные выражения для извлечения определенной части поддомена из заголовка Host и последующего присвоения этого значения переменной, которая позже используется для формирования полного имени серверной части.

Однако один из способов решить вашу проблему - использовать отображение:

frontend frontend_main
...
use_backend %[req.hdr(host),lower,map(/etc/haproxy/subdomains.map,backend_main)]

Содержание /etc/haproxy/subdomains.map будет выглядеть так:

#domainname  backendname
one.example.com backend_one
two.example.com backend_two
etc.domain1.com backend_etc

Все запросы, которые не соответствуют ни одному из поддоменов в этом файле, будут отправлены в backend_main бэкэнд.