AKS集群出口流量通过内部负载均衡器固定源IP至LB IP的配置方案咨询
我完全理解你的痛点——用Kubenet的AKS集群里,pod出口流量默认走节点IP,而你需要固定成内部LB的IP来给on-prem服务做白名单,既不想把所有节点IP都加进去(成本高),也不想把pod钉死在单个节点上(失去集群弹性)。
先解释下你之前的配置为什么没生效:你创建的内部LoadBalancer服务默认是处理入口流量的,也就是外部(集群内或VNet内)请求进来时路由到pod,但pod主动发起的出口流量(比如访问on-prem服务)还是会走节点的SNAT规则,所以源IP还是节点IP,这是Kubenet的默认行为。
接下来给你几个可行的方案,按推荐优先级排序:
方案一:用Azure NAT网关(推荐,最简洁)
如果你的AKS集群所在的VNet有可用的私网NAT网关,你可以把AKS节点子网的出站流量路由到NAT网关,然后把NAT网关的静态内部IP配置给on-prem服务白名单。配置要点:
- 确保NAT网关的静态IP在VPN的路由范围内,on-prem服务能通过VPN访问到这个IP
- 具体步骤:
- 在AKS节点所在的子网,修改子网的出站路由,把默认路由指向NAT网关
- 给NAT网关分配一个静态的内部IP
- 把这个静态IP加到on-prem服务的白名单里
这样所有节点上的pod出口流量都会用NAT网关的IP作为源IP,不管pod跑在哪个节点上,完美解决你的弹性和固定IP的需求。
方案二:用Kubernetes SNAT规则结合内部LB(适合不想用NAT网关的场景)
这个方案需要手动配置iptables规则,让特定pod的出口流量先经过内部LB,再发往on-prem服务。具体步骤:
- 先确认你的内部LB服务(
my-service-egress)正常运行,获取它的静态内部IP:kubectl get service my-service-egress -n my-internal-service-namespace -o jsonpath='{.spec.clusterIP}' - 给你的
my-servicepod添加专属标签,比如egress-through-lb: true,方便后续规则精准匹配 - 在所有AKS节点上配置iptables规则,把目标为on-prem服务的流量路由到内部LB的IP(以on-prem服务IP为
192.168.1.100、端口8080为例):
注意:节点重启后iptables规则会消失,建议用DaemonSet来自动在所有节点上配置和维护这个规则。# 替换为你的内部LB IP、on-prem服务信息和AKS pod子网CIDR LB_IP="10.0.0.100" ON_PREM_IP="192.168.1.100" ON_PREM_PORT="8080" POD_SUBNET="10.244.0.0/16" iptables -t nat -A POSTROUTING -s $POD_SUBNET -d $ON_PREM_IP --dport $ON_PREM_PORT -j SNAT --to-source $LB_IP
方案三:调整Service的externalTrafficPolicy(局限性较大,不推荐)
你可以修改内部LB服务的spec.externalTrafficPolicy为Local,这样LB会直接把流量路由到本地节点的pod,避免跨节点转发。但这个方案的问题是:
- 需要确保每个节点上都运行
my-service的pod(比如用DaemonSet或者副本数等于节点数),否则LB会拒绝流量 - 本质上出口流量的源IP还是节点IP,只是减少了跨节点的SNAT,无法直接实现用LB IP作为源的需求,需要配合额外的SNAT规则才能生效
另外补充下你之前的LoadBalancer manifest问题:它只是一个普通的内部入口LB,不会主动接管pod的出口流量。如果想用LB来做出口,必须通过规则让pod的流量主动导向LB,这就是方案二的核心思路。
最后再提醒下:如果用方案一的NAT网关,一定要确认NAT网关的IP在VPN的路由范围内,且VPN连接是双向打通的,确保on-prem服务能正常回包。
备注:内容来源于stack exchange,提问作者Ed Boykin

