対象サーバについて
製品名 | OpenBlockS 600 |
OS(kernel ver) | Debian lenny(2.6.29) |
CPU | 600MHz(AMCC PowerPC 405EX) |
メモリ | 1GB(DDR2 SDRAM) |
ストレージ | 8GB(Compact Flash) |
はじめに
こんなに簡単! Linuxでロードバランサを参考にさせて頂きながら、IPVSを使用してOpenblocks600をロードバランサにするための設定を記載していきます。
まずはIPVSとipvsadmについて取り上げますが、上記サイトにも詳しく説明がある通り、IPVSだけでは特定のリアルサーバが落ちた際にロードバランスの割り当てからはずすしたり、ロードバランサ自体を冗長化させたりはできませんので、別途keepalivedを導入する必要があります。
一度に書いてしまうと長くなってしまいますので、上記サイトと同じく、1.IPVS(本記事)、2.keepalivedでリアルサーバの障害検出、3.keepalivedでロードバランサの冗長化、の流れで試していきたいと思います。
IPVS及びipvsadmの導入
IPVSのロード
IPVSはカーネルモジュールとして提供されていますので、IPVSをサポートしたカーネルをビルドする必要がありますが、Openblocks600のカーネルはすでにIPVSをサポートしていました。早速カーネルモジュールをロードしてIPVSのバージョンを調べます。
obs-act:/usr/src# modprobe ip_vs_rr obs-act:/usr/src# obs-act:/usr/src# lsmod | grep ip_vs_rr ip_vs_rr 1656 0 ip_vs 98596 2 ip_vs_rr obs-act:/lib/modules/2.6.29/kernel/net/ipv6# vi /etc/modules # /etc/modules: kernel modules to load at boot time. # # This file contains the names of kernel modules that should be loaded # at boot time, one per line. Lines beginning with "#" are ignored. # Parameters can be specified after the module name. bonding 8021q ip_vs_rr ~ obs-act:/usr/src# cat /proc/net/ip_vs IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn
カーネルモジュールのIPVS versionは1.2.1でした。
ipvsadmのインストール
ipvsadmはIPVSを使用するためのコマンドラインツールで、仮想サーバやリアルサーバの設定を行ったり、設定・接続状況などが確認できます。
obs-act:/usr/src# aptitude install ipvsadm パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 拡張状態情報を読み込んでいます パッケージの状態を初期化しています... 完了 タスクの記述を読み込んでいます... 完了 以下の新規パッケージがインストールされます: ipvsadm 更新: 0 個、新規インストール: 1 個、削除: 0 個、保留: 0 個。 39.8kB のアーカイブを取得する必要があります。展開後に 180kB のディスク領域が新たに消費されます。 拡張状態情報を書き込んでいます... 完了 取得:1 http://ftp.jp.debian.org lenny/main ipvsadm 1:1.24-2.1 [39.8kB] 39.8kB を 1s 秒でダウンロードしました (38.6kB/s) パッケージを事前設定しています ... 未選択パッケージ ipvsadm を選択しています。 (データベースを読み込んでいます ... 現在 17029 個のファイルとディレクトリがインストールされています。) (.../ipvsadm_1%3a1.24-2.1_powerpc.deb から) ipvsadm を展開しています... man-db のトリガを処理しています ... ipvsadm (1:1.24-2.1) を設定しています ... ipvsadm is not configured to run. Please run dpkg-reconfigure ipvsadm. パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 拡張状態情報を読み込んでいます パッケージの状態を初期化しています... 完了 拡張状態情報を書き込んでいます... 完了 タスクの記述を読み込んでいます... 完了 obs-act:/usr/src# ipvsadm --version ipvsadm v1.24 2005/12/10 (compiled with popt and IPVS v1.2.0)
ipvsadmはカーネルモジュールのIPVSとバージョンをそろえる必要がありますが、Openblocks600のdebian付属のipvsadmは1.2.0でカーネルモジュールのバージョンと差分が生じてしまいました。
ipvsadmパッケージのアンインストール
obs-act:/lib/modules/2.6.29/kernel/net/ipv6# aptitude remove ipvsadm パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 拡張状態情報を読み込んでいます パッケージの状態を初期化しています... 完了 タスクの記述を読み込んでいます... 完了 以下のパッケージが削除されます: ipvsadm 更新: 0 個、新規インストール: 0 個、削除: 1 個、保留: 0 個。 0B のアーカイブを取得する必要があります。展開後に 180kB のディスク領域が解放されます。 拡張状態情報を書き込んでいます... 完了 (データベースを読み込んでいます ... 現在 17044 個のファイルとディレクトリがインストールされています。) ipvsadm を削除しています ... ipvsadm is not configured to run. Please run dpkg-reconfigure ipvsadm. man-db のトリガを処理しています ... パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 拡張状態情報を読み込んでいます パッケージの状態を初期化しています... 完了 拡張状態情報を書き込んでいます... 完了 タスクの記述を読み込んでいます... 完了
ipvsadm 1.2.1をソースからビルド
ipvsadm1.2.1をダウンロードしてソースからビルドします。
obs-act:/usr/src# wget http://www.linux-vs.org/software/kernel-2.6/ipvsadm-1.26.tar.gz --2011-05-10 23:04:35-- http://www.linux-vs.org/software/kernel-2.6/ipvsadm-1.26.tar.gz www.linux-vs.org をDNSに問いあわせています... 69.56.251.119, 2001:470:1f0f:297::2 www.linux-vs.org|69.56.251.119|:80 に接続しています... 接続しました。 HTTP による接続要求を送信しました、応答を待っています... 200 OK 長さ: 41700 (41K) [application/x-gzip] `ipvsadm-1.26.tar.gz' に保存中 100%[===============================================================================>] 41,700 90.8K/s 時間 0.4s 2011-05-10 23:04:36 (90.8 KB/s) - `ipvsadm-1.26.tar.gz' へ保存完了 [41700/41700] obs-act:/usr/src# tar zxf ipvsadm-1.26.tar.gz obs-act:/usr/src# cd ipvsadm-1.26 obs-act:/usr/src/ipvsadm-1.26# ls Makefile SCHEDULERS config_stream.h dynamic_array.c ipvsadm-restore.8 ipvsadm.8 ipvsadm.spec PERSISTENCE_ENGINES VERSION contrib dynamic_array.h ipvsadm-save ipvsadm.c ipvsadm.spec.in README config_stream.c debian ipvsadm-restore ipvsadm-save.8 ipvsadm.sh libipvs obs-act:/usr/src/ipvsadm-1.26# make make -C libipvs make[1]: ディレクトリ `/usr/src/ipvsadm-1.26/libipvs' に入ります gcc -Wall -Wunused -Wstrict-prototypes -g -fPIC -DLIBIPVS_USE_NL -DHAVE_NET_IP_VS_H -c -o libipvs.o libipvs.c In file included from libipvs.h:13, from libipvs.c:23: ip_vs.h:15:29: error: netlink/netlink.h: そのようなファイルやディレクトリはありません ip_vs.h:16:31: error: netlink/genl/genl.h: そのようなファイルやディレクトリはありません ip_vs.h:17:31: error: netlink/genl/ctrl.h: そのようなファイルやディレクトリはありません In file included from libipvs.h:13, from libipvs.c:23: ip_vs.h:520: error: array type has incomplete element type ip_vs.h:521: error: array type has incomplete element type ip_vs.h:522: error: array type has incomplete element type ip_vs.h:523: error: array type has incomplete element type ip_vs.h:524: error: array type has incomplete element type ip_vs.h:525: error: array type has incomplete element type libipvs.c: In function ‘ipvs_nl_message’: libipvs.c:57: warning: implicit declaration of function ‘nlmsg_alloc’ libipvs.c:57: warning: assignment makes pointer from integer without a cast libipvs.c:61: warning: implicit declaration of function ‘genlmsg_put’ libipvs.c:61: error: ‘NL_AUTO_PID’ undeclared (first use in this function) libipvs.c:61: error: (Each undeclared identifier is reported only once libipvs.c:61: error: for each function it appears in.) libipvs.c:61: error: ‘NL_AUTO_SEQ’ undeclared (first use in this function) libipvs.c: In function ‘ipvs_nl_noop_cb’: libipvs.c:69: error: ‘NL_OK’ undeclared (first use in this function) libipvs.c:70: warning: control reaches end of non-void function libipvs.c: At top level: libipvs.c:72: error: expected declaration specifiers or ‘...’ before ‘nl_recvmsg_msg_cb_t’ libipvs.c: In function ‘ipvs_nl_send_message’: libipvs.c:76: warning: implicit declaration of function ‘nl_handle_alloc’ libipvs.c:76: warning: assignment makes pointer from integer without a cast libipvs.c:78: warning: implicit declaration of function ‘nlmsg_free’ libipvs.c:82: warning: implicit declaration of function ‘genl_connect’ libipvs.c:85: warning: implicit declaration of function ‘genl_ctrl_resolve’ libipvs.c:91: warning: implicit declaration of function ‘nl_handle_destroy’ libipvs.c:96: warning: implicit declaration of function ‘nl_socket_modify_cb’ libipvs.c:96: error: ‘NL_CB_VALID’ undeclared (first use in this function) libipvs.c:96: error: ‘NL_CB_CUSTOM’ undeclared (first use in this function) libipvs.c:96: error: ‘func’ undeclared (first use in this function) libipvs.c:99: warning: implicit declaration of function ‘nl_send_auto_complete’ libipvs.c:102: warning: implicit declaration of function ‘nl_recvmsgs_default’ libipvs.c: In function ‘ipvs_init’: libipvs.c:127: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_getinfo_parse_cb’: libipvs.c:149: warning: implicit declaration of function ‘nlmsg_hdr’ libipvs.c:149: warning: initialization makes pointer from integer without a cast libipvs.c:152: warning: implicit declaration of function ‘genlmsg_parse’ libipvs.c:159: warning: implicit declaration of function ‘nla_get_u32’ libipvs.c:162: error: ‘NL_OK’ undeclared (first use in this function) libipvs.c:163: warning: control reaches end of non-void function libipvs.c: In function ‘ipvs_getinfo’: libipvs.c:176: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_flush’: libipvs.c:199: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_nl_fill_service_attr’: libipvs.c:215: warning: implicit declaration of function ‘nla_nest_start’ libipvs.c:215: warning: assignment makes pointer from integer without a cast libipvs.c:219: warning: implicit declaration of function ‘NLA_PUT_U16’ libipvs.c:222: warning: implicit declaration of function ‘NLA_PUT_U32’ libipvs.c:225: warning: implicit declaration of function ‘NLA_PUT’ libipvs.c:229: warning: implicit declaration of function ‘NLA_PUT_STRING’ libipvs.c:236: warning: implicit declaration of function ‘nla_nest_end’ libipvs.c:239: warning: label ‘nla_put_failure’ defined but not used libipvs.c: In function ‘ipvs_add_service’: libipvs.c:255: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_update_service’: libipvs.c:276: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_del_service’: libipvs.c:296: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_zero_service’: libipvs.c:321: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_nl_fill_dest_attr’: libipvs.c:334: warning: assignment makes pointer from integer without a cast libipvs.c:348: warning: label ‘nla_put_failure’ defined but not used libipvs.c: In function ‘ipvs_add_dest’: libipvs.c:366: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_update_dest’: libipvs.c:396: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_del_dest’: libipvs.c:425: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_set_timeout’: libipvs.c:452: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c:454: warning: label ‘nla_put_failure’ defined but not used libipvs.c: In function ‘ipvs_start_daemon’: libipvs.c:473: warning: assignment makes pointer from integer without a cast libipvs.c:483: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_stop_daemon’: libipvs.c:504: warning: assignment makes pointer from integer without a cast libipvs.c:514: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: At top level: libipvs.c:526: warning: ‘struct nlattr’ declared inside parameter list libipvs.c:526: warning: its scope is only this definition or declaration, which is probably not what you want libipvs.c: In function ‘ipvs_parse_stats’: libipvs.c:530: warning: implicit declaration of function ‘nla_parse_nested’ libipvs.c:548: warning: implicit declaration of function ‘nla_get_u64’ libipvs.c: In function ‘ipvs_services_parse_cb’: libipvs.c:562: warning: initialization makes pointer from integer without a cast libipvs.c:592: warning: implicit declaration of function ‘nla_get_u16’ libipvs.c:598: warning: implicit declaration of function ‘nla_data’ libipvs.c:599: warning: passing argument 2 of ‘memcpy’ makes pointer from integer without a cast libipvs.c:604: warning: implicit declaration of function ‘nla_get_string’ libipvs.c:605: warning: passing argument 2 of ‘strncpy’ makes pointer from integer without a cast libipvs.c:610: warning: passing argument 2 of ‘strncpy’ makes pointer from integer without a cast libipvs.c:614: warning: implicit declaration of function ‘nla_memcpy’ libipvs.c:618: warning: passing argument 2 of ‘ipvs_parse_stats’ from incompatible pointer type libipvs.c: In function ‘ipvs_get_services’: libipvs.c:649: error: ‘NLM_F_DUMP’ undeclared (first use in this function) libipvs.c:650: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_dests_parse_cb’: libipvs.c:728: warning: initialization makes pointer from integer without a cast libipvs.c:759: warning: passing argument 2 of ‘memcpy’ makes pointer from integer without a cast libipvs.c:771: warning: passing argument 2 of ‘ipvs_parse_stats’ from incompatible pointer type libipvs.c: In function ‘ipvs_get_dests’: libipvs.c:809: error: ‘NLM_F_DUMP’ undeclared (first use in this function) libipvs.c:813: warning: assignment makes pointer from integer without a cast libipvs.c:829: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_get_service’: libipvs.c:939: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_timeout_parse_cb’: libipvs.c:972: warning: initialization makes pointer from integer without a cast libipvs.c:986: error: ‘NL_OK’ undeclared (first use in this function) libipvs.c:987: warning: control reaches end of non-void function libipvs.c: In function ‘ipvs_get_timeout’: libipvs.c:1005: error: too many arguments to function ‘ipvs_nl_send_message’ libipvs.c: In function ‘ipvs_daemon_parse_cb’: libipvs.c:1023: warning: initialization makes pointer from integer without a cast libipvs.c:1048: warning: passing argument 2 of ‘strncpy’ makes pointer from integer without a cast libipvs.c:1051: error: ‘NL_OK’ undeclared (first use in this function) libipvs.c:1052: warning: control reaches end of non-void function libipvs.c: In function ‘ipvs_get_daemon’: libipvs.c:1071: error: ‘NLM_F_DUMP’ undeclared (first use in this function) libipvs.c:1072: error: too many arguments to function ‘ipvs_nl_send_message’ make[1]: *** [libipvs.o] エラー 1 make[1]: ディレクトリ `/usr/src/ipvsadm-1.26/libipvs' から出ます make: *** [libs] エラー 2
エラーが出て失敗しました。
類似事象を探してみたところ、海外のサイトに同じエラーが紹介されていました。
コンパイラがカーネルソースを見つけられないためにエラーが発生しているようです。
Openblocks600内にカーネルソースが見当たらなかったためkernelを落としてきてシンボリックリンクをはります。
再コンパイル
obs-act:/usr/src# aptitude install linux-source-2.6.26 obs-act:/usr/src# tar xvf linux-source-2.6.26.tar.bz2 obs-act:/usr/src# ln -s /usr/src/linux-source-2.6.26 /usr/src/linux obs-act:/usr/src# ls -al 合計 48300 drwxrwsr-x 3 root src 4096 2011-05-11 01:09 . drwxr-xr-x 13 root root 4096 2011-04-03 22:27 .. lrwxrwxrwx 1 root src 28 2011-05-11 01:09 linux -> /usr/src/linux-source-2.6.26 drwxr-xr-x 21 root root 4096 2011-01-25 14:55 linux-source-2.6.26 -rw-r--r-- 1 root root 49391360 2011-01-25 15:35 linux-source-2.6.26.tar.bz2 obs-act:/usr/src# wget http://www.linuxvirtualserver.org/software/kernel-2.6/ipvsadm-1.24.tar.gz obs-act:/usr/src# tar xvf ipvsadm-1.24.tar.gz obs-act:/usr/src# cd ipvsadm-1.24 obs-act:/usr/src/ipvsadm-1.24# make
今度はエラーが出なかったので、インストール作業を続けます。
obs-act:/usr/src/ipvsadm-1.24# make install obs-act:/usr/src/ipvsadm-1.24# ipvsadm -v ipvsadm v1.24 2005/12/10 (compiled with getopt_long and IPVS v1.2.1)
ipvsadmのバージョンがめでたく1.2.1になりました。
IPフォーワードの有効化
ロードバランサの前に、特定のポートから別のポートへの転送機能をONにする必要があるため、IPフォーワード機能の有効化を行います。
obs-act:~# cat /proc/sys/net/ipv4/ip_forward 0
デフォルトではIPフォーワード機能は無効になっています。
obs-act:~# vi /etc/sysctl.conf ... # Uncomment the next line to enable packet forwarding for IPv4 net.ipv4.ip_forward=1 ... "/etc/sysctl.conf" 67 lines, 2274 characters written
net.ipv4.ip_forwardを1にします。
obs-act:~# sysctl -p net.ipv4.ip_forward = 1
/etc/sysctl.confファイルを読み込みました。
obs-act:~# cat /proc/sys/net/ipv4/ip_forward 1
IPフォーワードが有効化されました。
IPVSの動作試験
ネットワーク構成について
下図のようなネットワークを構築して実験します。
左が物理的な接続を表し、右が論理的な接続を表しています。
ラウンドロビン動作確認用のクライアントとしてはWindowsにインストールしたcURLを利用します。
Openblocks600はBondingでL2SWと接続されているため、VIPを作成するセグメント(192.168.0.0/24)とリアルサーバを収容するセグメント(172.16.0.0/24)をvlanで分離します。
VIP設定
ユーザがWebアクセスする際に利用するVIPを手動で振ります。
OBS-ACT:~# /etc/init.d/networking stop OBS-ACT:~# vi /etc/network/interfaces ... auto bond0.2:100 iface bond0.2:100 inet static address 192.168.0.151 netmask 255.255.255.0 network 192.168.0.0 broadcast 192.168.0.255 gateway 192.168.0.1 vlan-raw-device bond0 OBS-ACT:~# /etc/init.d/networking start OBS-ACT:~# ip addr show ... 5: bond0.2@bond0:mtu 1500 qdisc noqueue state UP link/ether 00:0a:85:04:02:ff brd ff:ff:ff:ff:ff:ff inet 192.168.0.150/24 brd 192.168.0.255 scope global bond0.2 inet 192.168.0.151/24 brd 192.168.0.255 scope global secondary bond0.2:100 inet6 fe80::20a:85ff:fe04:2ff/64 scope link valid_lft forever preferred_lft forever ...
IPアドレスが二つ振られていることを確認します。
ipvsadmによるIPVSの設定
設定をリセットします。
OBS-ACT:~# ipvsadm -C
状態確認します。
OBS-ACT:~# ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn
何も登録されていないことを確認します。
OBS-ACT:~# ipvsadm -A -t 192.168.0.151:80 -s rr
VIPを追加します。ポート80、ラウンドロビン(rr)でリアルサーバにバランスさせます。
OBS-ACT:~# ipvsadm -a -t 192.168.0.151:80 -r 172.16.0.2 -m OBS-ACT:~# ipvsadm -a -t 192.168.0.151:80 -r 172.16.0.3 -m
リアルサーバのIPアドレスを追加します。
パケット転送方式にはNAT(-m)を選択します。
OBS-ACT:~# 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.151:80 rr -> 172.16.0.3:80 Masq 1 0 0 -> 172.16.0.2:80 Masq 1 0 0
登録されていることを確認します。
※keepalivedを起動させる際には一度設定をクリアする必要があります。
リアルサーバ側の設定
両リアルサーバのDocumentRootにホスト名だけ記載したhtmlファイルを用意して、リアルサーバ1にパス指定無しでhttpアクセスするとDellと返し、リアルサーバ2にアクセスするとHitachiと返却するように設定します。
クライアントからcurlにてアクセス
クライアントはサーバ台数もありWindowsにcURLを入れました。
YUU BLOGさんのサイトを参考にさせて頂きました。
C:\Users\abc>curl 192.168.0.151 Hitachi C:\Users\abc>curl 192.168.0.151 Dell C:\Users\abc>curl 192.168.0.151 Hitachi C:\Users\abc>curl 192.168.0.151 Dell
ラウンドロビンしました。
NAT動作確認
Openblocksのbond0.2、DellとHitachiのeth0.10でtcpdumpをまわしながら、curlでVIPにアクセスします。
クライアント
C:\Users\abc>curl 192.168.0.151 Hitachi C:\Users\abc>curl 192.168.0.151 Dell
Openblocks600
OBS-ACT:~# tcpdump -i bond0.2 port www tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on bond0.2, link-type EN10MB (Ethernet), capture size 96 bytes 18:59:11.878754 IP 192.168.0.7.53925 > 192.168.0.151.www: S 3573158802:3573158802(0) win 819218:59:11.878957 IP 192.168.0.151.www > 192.168.0.7.53925: S 1108100247:1108100247(0) ack 3573158803 win 5840 18:59:11.879229 IP 192.168.0.7.53925 > 192.168.0.151.www: . ack 1 win 64240 18:59:11.879369 IP 192.168.0.7.53925 > 192.168.0.151.www: P 1:137(136) ack 1 win 64240 18:59:11.879761 IP 192.168.0.151.www > 192.168.0.7.53925: . ack 137 win 6432 18:59:11.880843 IP 192.168.0.151.www > 192.168.0.7.53925: P 1:262(261) ack 137 win 6432 18:59:11.886597 IP 192.168.0.7.53925 > 192.168.0.151.www: F 137:137(0) ack 262 win 63979 18:59:11.887060 IP 192.168.0.151.www > 192.168.0.7.53925: F 262:262(0) ack 138 win 6432 18:59:11.887294 IP 192.168.0.7.53925 > 192.168.0.151.www: . ack 263 win 63979 18:59:17.488190 IP 192.168.0.7.53950 > 192.168.0.151.www: S 2921444013:2921444013(0) win 8192 18:59:17.488521 IP 192.168.0.151.www > 192.168.0.7.53950: S 3572830156:3572830156(0) ack 2921444014 win 5840 18:59:17.489837 IP 192.168.0.7.53950 > 192.168.0.151.www: . ack 1 win 64240 18:59:17.490022 IP 192.168.0.7.53950 > 192.168.0.151.www: P 1:137(136) ack 1 win 64240 18:59:17.490341 IP 192.168.0.151.www > 192.168.0.7.53950: . ack 137 win 6432 18:59:17.490651 IP 192.168.0.151.www > 192.168.0.7.53950: P 1:245(244) ack 137 win 6432 18:59:17.496756 IP 192.168.0.7.53950 > 192.168.0.151.www: F 137:137(0) ack 245 win 63996 18:59:17.497085 IP 192.168.0.151.www > 192.168.0.7.53950: F 245:245(0) ack 138 win 6432 18:59:17.498953 IP 192.168.0.7.53950 > 192.168.0.151.www: . ack 246 win 63996 ^C 18 packets captured 18 packets received by filter 0 packets dropped by kernel
192.168.0.7(クライアント)と192.168.0.151(VIP)の間で通信が行われています。
リアルサーバ1(Dell)
dell:~# tcpdump -i eth0.10 port www tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0.10, link-type EN10MB (Ethernet), capture size 96 bytes 18:59:17.993340 IP 192.168.0.7.53950 > 172.16.0.2.www: S 2921444013:2921444013(0) win 819218:59:18.006360 IP 172.16.0.2.www > 192.168.0.7.53950: S 3572830156:3572830156(0) ack 2921444014 win 5840 18:59:17.994918 IP 192.168.0.7.53950 > 172.16.0.2.www: . ack 1 win 64240 18:59:17.995101 IP 192.168.0.7.53950 > 172.16.0.2.www: P 1:137(136) ack 1 win 64240 18:59:17.995121 IP 172.16.0.2.www > 192.168.0.7.53950: . ack 137 win 6432 18:59:17.995402 IP 172.16.0.2.www > 192.168.0.7.53950: P 1:245(244) ack 137 win 6432 18:59:18.001833 IP 192.168.0.7.53950 > 172.16.0.2.www: F 137:137(0) ack 245 win 63996 18:59:18.001866 IP 172.16.0.2.www > 192.168.0.7.53950: F 245:245(0) ack 138 win 6432 18:59:18.004070 IP 192.168.0.7.53950 > 172.16.0.2.www: . ack 246 win 63996 ^C 9 packets captured 9 packets received by filter 0 packets dropped by kernel
192.168.0.7(クライアント)と172.16.0.2(リアルサーバ1)の間で通信が行われています。
リアルサーバ2(Hitachi)
hitachi:~# tcpdump -i eth0.10 port www tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0.10, link-type EN10MB (Ethernet), capture size 96 bytes 18:52:07.575499 IP 192.168.0.7.53925 > 172.16.0.3.www: S 3573158802:3573158802(0) win 819218:52:07.598416 IP 172.16.0.3.www > 192.168.0.7.53925: S 1108100247:1108100247(0) ack 3573158803 win 5840 18:52:07.576003 IP 192.168.0.7.53925 > 172.16.0.3.www: . ack 1 win 64240 18:52:07.576141 IP 192.168.0.7.53925 > 172.16.0.3.www: P 1:137(136) ack 1 win 64240 18:52:07.576244 IP 172.16.0.3.www > 192.168.0.7.53925: . ack 137 win 6432 18:52:07.577248 IP 172.16.0.3.www > 192.168.0.7.53925: P 1:262(261) ack 137 win 6432 18:52:07.583370 IP 192.168.0.7.53925 > 172.16.0.3.www: F 137:137(0) ack 262 win 63979 18:52:07.583518 IP 172.16.0.3.www > 192.168.0.7.53925: F 262:262(0) ack 138 win 6432 18:52:07.584017 IP 192.168.0.7.53925 > 172.16.0.3.www: . ack 263 win 63979 ^C 9 packets captured 9 packets received by filter 0 packets dropped by kernel
192.168.0.7(クライアント)と172.16.0.3(リアルサーバ2)の間で通信が行われています。
上記の結果から、クライアントからVIP宛の通信は、宛先をリアルサーバのIPに書き換えてIPフォーワードしていることが分かります。
また、リアルサーバからクライアントへの戻り通信は、送信元をリアルサーバからVIPに書き換えていることが分かります。
リアルサーバ障害時の動作
リアルサーバ2(Hitachi)側のApacheを落として動作を確認します。
Hitachi
hitachi:~# /etc/init.d/apache2 stop
リアルサーバ2を落とした後にクライアントからアクセスします。
クライアント
C:\Users\abc>curl 192.168.0.151 curl: (7) couldn't connect to host C:\Users\abc>curl 192.168.0.151 Dell C:\Users\abc>curl 192.168.0.151 curl: (7) couldn't connect to host C:\Users\abc>curl 192.168.0.151 Dell
2回に1回、接続NGになってしまいます。
リアルサーバの障害時は自動的に迂回するようにするためにはkeepalivedが必要ですが、weightをいじることで、手動で計画的にリアルサーバをラウンドロビンの対象からはずすことは可能です。
一度リアルサーバ2のApacheプロセスを上げてから動作を確認してみます。
リアルサーバ2
hitachi:~# /etc/init.d/apache2 start
Openblocks600
OBS-ACT:~# ipvsadm -e -t 192.168.0.151:80 -r 172.16.0.3 -m -w 0 OBS-ACT:~# 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.151:80 rr -> 172.16.0.3:80 Masq 0 0 4 -> 172.16.0.2:80 Masq 1 0 8
172.16.0.3のWeightが0になっていることを確認して、クライアントからcurlを実行します。
クライアント
C:\Users\abc>curl 192.168.0.151 Dell C:\Users\abc>curl 192.168.0.151 Dell C:\Users\abc>curl 192.168.0.151 Dell C:\Users\abc>curl 192.168.0.151 Dell
アクセスが無事、リアルサーバ1に偏りました。
元に戻して再度確認します。
Openblocks600
OBS-ACT:~# ipvsadm -e -t 192.168.0.151:80 -r 172.16.0.3 -m -w 1 OBS-ACT:~# 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.151:80 rr -> 172.16.0.3:80 Masq 1 0 0 -> 172.16.0.2:80 Masq 1 0 0
クライアント
C:\Users\abc>curl 192.168.0.151 Hitachi C:\Users\abc>curl 192.168.0.151 Dell C:\Users\abc>curl 192.168.0.151 Hitachi C:\Users\abc>curl 192.168.0.151 Dell
ラウンドロビン動作に戻りました。
IPVSを使用してOpenblocks600をロードバランサ化しましたが、このままでは障害中のリアルサーバにもアクセスを割り当ててしまいます。そこで次回の記事(keepalived(1.2.1)の導入)では、keepalivedを導入することでリアルサーバのサービス監視を行い、リアルサーバに障害が起きた際には自動的にロードバランス先からはずせるようにします。