Haproxy - 从子域动态选择后端

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

答案1

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

无论如何,您可以这样做。

我们知道我们可以host通过使用请求文件req.hdr(host)),但是这给了我们请求的 FQDN,而不是子域。

值得庆幸的是,有一个注册子程序转换器我们应该能够应用于req.hdr样本以剪掉基础域和 TLD。

regsub(<regex>,<subst>[,<flags>])
对输入字符串应用基于正则表达式的替换。它
与著名的“sed”实用程序“s/<regex>/<​​subst>/”执行相同的操作。
默认情况下,它将在输入字符串中用
替换字符串
<subst> 替换与正则表达式 <regex> 匹配的最大部分的第一次出现。通过在第三个参数 <flags> 中添加标志“g”,可以替换所有出现的情况
。还可以
通过在 <flags> 中添加标志“i”使正则表达式不区分大小写。由于 <flags> 是一个
字符串,它由所有所需标志的连接组成。因此,如果
同时需要“i”和“g”,则使用“gi”或“ig”将具有相同的效果。
值得注意的是,由于
配置解析器当前的限制,某些字符(例如右括号或逗号)
无法在参数中使用。
该转换器的第一个用途是
用其他字符或字符序列替换某些字符或字符序列。

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

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

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

field(1,'.')

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

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

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

检查基本域和 TLD 以确保它们符合您的预期可能会有所帮助。假设您只有两个(example.comfoo.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 
  ...

如果您愿意,可以为每个子域、每个基本域设置不同的“动态”后端,从而获得更加精美的效果;您只需要使用上面的部分即可解决这个问题。

答案2

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

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

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后端。

相关内容