2016-03-26 42 views
1

我想从我的nodejs服务器中的请求对象获取客户端的IP地址。如何从haproxy docker容器中的请求获取客户端IP?

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

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

通过haproxy配置并在defaults块中使用option forwardfor header X-Client-IP也将x-client-ip标头设置为码头网络网关接口ip。此外,调试日志也记录相同的IP。

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

如何在容器内部将实际客户端的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 

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

+0

我花了好几天的时间来完成这项工作。我已经看到了恐怖......见下面的答案。我也有一个工作haproxy:1.6版本,但这不会是这里的问题。 – eljefedelrodeodeljefe

回答

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" 

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

二,搬运工运行命令应更新为:

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选项。它告诉码头启动新容器并使用与主机相同的网卡。

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

0

haproxy的工作方式是不可能的,因为它在启动时不连接主机,因为它需要完全解析地址,因此它会持续抛出。我已经尝试了很多解决方法(也许这是可能的),但我放弃了,并使其与docker-compose

运行我发布了一个运行的示例,可能会帮助更早的帖子。

要点是将容器与实际已经存在的主机相链接。这由码头链接完成。

泊坞窗,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