2016-03-26 76 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