如何在Nginx Ingress实现TCP端口基于域名的主机路由?
解决方案
报错根因
ingress-nginx官方TCP配置规范要求tcp配置块的key必须为整数端口号,你把key写为域名:端口格式的字符串时,Chart渲染Kubernetes Service资源会直接把该字符串作为Service.spec.ports.port字段的值,触发K8s API的类型校验失败(该字段仅接受整数)。
另外注意:TCP四层要实现基于域名的路由,必须要求客户端连接使用TLS加密,携带SNI扩展,非TLS的TCP报文没有域名信息,无法实现主机路由。
正确配置方案
通过ingress-nginx的tcp-snippets配置注入自定义路由逻辑,不需要修改原有tcp块的端口规则:
步骤1:修改Chart values配置
chart: nginx-git/ingress-nginx version: 3.32.0 values: - tcp: # 填写任意默认后端,实际路由会被lua逻辑覆盖 5672: "cust1namespace/rabbitmq:5672" - controller: config: tcp-snippets: | server { listen *:5672 ssl; # 开启TLS预读取,拿到SNI域名 ssl_preread on; preread_by_lua_block { -- 自定义域名与上游RabbitMQ服务的映射规则 local route_map = { ["cust1domainname"] = "tcp-cust1namespace-services-rabbitmq-5672", ["cust2domainname"] = "tcp-cust2namespace-services-rabbitmq-5672" } local client_sni = ngx.ssl.server_name() if client_sni and route_map[client_sni] then ngx.var.proxy_upstream_name = route_map[client_sni] else -- 未匹配到域名直接断开连接,也可配置走默认后端 ngx.exit(ngx.ERROR) end } proxy_pass upstream_balancer; # 替换为你的SSL证书实际存储路径 ssl_certificate /etc/nginx/ssl/tls.crt; ssl_certificate_key /etc/nginx/ssl/tls.key; }
步骤2:校验上游命名规则
配置前先确认你使用的ingress-nginx版本的上游命名规则是否与示例一致,规则格式通常为tcp-{namespace}-{service-name}-{port},如果不一致直接调整route_map中的值即可。
如果你的RabbitMQ不使用TLS加密,无法在TCP层获取域名,只能改用以下两种方案:
- 给不同租户的RabbitMQ分配不同的外网端口,通过端口区分路由
- 改用应用层路由,客户端连接时携带RabbitMQ虚拟主机参数,在RabbitMQ侧做租户区分
内容的提问来源于stack exchange,提问作者mayank arora
相关产品推荐
相关产品推荐

