勉強がてらubuntuでlvsを構築してみたので手順やハマったところをメモ
実験用の環境はvagrantで構築
nodeをたくさん立てる必要があるためdocker使ってメモリ節約したかったけど
dockerだと通信周りの設定でハマりそう&その部分は今回の趣旨と違うため次のステップとしとく
構築したい環境はこんな感じ
name | ip:port | vip:port | 備考 |
---|---|---|---|
lb0 | 192.168.0.11:80 | 192.168.0.2:80 | IPVS |
web0 | 192.168.0.3:80 | real server 1 (nginx) | |
web1 | 192.168.0.4:80 | real server 2 (nginx) | |
cli0 | 192.168.0.100 | アクセス確認用クライアント |
今回はDRで設定することにする
(lbにて振り分けたパケットが送信元へ返る際、lbは通らずに直接送信元へ返る)
lb0設定
virtual ipを設定する
$ sudo ip addr add 192.168.0.2/32 dev eth1 label eth1:0 # 確認 $ sudo ip addr
ipvsadmを入れる
$ sudo apt-get install ipvsadm
ipvsadmはlinux kernelに含まれるIPVSという機能を利用してアクセス振り分けを設定するためのツール。設定は意外と単純でわかりやすい。
設定はコマンドでinteractiveに行うこともできるが今回はファイルに残すことにする
ipvsadm.rulesというファイル名にしておく
$ vi ipvsadm.rules -C -A -t 192.168.0.2:80 -s rr -a -t 192.168.0.2:80 -r 192.168.0.3:80 -g -a -t 192.168.0.2:80 -r 192.168.0.4:80 -g $ sudo ipvsadm --restore < ipvsadm.rules # 確認 $ sudo ipvsadm IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 192.168.0.2:80 wlc -> 192.168.0.3:80 Route 1 0 0 -> 192.168.0.4:80 Route 1 0 0
まず-Aで振り分けたいアクセスを指定
-s rrでラウンドロビンによる振り分けになる
-aで上記のアクセスの振り分け先を追加する
-gとすることでDRによる転送を行う
real server設定(web0で説明)
まずnginxを入れて設定
$ sudo apt-get install nginx $ echo "web0" | sudo tee /usr/share/nginx/html/index # 確認 $ curl http://192.168.0.3 web0
192.168.0.2宛のアクセスを受け入れるための設定
/etc/network/interfacesに以下の設定を追記
auto lo:0 iface lo:0 inet static address 192.168.0.2 netmask 255.255.255.255
設定を反映
$ sudo ifup lo:0 # 確認 $ ip addr
192.168.0.2に対するarpのリクエストに返答しないよう設定
/etc/sysctl.confに以下を追記
net.ipv4.conf.all.arp_ignore = 1 net.ipv4.conf.all.arp_announce = 2
設定を反映
$ sudo sysctl -p
確認
cli0からlb0のvipにアクセスしてweb0とweb1が交互に帰ってくればOK
$ while true; do curl http://192.168.0.2; sleep 1; done web0 web1 web0 ...
卜ラブルシューティング
最後の確認時に想定した応答が返ってこない場合のチェックポイント
lb0からreal serverへhttpアクセスできるか
lb0にてcurlを使って正しい応答が返ってくるか確認
$ curl http://192.168.0.3 web0 $ curl http://192.168.0.4 web1
返ってこない場合はreal serverにてnginxのプロセスが起動しているか確認
cli0からのアクセスがlb0を経由しているか
real server側での設定がうまくいっていないとcli0から直接web0などにアクセスがいってしまう。
cli0にて以下を確認
cli0 $ arp -a ? (192.168.0.3) at 08:00:27:98:d7:cd [ether] on eth1 ? (192.168.0.4) at 08:00:27:d1:3c:2e [ether] on eth1 ? (192.168.0.11) at 08:00:27:85:8a:96 [ether] on eth1 ? (10.0.2.2) at 52:54:00:12:35:02 [ether] on eth0 ? (10.0.2.3) at 52:54:00:12:35:03 [ether] on eth0 ? (192.168.0.2) at 08:00:27:85:8a:96 [ether] on eth1
ここでvip(192.168.0.2)とreal serverのipに紐づくmacアドレスが一致している場合がある。real server側でarpに応答しない設定を入れたが
- うまく設定できていない場合
- 設定前にcli0からvipへのアクセスを行っていた場合
にvipに対するmacアドレスがreal serverのもので設定されてしまう。その場合はarpのキャッシュを消す
$ sudo arp -d 192.168.0.2 # 消えたこと確認 $ sudo arp -a | grep "0.2" ? (192.168.0.2) at <incomplete> on eth1
この状態でreal serverのarpに応答しない設定を入れて再度curlでアクセス
それぞれのipアドレスに対して正しいmacアドレスが設定されていればOK
正しいmacアドレスは各サーバにてip addrとすることで確認できる
web0, web1が192.168.0.2へのパケットに応答しているか
lo:0へ192.168.0.2を割り当てる設定がうまくいっていない場合、アクセスは来るが応答はしない状態になる。これを確認するにはtcpdumpを用いる。
例えばweb0にて
$ sudo tcpdump net 192.168.0.0/24 -i eth1 -n
これでcli0からcurlで192.168.0.2へアクセスすると、web0へアクセスが振られた場合にログが出てくるはず。例えばこんなの
04:56:31.674022 IP 192.168.0.100.50853 > 192.168.0.3.80: Flags [S], seq 4034527911, win 29200, options [mss 1460,sackOK,TS val 235469 ecr 0,nop,wscale 5], length 0
見るのはここだけでOK
192.168.0.100.50853 > 192.168.0.3.80: Flags [S]
これはsynパケットなので、応答が返る場合にはこの直後に以下のようなログが出てackが返るはず
192.168.0.3:80 > 192.168.0.100.50853: Flags [S.]
lo:0の設定がうまくいっていない場合、synパケットが自分宛だと認識できないため捨ててしまい、それに対する応答は当然返さない。その場合はsynパケットが2回くらい続いてから接続が切断されているはず(自分のところではそうだった)
lo:0が正しく設定されているかは各real serverにてip addrしてみて設定が入っているか確認する。また、/etc/network/interfacesへの設定が間違っていないかなど確認する(書式とか)
サーバのipアドレスに192.168.0.1を使っている
今回の趣旨から外れるところだが、自分が一番ハマったのはこれ。
vagrant環境ではvagrant host(自分のPC)のアドレスとして.1が設定される。PC側の設定を見ると例えばこんな感じになっている
host$ ifconfig vboxnet4: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> ether 0a:00:27:00:00:04 inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.0.255
そのため、192.168.0.1を別のサーバのipアドレスに設定していた場合は衝突してうまく通信ができなくなる。自分はlb0のアドレスとして最初にこれを設定していてハマった。このときはcli0でのarpキャッシュにて、192.168.0.1と192.168.0.2が異なっていることでなんとか気づけた。
だがその後よく見ると、vagrant up時に「.1となるアドレスは衝突するため設定するな」というwarningが出ていた。。