「Linux Virtual Server」と「Keepalived」で作る冗長化ロードバランサ
Keepalivedを使ったサーバーの監視
以上の設定を行うことで、仮想サービスとして定義したIPアドレスおよびポート宛てのリクエストをサーバーに転送し、負荷分散を行う環境を構築できる。しかし、この場合サーバーが何らかの原因でサービスを提供できなくなっても、そのサーバーにはリクエストが転送される可能性がある。つまり、サービスの冗長化は厳密には行えていない。そこで、続いてはKeepalivedを使ってサービスの稼働状態を監視し、サービスが停止しているサーバーに対してはリクエストの転送を行わない、という設定を行ってみよう。
Keepalivedは以下のような機能を持つルーティング管理ソフトウェアだ。
- パケット転送先サービスの死活監視
- LVS自体の死活監視
- LVS設定の動的変更
Keepalivedは、大きく分けて2つの目的で利用される。まず一つは、サービスの稼働状況に応じてロードバランサの設定を変更し、停止しているサービスに対してリクエストが振り分けられないようにすることだ。これは、KeepalivedがLVSの設定を監視結果に応じて動的に変更することで実現される。そしてもう一つは、ロードバランサ自体の冗長化だ。ロードバランサが1台しかない場合、ロードバランサ自体に障害が発生するとリクエストの振り分け先となるサービスが稼働していたとしてもリクエストを処理できなくなる。そのため、冗長性をより向上させたい場合はロードバランサを複数用意した構成を取るのが一般的だ。この場合、1つのロードバランサが停止した場合は別のロードバランサがその処理を肩代わりすることでサービスを継続させることができる。
以下では、まずサービスが停止しているサーバーにリクエストを送信しないようにするための設定方法を説明する。続いて、複数のロードバランサを使用した冗長構成の構築方法を説明する。
なお、Keepalivedを使用する場合LVSやIPエイリアスの設定はKeepalived経由で行われるため、これらの設定はすべて一度リセットしておく必要がある。
Keepalivedのインストールと基本的な設定
Keepalivedは、RHELおよびその互換環境では「keepalived」パッケージとして提供されている。まずはこのパッケージをインストールしておく。
# yum install keepalived
Keepalivedの設定は/etc/keepalived/keepalived.confファイルで行う。この設定ファイル内の設定項目については、/usr/share/doc/keepalived-<バージョン番号>/keepalived.conf.SYNOPSISファイルに記載されている。keepalived.confのmanページ(「man keepalived.conf」で参照できる)も用意されているが、こちらは情報がやや古いようなので、keepalived.conf.SYNOPSISファイルのほうを参照することをおすすめする。
keepalived.confファイルにはデフォルトでいくつかの設定が記述されているのだが、環境に応じてそのほぼすべてを書き換えることになる。そのため、オリジナルのファイルはバックアップしておくことをおすすめする。
Keepalivedではサーバーの障害を検知したり、なんらかの構成変更が行われた場合、メールでその旨を管理者に通知する。keepalived.confでは、まずglobal_defs内でこのような通知メールの送信先や使用するSMTPサーバーなどを設定する。下記で太字で示している部分が変更すべき項目だ。
! Configuration File for keepalived global_defs { notification_email { admin@example.org ←通知メールの送信先メールアドレスを指定 } notification_email_from admin@example.org ←通知メールの送信元メールアドレスを指定 smtp_server 203.0.113.200 ←メール送信に使用するSMTPサーバーのIPアドレスを指定 smtp_connect_timeout 30 router_id LVS_DEVEL ←ロードバランサを識別するための名前を指定 }
続いて、仮想サービスおよび仮想サービスに対応するサーバーの設定を行う。設定内容は以下のようになる。
virtual_server 203.0.113.100 80 { ←対象とする仮想サービスを指定 delay_loop 5 ←死活監視のためのポーリング間隔を秒で指定 lvs_sched rr ←負荷分散方式を指定 lvs_method NAT ←パケットの転送方式を指定 protocol TCP ←対象とするプロトコルを指定 sorry_server 192.168.100.20 80 ←サーバーがすべて停止した場合のパケット転送先を指定 real_server 192.168.100.21 80 { ←仮想サービスに対応するサーバーを指定 weight 1 ←負荷分散の重みを指定 inhibit_on_failure ←サービスが停止した場合には重みを0にする HTTP_GET { ←ポーリングに使用するプロトコルを指定 url { path / ←ポーリング先URLを指定 status_code 200 ←正常な場合に返されるステータスコードを指定 } connect_timeout 5 ←ポーリングのタイムアウト時間を秒で指定 nb_get_retry 3 ←リトライ回数を指定 delay_before_retry 3 ←リトライ時に待機する時間を秒で指定 } } real_server 192.168.100.22 80 { weight 1 inhibit_on_failure HTTP_GET { url { path / status_code 200 } connect_timeout 5 nb_get_retry 3 delay_before_retry 3 } } }
Keepalivedでは、指定した間隔でサーバーに対しポーリングを行い、もし応答が帰ってこない、もしくは指定したレスポンスが帰ってこなかった場合にそのサービスが停止していると判断する。たとえばこの設定例では、/というパスに対しHTTPでGETリクエストを行い、レスポンスとして200以外のステータスコードが帰ってきた場合、もしくは5秒以内にレスポンスが帰って来なかった場合サービスに異常が発生していると判断する。これを3回繰り返し、3回とも失敗した場合はそのサーバーの負荷分散のための重みを0に設定することで、サーバーにリクエストが転送されないようにしている。
また、すべてのサーバーにおいて異常が発生した場合は、「sorry_server」で指定したサーバーおよびポートにリクエストを転送する。この設定は、すべてのサーバーにおいてサービスが停止してしまった場合などにサービスが利用できない旨をユーザーに表示する、といった目的で利用できる。
さて、設定が完了したら、次のようにしてKeepalivedを起動する。
# service keepalived start
すると、自動的にeth0に対しIPエイリアスの設定が行われ、またLVSによるロードバランス設定も行われる。IPエイリアスの設定についてはifconfigコマンドでは確認できないが、代わりにipコマンドで確認できる。たとえばeth0に付加されたIPアドレスを確認したい場合は、以下のようにする。
# ip addr show eth0 3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:22:4d:67:ea:b2 brd ff:ff:ff:ff:ff:ff inet 203.0.113.1/24 brd 133.242.98.143 scope global eth0 inet 203.0.113.100/32 scope global eth0 : :
ここで、「inet」行が2つ表示され、IPアドレスが2つ割り当てられていることが分かる。また、サーバーを停止させると、そのサーバーの重みが0になることも確認しておこう。たとえば192.168.100.22というIPアドレスを持つサーバーを停止させた場合、ipvsadm -lコマンドでLVSの設定を確認すると、次のように「Weight」が0になっていることが確認できる。
# ipvsadm -l IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 203.0.113.100:http rr -> 192.168.100.21:http Masq 1 3 1 -> 192.168.100.22:http Masq 0 0 0