SL Linux 6.0 上安裝 haproxy 通透模式(tproxy) 安裝筆記

SL Linux 是 RHEL 6.0 的翻版 , 所以核心是 2.6.32 , 因此這個版本本身就俱備 TProxy 的功能可以做 socket 的通透代理 , 意思就是說 , 在做 Proxy 時 , 傳遞給目標主機時 , 仍然會把來源真實 IP 帶過去 , 目標主機得到的不會是 Proxy Server 的 IP .
好了 , 廢話不說 , 下圖是一個實驗性的 Web Loading Balance 簡單配置架構 , 我將以此架構來做 Haproxy 通透代理

除了 HA Proxy 俱備一個 123.123.123.1 (對外的 public ip) , 內部的 Web Server 則是用一個小 Hub 串接為一個 Private LAN , 這樣內部 Server 都與外隔絕了 , 而 HA Proxy 也必須充當 NAT Server , 不然內部的 Web Server 都沒辦法進行更新或 ntp 更新 , 這個架構是一個簡單的網站負載平衡架構 , HA Proxy 會依照設定將流量分別導到 Web Server 1 及 Web Server 2 , 當然也有其他方式可以做到 , 例如 lvs , 但 haproxy 可以做到 L7 的層級 , 雖然效能不能和 lvs 比 , 但也不會慢到那 , 算是一種窮人解決方案

安裝前的準備

  1. 確定 Haproxy 上有沒有 epel 可以給 yum 用 , 可以參考這篇 http://fedoraproject.org/wiki/EPEL , 去下載 RHEL 6.0 的 rpm 來裝
  2. 用 yum install haproxy 安裝 haproxy
  3. 確定一下 haproxy 那台的 iptables service 都要打開

設定方式

要讓 haproxy 以 tproxy 運作通透代理必須設定 ip rule 及 iptables , 從 google 上找到這篇 http://blog.loadbalancer.org/configure-haproxy-with-tproxy-kernel-for-full-transparent-proxy/ , 基本上按照這篇設定 ip rule 及 iptables 是可以動作的 , 但美中不足的是 , 若 Web Server 的 GateWay 都指向 Haproxy 那台 IP , 會發生由 Web Server 本身要抓取自己 url 會等老半天發生錯誤 , 當然也可以透過修改 /etc/hosts 方式解決 , 但總覺得很呆 , 於是又找了一下發現了一招 , 可以由 iptables 設定將特定 sub net 轉成另一組 sub net 來解決 , 於是綜合上述的網址 , ip rule 及 iptables 的設定方法寫成如下

iptables -t mangle -N DIVERT
iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
iptables -t mangle -A DIVERT -j MARK --set-mark 111
iptables -t mangle -A DIVERT -j ACCEPT

iptables -A FORWARD -i eth+ -j ACCEPT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j NETMAP --to 192.168.10.0/24

ip rule add fwmark 111 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100

echo 1 > /proc/sys/net/ipv4/conf/all/forwarding
echo 1 > /proc/sys/net/ipv4/conf/all/send_redirects
echo 1 > /proc/sys/net/ipv4/conf/eth0/send_redirects


注意一下 , iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j NETMAP --to 192.168.10.0/24 部分比較怪異 , 這是把內網(web server) 的 ip 改成 192.168.10 的區段 , 事實上這個區段必須是不存在的  , 這樣才可以內網WEB SERVER對自己的 URL 存取可正常運作 , 當設定好後 , haproxy 的設定檔部分 , 每個 backend server 的設定要加上  source 0.0.0.0 usesrc clientip 才會使用 transparent 模式 , 下面就列出一個以上面架構圖為主的 haproxy 設定範例

global
# 原本有 user 及 group 要註解掉 , 因為這種設定要用 root 才能跑
#    user        haproxy
#    group       haproxy
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    daemon
    # turn on stats unix socket
     stats socket /var/lib/haproxy/stats

defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000
    balance roundrobin

frontend frontend_main
        bind 123.123.123.1:80
        option  forwardfor
        mode    http
        # 下一行判斷是否為 crazy. 為開頭的網址
        acl             crazy_ha hdr_dom(host) -i crazy
        # 如果符合 crazy_ha 的 rule , 就使用 backend_crazy 的設定
        use_backend     backend_crazy if crazy_funuv
        # 下一行是預設的 backend 設定
        default_backend backend_default
# 這個 backend_crazy 只是為了證明 haproxy L7 的用法
 backend backend_crazy
        mode    http
        option  forwardfor
        source  0.0.0.0 usesrc clientip
        cookie  SERVERID insert nocache indirect
        server  server1 192.168.0.11:80 weight 1 cookie server1 check
        option  redispatch

backend backend_default
        mode    http
        option  forwardfor
        source  0.0.0.0 usesrc clientip
        cookie  SERVERID insert nocache indirect
        server  server1 192.168.0.11:80 weight 1 cookie server1 check
        server  server1 192.168.0.12:80 weight 1 cookie server1 check
        option  redispatch

以上設定完後並且執行那 ip rule 及iptables 設定後可能會因為 SSH 連線時也是內網 IP 而斷線 , 因為上面紅字的部分的關係啦 , 斷線後重連就好了, 接著重啟 haproxy 就可以觀察一下 web server 中的 httpd log 是否 ip 都換成了真實來源的 IP , 而內網自己抓自己時則會發現 ip 會變成 192.168.10.xx 

完B

15 則評論在 SL Linux 6.0 上安裝 haproxy 通透模式(tproxy) 安裝筆記.

  1. Pigo前輩你好,
    參考了你的文章我試著建立Haproxy 通透模式,不過無論如何都無法成功。

    已經嘗試了好幾天了…
    我試過:
    使用CentOS 5.5 Kernel 更新至 2.6.32,自己編譯iptables 1.4.10, 編譯haproxy 1.4, 測試後 –> 失敗
    使用SUSE 11 Kernel 2.6.32, iptables 1.4.x , 編譯haproxy 1.4, 測試後 –> 失敗
    使用SL Linux 6 Kernel 2.6.32, iptables 1.4.x, EPEL的haproxy 1.4, 測試後 –> 失敗

    最後都是 503 Service Unavaliable,看起來都像是卡在同樣的地方,關掉通透模式正常。
    目前是測試環境,Haproxy主機 eth0 內網, eth1外網。後端一台web eth0內網,eth1外網。
    HAProxy 連接Web時,通透模式下 連接外網或內網均無法正常運作通透模式。
    是否可請你協助一下提點一下問題點可能在哪,或者登入我的測試環境主機協助指點。
    如果你願意抽空解惑的話,請透過我的E-mail聯繫我。感激不盡!

  2. 謝謝Pigo,的確是要將內網Gateway設定為Haproxy的ip才能正常運作。

    那試問一下,如果預設的Gateway不設定為Haproxy的IP,有沒有方式可以正常運作呢?

    針對這個問題我思考的方向是用Iptables 進行NAT或者是加上IP route的方式,不知道是否可行?

  3. 這個問題 , 我也沒有去實作 , 如果是要針對特定網段傳輸另設 ip route 應該是可以 , 但如果要判斷非 80 port 而走不同 gateway , 我還想不出該怎麼弄呢

    我自己是有想過一招 , 不過還沒實做過

    就是內網的網卡弄出兩個 ip (alias) , 例如 haproxy 對Server A 的192.168.2.11 , 而Server A預設主 ip 是 192.168.2.10 , 這個主 ip 就是走正常 gateway , 而 192.168.2.11 就設定 gateway 是 haproxy ip , 不知道這樣可不可以

  4. 謝謝Pigo, 你提供的方案我會思考並嘗試看看。
    其實是我手邊有一些服務主機必須24小時運作,這些主機目前是外網IP。
    我原打算上HAProxy後,將這些服務的DNS改為HAProxy來運作,
    在DNS完全發佈生效之前(略估最久24小時),外網IP的主機原外網IP還必須繼續使用。
    而這些外網主機必須接收到正確的外部Client端IP。
    所以我才會有可能不能透過HAProxy當做Gateway的疑慮。
    我認為通透模式下,即使HAProxy的Server1設定給他外網IP應該Server1拿不到正確的外部Client IP。
    才想請教一下Pigo前輩有沒有什麼方案可以參考。

  5. 謝謝Pigo,目前已經將HAProxy導入運作中,不過…

    iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j NETMAP –to 192.168.10.0/24

    這段看起來沒有運作,我還是需要寫入hosts才能改善抓不到網址的問題。
    我的內網是10.1.100.254 (HAProxy) 後端兩台為 10.1.91.11, 10.1.91.12
    Netmask 是 255.255.0.0。

    即使我加上了NETMAP這段如下:
    iptables -t nat -A POSTROUTING -s 10.1.91.0/24 -j NETMAP –to 10.1.99.0/24

    在內部的兩台主機測試,用 wget test.mycom.tw/test.html還是無法正常,使用hosts寫死才ok。
    不知道是不是因為Netmast 是 /16的原因。這方面Pigo有沒有什麼建議能用NETMAP的方式?


  6. 其實我也不太清楚 NETMAP 內部運作原理

    我只是猜測你的 SERVER MASK 都是 16 , 10.1.91.0 和 10.1.99.0 都是同一區段 , 做 NETMAP 搞不好就失敗了 , 所以換一個不會重複到的區段應該就可以了

  7. Pigo您好,不知道能不能向您請教一下
    當我設定cookie SERVERID insert nocache indirect後
    haproxy就會給連進來的client端一個SERVERID的cookie
    所以這就表示cookie的機制他已經啟動嗎?
    也就是說如果這樣她就會依照client給haproxy的cookie去倒到相對應的後端server這樣嗎?(ex:SERVERID=A 導到A主機)
    因為我希望能依照我的設定將client導到我想指派的server
    原本的想法是想將他給的SERVERID的值直接改掉
    (例如: 原本haproxy丟給client的是SERVERID = A但我經過測試覺得丟給B比較好所以強制改成SERVERID = B)
    但我trace 他的source code好久卻都找不到他處理cookie然後導向到後端主機的地方
    原本我認為應該是在source code裡proto_http.c下的manage_client_side_appsession這個function裡
    但做了測試卻發現好像haproxy跟本沒跑進這個funtion裡
    等於好像在做原本預設的roundrobin
    所以我才想說是不是設定檔沒有設定好那個功能沒有開啟
    又或者是導向server的code另在別處
    卡了好久..
    希望大大能為我解惑…
    感激不盡!!!

  8. To Roby:
    你的Netmask 是 255.255.0.0。所以不生效的那一句应该要改成如下才会生效:
    iptables -t nat -A POSTROUTING -s 10.1.91.0/16 -j NETMAP –to 10.1.99.0/16
     

  9. JJ :

    請問pigo~

    若 HAProxy 的模式是 tcp 不是 http,tproxy 運作是否就會失效…

    我測試導 pop3 service,但卻一直失敗…:(

    抱歉,我沒試過導 tcp 耶,不過 tcp 和 http 應該是差不多的才對,你要不要試試看直接命令列執行 haproxy 的 debug 模式運作看看 Log , tcp mode 的設定應該不能包含 http 的命令,如 forwardfor

發佈留言