- 浏览: 194880 次
- 性别:
- 来自: 南京
文章分类
最新评论
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环境:
2.Docker swarm接收外部请求的处理流程
Docker swarm利用ingress overlay网络处理外部请求,并利用IPVS做外部负载均衡,具体可参考docker swarm-服务发现与负载均衡
2.1 IPVS有三种NAT、IP Tunneling和 DR,
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,具体的启动命令是
有亮点需要说明:
zuul配置片段:
除了用service create方式外,还可以用docker run的方式绕过ingress网络,方法如下
具体应用服务获取客户端IP的代码片段:
如果用nginx,
配置参照 this working nginx configuration
最近在项目中遇到一个问题,因为业务要求,需要在服务中获取到客户端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
发表评论
-
解决spring boot应用以docker容器方式启动后,进程ID是1而导致的jstack和jmap等命令不可用的问题
2019-09-12 10:01 2549[TOC] 目的 解决spring boot应用以docker ... -
服务启动好后起防火墙
2019-03-27 09:46 0docker 服务创建好以后,启动防火墙,启动服务报如下错误 ... -
Docker CI环境迁移(备份,还原)
2018-08-30 20:06 2000一、Gitlab 备份及还原 在原机器上执行 docker e ... -
docker swarm-服务发现与负载均衡原理分析
2017-11-28 16:49 4396本文主要翻译自Docker Reference Archite ... -
docker配置日志自动清理
2017-08-04 13:55 5743一、简述 随着系统的运行,每个docker容器都会产生大量 ... -
docker registry 批量删除镜像
2017-10-20 09:51 1976参考地址 registry delete registry版本 ... -
Docker Jenkins gitlab CI环境
2017-01-21 09:45 1504本文介绍利用docker、docker gitlab/gitl ... -
Docker 安装Jenkins
2017-01-15 10:10 26231.安装docker 2.安装docker-c ... -
Docker 搭建gitlab
2017-01-15 09:21 948系统 ubuntu 16.04l 1.安装 docker 2. ... -
Docker gitlab
2017-01-11 23:07 0nexus: docker volume create -- ... -
Docker 搭建maven私服
2017-01-09 17:50 1745Docker 镜像docker-nexus3 1.创建dat ... -
Docker 安装
2017-01-08 21:15 746操作系统 Ubuntu Xenial 16.04(x86_64 ...
相关推荐
Docker swarm守护程序,可修改入口网格路由以将真实的客户端IP暴露给服务容器: 纯粹通过路由和防火墙规则实施; 所以 无需运行traefik或其他反向代理等其他应用层; 所以 无需重新配置您现有的应用程序。 据我们所...
在Python中封装Docker Swarm的API,主要是通过Python的`docker`库,这是一个强大的客户端库,能够与Docker守护进程进行交互。使用这个库,我们可以执行诸如创建、更新、查看和删除服务、节点、网络等操作。以下是...
在IT领域,Docker Swarm是Docker公司推出的一款容器编排工具,用于管理和调度Docker容器集群。这个名为"Docker Swarm 管理资源.rar"的压缩包很可能包含了一系列关于如何使用Docker Swarm进行资源管理的教程、文档、...
在IT行业中,Docker Swarm、Portainer CE和Nginx是三个非常重要的工具,它们各自在容器编排、管理以及Web服务器领域发挥着关键作用。本文将深入探讨这些组件的功能、用途及其最新版本20.10.17、2.14.2和1.23.1的特点...
我们可以为待部署应用服务指定一个 Overlay 网络,当应用服务初始化或者进行更新时,Swarm Manager 在给定的 Overlay 网络中为 Docker 容器自动地分配 IP 地址,实际是一个虚拟 IP 地址(VIP)。 7. 服务发现 ...
### Java获取客户端真实IP的两种方法详解 #### 一、问题背景 在Web开发中,经常需要获取客户端的真实IP地址来进行一系列的操作,比如统计访问来源、进行地理定位、安全防护等。然而,在实际应用场景中,客户端请求...
2. **获取Swarm信息**:使用Node.js的`dockerode`库,通过Docker Remote API查询Swarm集群的状态,包括节点、服务和任务列表。 3. **数据处理**:解析获取到的JSON数据,将其转化为适合D3.js绘图的格式。 4. **D3....
2. **加入集群**:其他主机使用 `docker swarm join` 命令,用管理节点的 token 和 IP 加入集群。 3. **检查集群状态**:使用 `docker node ls` 查看加入的节点,`docker service inspect` 查看集群详情,`docker ...
- 在 Manager 节点上执行命令 `docker swarm init --advertise-addr <MANAGER-IP>`。例如: ```bash docker swarm init --advertise-addr 192.168.99.100 ``` - 初始化成功后会返回一段包含 Join 命令的信息,...
加入令牌可以从主管理节点使用 `docker swarm join-token worker` 命令获取。 ### 3. 查询集群节点列表 在 Swarm 的管理节点上,可以使用 `docker node ls` 命令来查看集群中的所有节点状态,包括节点 ID、角色...
### Docker Swarm 集群搭建和试验 #### Docker Swarm 概述 Docker Swarm 是一个由 Docker 官方提供的用于创建 Docker 主机集群的工具。它具有多项关键特性,包括但不限于服务发现、负载均衡、任务分发与调度、服务...
将功能作为服务(在Docker Swarm之上)
Linux运维-运维课程MP4频-05容器-69dockerswarm网络存储卷-nfs准备.mp4
docker swarm部署分布式微服务编排文件示例
Docker Swarm是Docker自带的集群管理工具,它将多个Docker主机合并为一个虚拟的Docker主机,能够进行高效和快速的负载均衡。通过Swarm模式,Docker管理节点负责维护集群状态并分发任务至各个工作节点。在Swarm模式下...
本文介绍了docker swarm 集群故障与异常详解,分享给大家,具体如下: 在上次遭遇 docker swarm 集群故障后,我们将 docker 由 17.10.0-ce 升级为最新稳定版 docker 17.12.0-ce 。 前天晚上22:00之后集群中的2个...
1. **Docker Swarm**:Docker Swarm是Docker的集群管理工具,它将多个Docker宿主机转换为一个单一的虚拟系统,允许用户在一个分布式系统上进行服务部署和管理。在本场景中,Docker Swarm被用来部署Spring Cloud应用...
使用单个命令,您可以将Mongos , Config和Data副本集部署到Docker Swarm上,形成一个高可用性的MongoDB集群,该集群能够在不中断服务的情况下承受多个节点的故障。 Docker堆栈由两个MongoDB副本集,两个Mongos实例...
ansible-dockerswarm, 基于"Swarm Mode" 和Ansible的Docker 引擎 Ansible角色:Docker 群 在 Docker/centos和 debian/ubuntu服务器上使用新的Docker"发动机模式群"( https://docs.docker.com/engine/swarm/ ) 建立集