Haproxy - 从子域动态选择后端

UpT*_*eek 6 haproxy

我最近发现您可以根据请求主机头动态匹配后端,如下所示:

 use_backend %[req.hdr(host),lower]
Run Code Online (Sandbox Code Playgroud)

但是,有没有人知道我可以使用请求主机头的子域来匹配后端的任何方式?

例如,沿着这些路线的东西:

backend one
backend two

use_backend %[<SUBDOMAIN OF HOSTHEADER>,lower]
Run Code Online (Sandbox Code Playgroud)

这会像这样匹配:

 one.example.com -> backend one
 two.example.com -> backend two
Run Code Online (Sandbox Code Playgroud)

Gre*_*egL 7

添加和删​​除 DNS 条目允许您动态地将子域路由到各种后端,购买您仍然需要定义这些后端,以便仍然重新启动服务。因此,我不完全确定此配置的用处。

无论如何,这就是你的方法。

我们知道我们可以host通过使用req.hdr ( req.hdr(host))找到标头的内容,但这为我们提供了请求的 FQDN,而不是子域。

值得庆幸的是,我们应该能够将regsub转换器应用于示例以剪掉基本域和 TLD。req.hdr

regsub(<regex>,<subst>[,<flags>])
将基于正则表达式的替换应用于输入字符串。它
使用“s/<regex>/<​​subst>/”执行与众所周知的“sed”实用程序相同的操作。通过
默认,将在输入字符串中替换的第一次出现
最大的部分正则表达式的<正则表达式>用替换
字符串<SUBST>。可以通过
在第三个参数 <flags> 中添加标志“g”来替换所有出现的事件。还可以
通过在 <flags> 中添加标志“i”来使正则表达式不区分大小写。由于 <flags> 是一个
字符串,它由所有所需标志的串联组成。

需要注意的是,由于
配置解析器的当前限制,某些字符(例如右括号或逗号)
无法在参数中使用。
此转换器的第一个用途是
将某些字符或字符序列替换为其他字符。

该引文中的重点是我的,旨在表明在这种情况下,您需要的正则表达式是^(.*)(?:\..*){2}$,由于括号,它不起作用。

因此,您需要使用转换器。

field(<index>,<delimiters>) 根据输入字符串中的
给定分隔符提取给定索引处的子
字符串。索引从 1 开始,分隔符是字符串格式
的字符列表。

field(1,'.')
Run Code Online (Sandbox Code Playgroud)

如果我们将整个示例管道放在一起,则该use_backend行如下所示:

use_backend BE:subs-%[req.hdr(host),lower,field(1,'.')]
Run Code Online (Sandbox Code Playgroud)

现在,这开启了one.*.*将进入同一个后端的事实,并可能导致一些非常奇怪的情况。

检查基本域和 TLD 以确保它们符合您的期望可能是有意义的。假设您只有两个 (example.comfoo.com),您将req.hdr_end(host)用来检查它们,使 ACL 看起来像:

 acl is_valid_base_domain  req.hdr_end(host) -i example.com foo.com
Run Code Online (Sandbox Code Playgroud)

如果我们把它们放在一起,整个配置看起来像这样:

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 
  ...
Run Code Online (Sandbox Code Playgroud)

如果您愿意,您可以通过为每个子域、每个基本域设置不同的“动态”后端来变得更漂亮;你只需要使用上面的部分来解决这个问题。

  • @UpTheCreek,修复了反映您发现的内容的答案。如果您喜欢,请随时给我一张支票。 (2认同)

Tub*_*ess 5

据我所知,HAProxy 没有正则表达式支持从 Host 标头中提取子域的特定部分,然后将该值分配给一个变量,该变量稍后用于形成完整的后端名称。

但是,您解决问题的一种方法是使用映射:

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

的内容/etc/haproxy/subdomains.map如下所示:

#domainname  backendname
one.example.com backend_one
two.example.com backend_two
etc.domain1.com backend_etc
Run Code Online (Sandbox Code Playgroud)

与该文件中的任何子域都不匹配的所有请求都将转到backend_main后端。