Haproxy - selecionando backend dinamicamente a partir do subdomínio

5

Descobri recentemente que você pode corresponder um back-end dinamicamente, com base no hostheader da solicitação, assim:

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

No entanto, alguém sabe de alguma forma que eu poderia usar o subdomínio do hostheader do pedido para corresponder ao back-end?

Por exemplo algo ao longo destas linhas:

backend one
backend two

use_backend %[<SUBDOMAIN OF HOSTHEADER>,lower]

que corresponderia assim:

 one.example.com -> backend one
 two.example.com -> backend two
    
por UpTheCreek 23.11.2015 / 16:28

2 respostas

7

Adicionar e remover entradas de DNS permite rotear subdomínios para vários backends instantaneamente, mas você ainda precisa definir esses back-ends para que ainda haja uma reinicialização do serviço. Como tal, não tenho certeza da utilidade dessa configuração.

De qualquer forma, veja como você faria isso.

Sabemos que podemos encontrar o conteúdo do cabeçalho host usando req .hdr ( req.hdr(host) ), mas isso nos dá o FQDN da solicitação, não o subdomínio.

Felizmente, há um conversor regsub que devemos consiga se inscrever na amostra req.hdr para cortar o domínio base e o DPN.

regsub(<regex>,<subst>[,<flags>])
Applies a regex-based substitution to the input string. It does the same
operation as the well-known "sed" utility with "s/<regex>/<subst>/". By
default it will replace in the input string the first occurrence of the
largest part matching the regular expression <regex> with the substitution
string <subst>. It is possible to replace all occurrences instead by adding
the flag "g" in the third argument <flags>. It is also possible to make the
regex case insensitive by adding the flag "i" in <flags>. Since <flags> is a
string, it is made up from the concatenation of all desired flags. Thus if
both "i" and "g" are desired, using "gi" or "ig" will have the same effect.
It is important to note that due to the current limitations of the
configuration parser, some characters such as closing parenthesis or comma
are not possible to use in the arguments.
The first use of this converter is
to replace certain characters or sequence of characters with other ones.

A ênfase nessa citação é minha e visa mostrar que, neste caso, onde a regex que você precisa é de ^(.*)(?:\..*){2}$ , não funcionará por causa dos parênteses.

Assim, você precisará usar o conversor campo .

field(<index>,<delimiters>)
Extracts the substring at the given index considering given delimiters from
an input string. Indexes start at 1 and delimiters are a string formatted
list of chars.

field(1,'.')

Se colocarmos a amostra inteira pipline juntos, a linha use_backend se parece com:

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

Agora, isso abre o fato de que one.*.* irá para o mesmo backend e pode levar a algumas situações muito estranhas.

Pode fazer algum sentido verificar o domínio base e o TLD para garantir que eles são o que você espera. Supondo que você tenha apenas dois ( example.com e foo.com ) deles, você usaria req.hdr_end(host) para verificá-los, fazendo com que a ACL pareça:

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

E se colocarmos tudo junto, toda a configuração será algo assim:

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 
  ...

Você pode ficar ainda mais sofisticado se quiser ter back-ends "dinâmicos" diferentes para cada subdomínio, por domínio de base; você só precisa usar as peças acima para resolver isso.

    
por 23.11.2015 / 21:29
5

Até onde eu sei, o HAProxy não tem suporte a regex para extrair parte específica do subdomínio do cabeçalho Host e então atribuir esse valor a uma variável, que é usada posteriormente para formar o nome completo do backend.

No entanto, uma forma de resolver o seu problema seria usar o mapeamento:

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

O conteúdo de /etc/haproxy/subdomains.map ficaria assim:

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

Todas as solicitações que não corresponderem a nenhum subdomínio desse arquivo serão enviadas para backend_main backend.

    
por 23.11.2015 / 16:56

Tags