AKS高级网络环境下无法获取真实客户端IP的解决方案咨询
我之前在AKS的混合网络场景下碰到过几乎一模一样的问题,不用着急切换到标准Ingress,针对Azure CNI(高级网络)的集群,有几个精准的调整方案,能保留你现有自定义Nginx的配置:
核心原因分析
在Azure CNI模式下,AKS的LoadBalancer Service默认会启用SNAT(源网络地址转换),把客户端真实IP替换成节点IP再转发到Nginx Pod;而你已经设置的externalTrafficPolicy: Local在Azure CNI环境中需要配合额外注解才能完全生效,阻止SNAT行为。
解决方案步骤
1. 调整LoadBalancer Service配置,禁用SNAT
给Azure CNI集群的Service添加专属注解,让Azure Load Balancer保留客户端真实IP作为数据包源IP:
apiVersion: v1 kind: Service metadata: name: <our name> namespace: <our namespace> annotations: # 关键注解:禁用Azure LB的SNAT,保留客户端真实IP service.beta.kubernetes.io/azure-load-balancer-no-snat: "true" spec: ports: - port: 443 targetPort: 443 selector: app: <our app> loadBalancerIP: <our ip> type: LoadBalancer externalTrafficPolicy: Local
这个注解只需要在Azure CNI环境的Service中添加,kubenet环境的Service保持原有配置即可。
2. 更新Nginx的真实IP模块配置
现在数据包的源IP已经是客户端真实IP了,需要调整Nginx的real_ip配置,适配两种环境:
# 针对kubenet环境:从X-Original-Forwarded-For头获取真实IP,信任kubenet节点子网 real_ip_header X-Original-Forwarded-For; set_real_ip_from <kubenet节点子网>; # 比如你的原配置10.0.0.0/8 # 针对Azure CNI环境:直接使用数据包的源IP作为真实IP,信任Azure CNI节点子网 real_ip_header Remote_Addr; set_real_ip_from <azure-cni节点子网>; # 比如你的AKS节点所在的子网,如10.240.0.0/16
如果你的两个环境用的是不同的Nginx配置文件,直接分别配置即可;如果是共用配置,可以用Nginx的if指令结合环境变量来区分(比如通过ConfigMap注入环境标识)。
3. 验证健康检查(可选但重要)
添加no-snat注解后,确保Azure LB的健康检查能正常访问到Nginx Pod:
- 确认Nginx配置了健康检查端点(如
/healthz) - 可以在Service注解中指定健康检查路径:
annotations: service.beta.kubernetes.io/azure-load-balancer-health-probe-request-path: "/healthz"
为什么不用切换到标准Ingress?
你的自定义Nginx配置迁移成本高,而且标准Ingress Controller本质上也是基于Nginx的,解决真实IP问题的核心逻辑和上面的方案一致——都是通过调整LB和网络转发规则来保留源IP,所以完全没必要迁移。
内容的提问来源于stack exchange,提问作者ewramner

