Nginx健康检查式负载均衡配置问题:如何从upstream块获取活跃后端的DNS名称以设置proxy_ssl_name和Host头
看起来你遇到的核心问题是Nginx开源版没有直接提供获取上游服务器域名的变量,导致你用$upstream_addr做映射时不稳定——毕竟$upstream_addr返回的是解析后的IP:端口,甚至偶尔会带上额外信息,没法稳定匹配到对应的域名。另外你的resolver配置位置也有点问题,先帮你一步步梳理解决方案:
首先,先修正你的upstream配置,确保Nginx能动态解析后端域名(避免启动时只解析一次IP,后续IP变化时无法更新):
upstream backend { # 把resolver移到upstream里,设置有效期30秒,让Nginx定期刷新DNS resolver dns-default.openshift-dns valid=30s; # 给每个server加上resolve参数,让Nginx动态解析这个域名 server primary.com resolve max_fails=2 fail_timeout=2s; server secondary.com resolve backup; }
接下来解决动态获取活跃后端DNS的问题,因为开源版Nginx没有直接的上游域名变量,我们可以优化map的匹配规则,兼容$upstream_addr可能带端口的情况:
# 用正则匹配IP部分,不管后面的端口号 map $upstream_addr $active_dns { ~^121\.12\.11\.12:.* primary.com; ~^123\.23\.32\.12:.* secondary.com; # 万一匹配不到,默认用primary作为 fallback default primary.com; }
然后在location块里使用这个变量:
location / { proxy_pass https://backend; proxy_pass_request_headers on; proxy_ssl_server_name on; # 用我们映射出来的活跃域名设置SSL名称和Host头 proxy_ssl_name $active_dns; proxy_set_header Host $active_dns; }
不过这个方法有个局限性:如果后端域名的IP发生变化,你需要手动更新map里的IP规则。如果你的后端IP经常变动,推荐换一种思路——不用upstream块,而是用error_page实现故障转移,这样能直接指定每个后端的域名,不用依赖IP映射:
location / { resolver dns-default.openshift-dns valid=30s; # 直接代理到主后端 proxy_pass https://primary.com; proxy_pass_request_headers on; proxy_ssl_server_name on; proxy_ssl_name primary.com; proxy_set_header Host primary.com; # 当主后端返回502/503/504时,跳转到备用后端 error_page 502 503 504 @secondary; } # 备用后端的location location @secondary { resolver dns-default.openshift-dns valid=30s; proxy_pass https://secondary.com; proxy_pass_request_headers on; proxy_ssl_server_name on; proxy_ssl_name secondary.com; proxy_set_header Host secondary.com; }
这个方法的好处是完全不需要依赖IP映射,直接使用后端域名,SSL握手和Host头都不会有问题。缺点是没法像upstream那样设置连续失败次数(max_fails),只能基于单个请求的错误码跳转。如果需要更精细的健康检查规则,你可以考虑安装第三方模块ngx_http_upstream_check_module,它支持主动健康检查,并且能提供更多上游服务器的状态变量。
最后提醒一下:测试的时候可以先手动停掉主后端服务,看看请求是否能自动切到备用,同时检查SSL证书是否能正常验证(可以用curl -v看握手日志)。
备注:内容来源于stack exchange,提问作者Ram




