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

时间:2016-03-26 09:27:34

标签: node.js networking docker haproxy

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

我的技术结构是: 我运行两个docker容器。一个用于haproxy,另一个用于nodejs,使用expressjs框架。所有传入流量都是由haproxy首先接收的,我用它来进行代理和负载均衡。 Haproxy根据配置文件中的ACLs将请求转发到适当的后端。

我尝试在我的nodejs中访问x-forwarded-for请求标头,但它只返回了docker网络网关接口172.17.0.1的IP。

标题为haproxy配置并使用option forwardfor header X-Client-IP块中的defaults也将x-client-ip标头设置为docker network gateway interface ip。此外,调试日志也记录了相同的IP。

所以这就是问题所在。由于haproxy在容器内运行,因此它认为docker网络网关接口是客户端。

如何将实际客户端的IP收集到容器内的haproxy,以便它可以将其转发到nodejs?

这是我的haproxy配置文件:

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

注意:我没有使用任何防火墙。另外,请随意建议我的配置有任何改进。保持活力也是一个问题。

2 个答案:

答案 0 :(得分:2)

最后在通过码头论坛搜索后找到了解决方案。

解决方案分为两个步骤。

首先,我需要将haproxy配置更新为:

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"

请注意option forwardfor块中添加了frontend http-in。这告诉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

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

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

答案 1 :(得分:1)

haproxy的工作方式不可行,因为当你在启动时没有连接主机时它会继续投掷,因为它需要完全解析地址。我已经尝试了很多变通办法(可能它可能),但我放弃并使用docker-compose

进行此操作

我发布了一个可能在帖子中提前帮助的运行示例。

要点是将容器与实际已存在的主机链接。这是由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