Docker中Swarm的Overlay网络无法获取原始IP解决方案

问题背景

开发的项目中有IP定位的需求,当我接入腾讯地图相关IP定位及逆地址解析API并发布到外网后,却发现获取的IP一直是固定的内网IP(10.255.0.2)导致无法定位

问题排查

我的项目采用nginx作为反向代理,在代理中做以下配置转发请求原始IP

proxy_set_header X-Real-IP $remote_addr

然后在nginx打印的日志中$remote_addr已经是此内网IP,导致后续设置的请求头X-Real-IP就是此IP。我的应用是发布在Docker的swarm集群中,因此判定问题出在swarm集群。经过网上搜索资料后发现:
原始IP请求进入Ingress网络(swarm load balancer)后,原始IP被SNAT修改为内部Ingress网络的IP段,如10.255.0.x,之后才会被转发到service container。这会导致在service container中获取的远端IP始终是Ingress内部的虚拟IP段。此时会导致白名单、外网IP访问日志记录等依托正确外网IP解析的功能全部失效。

解决方案

方案一

将反向代理nginx以独立容器形式部署,不再部署在swarm集群中。此时nginx获取到的$remote_addr就是真实的原始IP,转发到swarm集群后的请求的请求头X-Real-IP已经在反向代理中设置过了,所以后续服务中就可以获取到真实的原始IP。PS:作者是采用的此方案

方案二

采用host模式+打标签,这种解决方案其实本质上和方案一是一样的,只是实现方式不同。在发布反向代理服务时,仍发布到swarm集群中,但是开放端口时指定mode=host。例如:

docker service create --name nginx --publish "mode=host,target=80,published=80" --mode global --network mynet image/nginx:1.0.0

方案三

docker ingress routing daemon的后台脚本增强方案,是一个轻量级的解决方案,需要在swarm各个节点实现运行一个后台脚本。该脚本需要指定一个ingress-gateway-ips的参数,可通过裸运行该脚本查看每一个swarm节点的ingress内部ip,通常为10.255.0.x。

Usage: /home/swarm/docker-ingress-routing-daemon.sh [--install [OPTIONS] | --uninstall | --help]
           --services <services>  - service names to disable masquerading for
           --tcp-ports <ports>    - TCP ports to disable masquerading for
           --udp-ports <ports>    - UDP ports to disable masquerading for
   --ingress-gateway-ips <ips>    - specify load-balance ingress IPs
              --no-performance    - disable performance optimisations
    (services, ports and IPs may be comma or space-separated or may be specified
     multiple times)
!!! Ingress subnet: 10.255.0.0/16
!!! This node's ingress network IP: 10.255.0.2

特别注意:

  • 该脚本需要在部署应用前提前运行,如果在已有应用集群上运行无法生效。
  • 如果在应用集群运行后,该后台进程被杀掉,仍然不影响其作用(路由表依旧生效),但是后续新部署/更新的应用会失效。
  • 运维应该通过机制确保该脚本对应的后台守护进程始终存在,如果被误杀需要在下次更新部署前拉起。

此脚本原始项目链接
该后台脚本如下,参考命令:

nohup /root/docker-ingress-routing-daemon.sh --ingress-gateway-ips 10.255.0.2,10.255.0.3,10.255.0.4 --install &

版权声明:本文为baidu_38956956原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。