Kubernetes HAProxy Ingress未显式设置Host头无法正常工作
这个问题的核心是Host头的匹配差异,我们来一步步拆解原因和解决办法:
为什么会出现404?
当你执行curl -L echo.example.com:30884时,curl自动发送的Host请求头是echo.example.com:30884(包含了端口号);而你的Ingress规则web-ingress中定义的Host是echo.example.com(不带端口)。
HAProxy Ingress Controller对Host头是精确匹配的,带端口的Host和不带端口的Host会被视为完全不同的主机,所以它找不到对应的后端规则,就返回了默认的default backend - 404。
而你用curl -L -H 'Host: echo.example.com' localhost:30884时,显式指定了正确的Host头,自然能匹配到Ingress规则,得到正常响应。
解决办法
这里提供几种实用的解决方案,你可以根据实际场景选择:
1. 显式指定Host头访问(临时测试用)
这是最直接的临时方案,和你之前的测试命令类似,只是把localhost换成域名:
curl -L -H 'Host: echo.example.com' echo.example.com:30884
这样发送的Host头不带端口,就能匹配Ingress规则。
2. 将Ingress Controller的NodePort映射到标准端口(推荐)
标准的HTTP请求默认使用80端口,HTTPS使用443端口,如果你把Ingress Controller的NodePort设置为80(需要集群节点允许特权端口),访问时就不需要加端口号,curl会自动发送不带端口的Host头。
修改Ingress Controller的Service:
kubectl edit service haproxy-ingress
找到ports字段下的nodePort,把当前的30884改成80,保存退出。等待Service更新后,直接访问:
curl -L echo.example.com
就能正常得到Echo Server的响应了。
3. 通过Ingress Annotation配置正则匹配Host(兼容带端口的场景)
如果你必须保留非标准端口,也可以通过HAProxy Ingress的自定义Annotation,让规则匹配带任意端口的Host头。
编辑你的web-ingress:
kubectl edit ingress web-ingress
添加以下Annotation:
annotations: haproxy.org/host-regex: "^echo\\.example\\.com(:.*)?$"
这个正则表达式会匹配echo.example.com以及后面带任意端口的Host(比如echo.example.com:30884)。保存后等待HAProxy重新加载配置,再执行curl -L echo.example.com:30884就能正常访问了。
验证
修改完成后,重新执行有问题的curl命令:
curl -L echo.example.com:30884
如果返回了Echo Server的预期响应,说明配置生效了。
内容的提问来源于stack exchange,提问作者user3340372

