如何从haproxy docker容器中获取客户端IP?

我试图从我的nodejs服务器中的请求对象获取客户端的IP地址。

我的技术结构是:我运行两个docker集装箱。 一个是haproxy ,另一个是使用expressjs框架的expressjs 。 所有传入stream量首先由haproxy接收,我使用它代理和负载平衡。 Haproxy根据configuration文件中的ACLs将请求转发到适当的后端。

我尝试访问我的nodejs中的x-forwarded-for请求标头,但它只返回dockernetworking接口172.17.0.1的IP。

转到haproxyconfiguration,并在defaults块中使用option forwardfor header X-Client-IP还将x-client-ip头设置为docker网关接口ip。 此外,debugging日志也logging相同的IP。

所以这就是麻烦了。 由于haproxy在容器内部运行,因此认为haproxy网关接口是客户端。

我怎么能得到实际的客户端的IP haproxy在容器内,以便它可以转发到nodejs?

这是我的haproxyconfiguration文件:

 global debug maxconn 4096 defaults mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms timeout http-keep-alive 50000ms option http-keep-alive option http-server-close option forwardfor header X-Client-IP frontend http-in bind *:80 acl is_api hdr_end(host) -i api.3dphy-dev.com use_backend api if is_api default_backend default backend default server s0 "${DOCKER_INTERFACE_IP}:3000" backend api balance leastconn option httpclose option forwardfor server s1 "${DOCKER_INTERFACE_IP}:17884" 

我运行我的haproxy容器使用:

 docker run -d --name haproxy_1 -p 80:80 -e DOCKER_INTERFACE_IP=`ifconfig docker0 | grep -oP 'inet addr:\K\S+'` -v $(pwd)/config/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro haproxy:1.6 

注意:我没有使用任何防火墙。 另外,随时提出我的configuration的任何改进。 保持活力也被certificate是一个问题。

最后通过docker论坛find了一个解决scheme。

解决scheme是一个两步的过程。

首先我需要更新我的haproxyconfiguration:

 global debug maxconn 4096 defaults mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms timeout http-keep-alive 50000ms option http-keep-alive option http-server-close frontend http-in bind *:80 option forwardfor acl is_site hdr_end(host) -i surenderthakran-dev.com use_backend site if is_site default_backend default backend default server s0 "${DOCKER_INTERFACE_IP}:3000" backend site balance leastconn option httpclose option forwardfor server s1 "${DOCKER_INTERFACE_IP}:17884" 

注意在frontend http-in块中添加option forwardfor 。 这告诉haproxy的前端部分将客户端IP添加到请求头。

其次,docker run命令应该更新为:

 docker run -d --name haproxy_1 -p 80:80 -e DOCKER_INTERFACE_IP=`ifconfig docker0 | grep -oP 'inet addr:\K\S+'` -v $(pwd)/config/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro --net=host haproxy:1.6 

注意在--net=host run命令中增加了--net=host选项。 它告诉docker启动新的容器,并使用与主机相同的网卡。

现在,原始客户端IP被添加到请求头中,并且可以在请求被转发到的任何应用程序的x-forwarded-for请求头中被访问。

haproxy的工作方式是不可能的,因为它在启动时不连接主机,因为它需要完全parsing地址,所以它一直处于抛出状态。 我已经尝试了很多解决方法(也许这是可能的),但是我放弃了,并且用docker-compose

我发布了一个运行的例子,可以帮助更早的post。

要点是将容器与实际已经存在的主机连接起来。 这是由docker链接完成的。

泊坞窗,compose.yml

 api1: build: . dockerfile: ./Dockerfile ports: - 3955 links: - mongo - redis environment: - REDIS_HOST=redis - MONGO_HOST=mongo - IS_TEST=true command: "node app.js" api2: build: . dockerfile: ./Dockerfile ports: - 3955 links: - mongo - redis environment: - REDIS_HOST=redis - MONGO_HOST=mongo - IS_TEST=true command: "node app.js" mongo: image: mongo ports: - "27017:27017" command: "--smallfiles --logpath=/dev/null" redis: image: redis ports: - "6379:6379" haproxy: image: haproxy:1.5 volumes: - ./cluster:/usr/local/etc/haproxy/ links: - "api1" - "api2" ports: - 80:80 - 70:70 expose: - "80" - "70" 

haproxy.cfg

 global log 127.0.0.1 local0 log 127.0.0.1 local1 notice defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 10000 timeout server 10000 listen stats :70 stats enable stats uri / frontend balancer bind 0.0.0.0:80 mode http default_backend aj_backends backend aj_backends mode http balance roundrobin option forwardfor http-request set-header X-Forwarded-Port %[dst_port] http-request add-header X-Forwarded-Proto https if { ssl_fc } option httpchk HEAD / HTTP/1.1\r\nHost:localhost default-server inter 3s fall 5 server api1 api1:3955 server api2 api2:3955 
Interesting Posts