ロードバランサを構築 (DSR編)

この前ロードバランサをNAT構成で構築したので、今度はDSR構成で構築してみる。
当初はリアルサーバの lo にWebサービスの IP をエイリアスとして割り当てて環境を構築しようとしたんだけど失敗。ロードバランサの環境の構築自体はうまくいったんだけど、ホストPCからの名前解決がなぜかできなくなってしまった。調べたけど原因が解らなかったので、別の方法で構築することにした。だめじゃん。
最終的にネットワーク構成はこんな感じに。前回と同じだが、今回は Webサービスの口を VIP のアドレスにくっつける。

      |
      | 192.168.0.254/24 (eth0) [VIP]
      |
      | 192.168.0.7/24 (eth0)
+-----------+
|  lbsrv01  |  ロードバランサ
+-----------+
      | 192.168.1.3/24 (eth1)
      |
      +------------------------+
      |                        |
      | 192.168.1.1/24         | 192.168.1.2/24
+-----------+            +-----------+
|  wsrv01   |            |  wsrv02   |  Webサーバ
+-----------+            +-----------+

ロードバランサ準備

VIP宛のパケットを処理できるようにする。

lbsrv01 % sudo iptables -t mangle -A PREROUTING -d 192.168.0.254 -j MARK --set-mark 1
lbsrv01 % sudo ip rule add prio 100 fwmark 1 table 100
lbsrv01 % sudo ip route add local 0/0 dev lo table 100
lbsrv01 % sudo sysctl net.ipv4.conf.default.rp_filter=0

keepalived の設定ファイルの編集。

lbsrv01 % sudo vim /etc/keepalived/keepalived.conf
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
! Configuration File for keepalived
virtual_server_group example {
    192.168.0.254 80                        # VIP を設定する。 
}

virtual_server group example {
    delay_loop  5
    lvs_sched rr
    lvs_method DR                           # NAT から DR に変更する。 
  ...
  ...
  ...
/etc/keepalived/keepalived.conf ~~~~~~~~~~

Webサーバ準備

同じくVIP宛のパケットを処理できるようにする。

wsrv0[12] % sudo iptables -t nat -A PREROUTING -d 192.168.0.254 -j REDIRECT

クライアント準備

VIPへの経路を設定する。

localhost % sudo route add 192.168.0.254 192.168.0.7 255.255.255.0

動かしてみる

keepalived 起動。

lbsrv01 % sudo service keepalived start

確認。

lbsrv01 % sudo ipvsadm -Ln                                      
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.0.254:80 rr
  -> 192.168.1.2:80               Route   1      0          0         
  -> 192.168.1.1:80               Route   1      0          0   

クライアントからリクエストを出す。

localhost % curl http://192.168.0.254                               
wsrv01
localhost % curl http://192.168.0.254
wsrv02

パケットを覗いてみる

クライアント(192.168.0.5)から接続する。

% telnet 192.168.0.254 80

そうすると各サーバはどうなるかというと。
ロードバランサ (eth0)

% sudo tcpdump  -n -i eth0 port 80 and host 192.168.0.5
22:13:49.946467 IP 192.168.0.5.55237 > 192.168.0.254.http: S 2412448495:2412448495(0) win 65535 <mss 1460,nop,wscale 3,nop,nop,timestamp 59097693 0,sackOK,eol>
22:13:49.948681 IP 192.168.0.254.http > 192.168.0.5.55237: S 1060219761:1060219761(0) ack 2412448496 win 5792 <mss 1460,sackOK,timestamp 1644563 59097693,nop,wscale 1>
22:13:49.949302 IP 192.168.0.5.55237 > 192.168.0.254.http: . ack 1 win 65535 <nop,nop,timestamp 59097694 1644563>

ロードバランサ (eth1)

% sudo tcpdump  -n -i eth1 port 80 and host 192.168.0.5
22:13:49.947032 IP 192.168.0.5.55237 > 192.168.0.254.http: S 2412448495:2412448495(0) win 65535 <mss 1460,nop,wscale 3,nop,nop,timestamp 59097693 0,sackOK,eol>
22:13:49.948596 IP 192.168.0.254.http > 192.168.0.5.55237: S 1060219761:1060219761(0) ack 2412448496 win 5792 <mss 1460,sackOK,timestamp 1644563 59097693,nop,wscale 1>
22:13:49.949461 IP 192.168.0.5.55237 > 192.168.0.254.http: . ack 1 win 65535 <nop,nop,timestamp 59097694 1644563>

Webサーバ 1

% sudo tcpdump  -n -i eth0 port 80 and host 192.168.0.5
22:09:27.393926 IP 192.168.0.5.55237 > 192.168.0.254.http: S 2412448495:2412448495(0) win 65535 <mss 1460,nop,wscale 3,nop,nop,timestamp 59097693 0,sackOK,eol>
22:09:27.395207 IP 192.168.0.254.http > 192.168.0.5.55237: S 1060219761:1060219761(0) ack 2412448496 win 5792 <mss 1460,sackOK,timestamp 1644563 59097693,nop,wscale 1>
22:09:27.396923 IP 192.168.0.5.55237 > 192.168.0.254.http: . ack 1 win 65535 <nop,nop,timestamp 59097694 1644563>

Webサーバ 2

% sudo tcpdump  -n -i eth0 port 80 and host 192.168.0.5
22:13:52.714886 IP 192.168.0.5.55237 > 192.168.0.254.http: S 2412448495:2412448495(0) win 65535 <mss 1460,nop,wscale 3,nop,nop,timestamp 59097693 0,sackOK,eol>
22:13:52.715068 IP 192.168.0.254.http > 192.168.0.5.55237: S 1060219761:1060219761(0) ack 2412448496 win 5792 <mss 1460,sackOK,timestamp 1644563 59097693,nop,wscale 1>
22:13:52.717999 IP 192.168.0.5.55237 > 192.168.0.254.http: . ack 1 win 65535 <nop,nop,timestamp 59097694 1644563>

クライアントからロードバランサに送られた 192.168.0.254 宛のパケットのアドレスが変換されずに Webサーバに届いていることがわかる。

おしまい。

参考

ほとんどここの真似をしました。勉強になります。
高トラフィックに対応できるLinuxロードバランサを目指して 〜 LVSをNATからDSRへ