`

docker swarm获取客户端IP

阅读更多
1.问题概述
最近在项目中遇到一个问题,因为业务要求,需要在服务中获取到客户端IP,但是在项目开发部署过程中发现利用java -jar ***.jar单独运行服务,或者打成镜像再docker run启动的服务都可以正确的获取到client IP,但是当采用docker stack deploy发布到docker swarm集群的时候,服务却获取不到正确的client IP了,得到的都是10.255.0.* 这样的IP,因为业务逻辑必须获取正确的client IP,所以有了下面的这个调查。
系统框架:spring boot、spring cloud、docker、docker swarm
spring boot version:1.5.1.RELEASE
spring cloud version:Dalston.SR4
docker环境:
Containers: 7
 Running: 4
 Paused: 0
 Stopped: 3
Images: 31
Server Version: 1.13.1
Storage Driver: overlay
 Backing Filesystem: extfs
 Supports d_type: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins: 
 Volume: local
 Network: bridge host macvlan null overlay
Swarm: active
 NodeID: qhsk9yp9h2md9qsopj7u6cjvg
 Is Manager: false
 Node Address: 192.168.0.138
 Manager Addresses:
  192.168.0.139:2377
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: aa8187dbd3b7ad67d8e5e3a15115d3eef43a7ed1
runc version: 9df8b306d01f59d3a8029be411de015b7304dd8f
init version: 949e6fa
Security Options:
 seccomp
  Profile: default
Kernel Version: 3.10.0-514.el7.x86_64
Operating System: Red Hat Enterprise Linux Server 7.3 (Maipo)
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 7.549 GiB
Name: bogon
ID: SZAV:QNS7:DI5C:RYIP:LM5Y:QCF3:KHS5:6KHD:XHC2:2KGF:Y3KI:CWHT
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Experimental: false
Insecure Registries:
 192.168.0.102:5000
 registry:5000
 127.0.0.0/8
Registry Mirrors:
 http://192.168.0.102:5000
Live Restore Enabled: false


2.Docker swarm接收外部请求的处理流程
Docker swarm利用ingress overlay网络处理外部请求,并利用IPVS做外部负载均衡,具体可参考docker swarm-服务发现与负载均衡
2.1  IPVS有三种NAT、IP Tunneling和 DR,
  • NAT工作模式,简单来说就是传统的NAT,进出流量都需要经过调度器,调度器会选择一个目的服务器,将进入流量的目标IP改写为负载均衡到的目标服务器,同时源IP地址也会改为调度器IP地址。机制简单,但限制大,IPVS需要维护每个映射关系,而且进出入流量都需要经过调度器,实际上这个会成为瓶颈。
  • TUN工作模式,即IP Tunneling模式。这种模式中,调度器将进入的包重新包成一个IP包,然后发送给选定的目的服务器,目的服务器处理后,直接将应答发送给客户(当然该重新封装的报文的源IP地址还是要填成调度器的)。
  • DR工作模式,即Direct Routing模式。这种模式中,调度器直接重写进入包的mac地址,将其改为选定的目标服务器的mac地址,这样就可以到达服务器。但这样的话需要要求IPVS服务器需要和真实服务器在同一局域网内,且真实服务器必须有真实网卡(这样重写了mac地址的报文才可以才可以到达该服务器)

2.2 docker ingress网络的选择
Docker ingress为了满足所有节点都可以接收请求,即便是没有相应服务的节点也要能提供服务(routing mesh),采用了NAT模式,请求进入ingress网络后,会把源地址修改成收到请求的节点的ingress 网络的IP地址,默认情况下是10.0.255.*,再找到具体服务所在的节点,把请求转发过去,把目标地址改成真正服务对应的IP,返回时也是先返回到接收请求的节点再返回到客户端,所有在docker swarm里面的服务获取不到真实的client ip
3.解决方法
这个问题在docker的issues中有很多人讨论,具体可以看Unable to retrieve user's IP address in docker swarm mode #25526,幸运的是docker 在docker engine 1.3.0中追加了一个新的特性 --publish可以指定mode=host,用来绕过ingress网络,根据这个特性,我们项目的解决思路是在所有的服务外层利用nginx或者zuul等做一个反向代理,并且这个代理不能用docker stack deploy的形式启动,要用server create的方式启动,并且要指定publish的mode=host。compose文件在3.2版本中才加入了ports的新语法来支持这个host模式,需要docker engine在17.04.0及以上版本才能支持。
我们项目里面用的是zuul,具体的启动命令是
docker service create --name zuu-server --publish "mode=host,target=8080,published=8080" --mode global --network mynet image/zuul:1.0.0

有亮点需要说明:
  • 因为用了mode=host应用就不会利用ingress网络,所以服务对应的task在哪个节点上那个节点才能接收外部请求,为了还要满足在任意节点上都可以访问到服务,所以把发布模式定义成了global
  • zuul接到请求后单纯的根据配置把请求转发到具体的服务,为了能在zuul中能发现其他的服务,zuul还必须在自建的mynet网络里面

zuul配置片段:
zuul:
  sensitive-headers: Cookies
  add-host-header: true
  forceOriginalQueryStringencoding: true
  routes:
    portal:
      path: /portal/**
      serviceId: portal  
      stripPrefix: false
   .....


除了用service create方式外,还可以用docker run的方式绕过ingress网络,方法如下
  • 创建attachable overlay network:docker network create --attachable  --driver overlay --subnet 10.0.0.1/16 mynet
  • docker run -d -p 8080:8080 --name zuuServer --net mynet image/zuul:1.0.0


具体应用服务获取客户端IP的代码片段:
String ips = request.getHeader("x-forwarded-for");
		if (StringUtils.isEmpty(ips)) {
			ips = request.getHeader("Proxy-Client-IP");
		}
		if (StringUtils.isEmpty(ips)) {
			ips = request.getHeader("WL-Proxy-Client-IP");
		}
		if (StringUtils.isEmpty(ips)) {
			ips = request.getRemoteAddr();
		}
      String ip = Arrays.stream(ips.split(",")).filter(ip-> ! StringUtils. equalsIgnoreCase("unkonwn",ip)).findFirst().get();


如果用nginx,
docker service update nginx_proxy \
	--publish-rm 80 \
	--publish-add "mode=host,published=80,target=80" \
	--publish-rm 443 \
	--publish-add "mode=host,published=443,target=443"


配置参照 this working nginx configuration
分享到:
评论

相关推荐

    docker-ingress-routing-daemon:Docker swarm守护程序,可修改入口网格路由以将真实的客户端IP暴露给服务容器

    Docker swarm守护程序,可修改入口网格路由以将真实的客户端IP暴露给服务容器: 纯粹通过路由和防火墙规则实施; 所以 无需运行traefik或其他反向代理等其他应用层; 所以 无需重新配置您现有的应用程序。 据我们所...

    Python-DockerSwarm模式集群操作API封装和SwarmUI的中间层应用

    在Python中封装Docker Swarm的API,主要是通过Python的`docker`库,这是一个强大的客户端库,能够与Docker守护进程进行交互。使用这个库,我们可以执行诸如创建、更新、查看和删除服务、节点、网络等操作。以下是...

    Docker Swarm 管理资源.rar

    在IT领域,Docker Swarm是Docker公司推出的一款容器编排工具,用于管理和调度Docker容器集群。这个名为"Docker Swarm 管理资源.rar"的压缩包很可能包含了一系列关于如何使用Docker Swarm进行资源管理的教程、文档、...

    docker swarm 20.10.17 + portainer-ce 2.14.2 + nginx 1.23.1 离线包

    在IT行业中,Docker Swarm、Portainer CE和Nginx是三个非常重要的工具,它们各自在容器编排、管理以及Web服务器领域发挥着关键作用。本文将深入探讨这些组件的功能、用途及其最新版本20.10.17、2.14.2和1.23.1的特点...

    Docker Swarm架构的特性与基本实践.docx

    我们可以为待部署应用服务指定一个 Overlay 网络,当应用服务初始化或者进行更新时,Swarm Manager 在给定的 Overlay 网络中为 Docker 容器自动地分配 IP 地址,实际是一个虚拟 IP 地址(VIP)。 7. 服务发现 ...

    java非常强的获取客户端真实IP的两种方法

    ### Java获取客户端真实IP的两种方法详解 #### 一、问题背景 在Web开发中,经常需要获取客户端的真实IP地址来进行一系列的操作,比如统计访问来源、进行地理定位、安全防护等。然而,在实际应用场景中,客户端请求...

    DockerSwarm的一个可视化工具使用DockerRemoteAPINodeJS和D3实现

    2. **获取Swarm信息**:使用Node.js的`dockerode`库,通过Docker Remote API查询Swarm集群的状态,包括节点、服务和任务列表。 3. **数据处理**:解析获取到的JSON数据,将其转化为适合D3.js绘图的格式。 4. **D3....

    第四章:Docker容器升华--swarm集群1

    2. **加入集群**:其他主机使用 `docker swarm join` 命令,用管理节点的 token 和 IP 加入集群。 3. **检查集群状态**:使用 `docker node ls` 查看加入的节点,`docker service inspect` 查看集群详情,`docker ...

    docker SWARM 部署教程

    - 在 Manager 节点上执行命令 `docker swarm init --advertise-addr <MANAGER-IP>`。例如: ```bash docker swarm init --advertise-addr 192.168.99.100 ``` - 初始化成功后会返回一段包含 Join 命令的信息,...

    使用Docker swarm初始化一个集群.pptx

    加入令牌可以从主管理节点使用 `docker swarm join-token worker` 命令获取。 ### 3. 查询集群节点列表 在 Swarm 的管理节点上,可以使用 `docker node ls` 命令来查看集群中的所有节点状态,包括节点 ID、角色...

    docker swarm 集群搭建和试验

    ### Docker Swarm 集群搭建和试验 #### Docker Swarm 概述 Docker Swarm 是一个由 Docker 官方提供的用于创建 Docker 主机集群的工具。它具有多项关键特性,包括但不限于服务发现、负载均衡、任务分发与调度、服务...

    Go-将功能作为服务(在DockerSwarm之上)

    将功能作为服务(在Docker Swarm之上)

    Linux运维-运维课程MP4频-05容器-69dockerswarm网络存储卷-nfs准备.mp4

    Linux运维-运维课程MP4频-05容器-69dockerswarm网络存储卷-nfs准备.mp4

    docker_swarm_service_componse.yml

    docker swarm部署分布式微服务编排文件示例

    基于Docker Swarm的台站分布式系统设计的技术可行性分析.pdf

    Docker Swarm是Docker自带的集群管理工具,它将多个Docker主机合并为一个虚拟的Docker主机,能够进行高效和快速的负载均衡。通过Swarm模式,Docker管理节点负责维护集群状态并分发任务至各个工作节点。在Swarm模式下...

    docker swarm 集群故障与异常详解

    本文介绍了docker swarm 集群故障与异常详解,分享给大家,具体如下: 在上次遭遇 docker swarm 集群故障后,我们将 docker 由 17.10.0-ce 升级为最新稳定版 docker 17.12.0-ce 。 前天晚上22:00之后集群中的2个...

    docker swarm部署springcloud1

    1. **Docker Swarm**:Docker Swarm是Docker的集群管理工具,它将多个Docker宿主机转换为一个单一的虚拟系统,允许用户在一个分布式系统上进行服务部署和管理。在本场景中,Docker Swarm被用来部署Spring Cloud应用...

    mongo-swarm:在Docker Swarm上引导MongoDB分片集群

    使用单个命令,您可以将Mongos , Config和Data副本集部署到Docker Swarm上,形成一个高可用性的MongoDB集群,该集群能够在不中断服务的情况下承受多个节点的故障。 Docker堆栈由两个MongoDB副本集,两个Mongos实例...

    ansible-dockerswarm, 基于"Swarm Mode" 和Ansible的Docker 引擎.zip

    ansible-dockerswarm, 基于"Swarm Mode" 和Ansible的Docker 引擎 Ansible角色:Docker 群 在 Docker/centos和 debian/ubuntu服务器上使用新的Docker"发动机模式群"( https://docs.docker.com/engine/swarm/ ) 建立集

Global site tag (gtag.js) - Google Analytics