「Linux Virtual Server」と「Keepalived」で作る冗長化ロードバランサ
多数のクライアントがアクセスするような負荷の高いサービスや停止させられないサービスを運用する場合、複数のサーバーを使ってサービスの負荷分散や冗長化を行うのが一般的だ。本記事では、「Linux Virtual Server(LVS)」を使ってこのような構成を実現する方法について紹介する。
Linuxサーバーをロードバランサにする「Linux Virtual Server」(LVS)
最近では多数のCPUコアを持つサーバーが安価で利用できるようになり、サーバー1台の処理能力は飛躍的に向上している。しかし、リクエストの処理に多くのリソースを使用するようなサービスや、短時間に多数のリクエストを処理する必要があるサービスでは、1台のサーバーだけでは処理能力が不足する場合がある。このような場合、複数台のサーバーで同じサービスを運用し、ロードバランサを使ってリクエストを振り分けることで負荷の分散を図ることが多い。
ロードバランサは通常サーバーとクライアントの間に設置され、クライアントからのリクエストを受け取って一定のルールの下サーバーに振り分ける、という処理を行う。設置方法はネットワーク環境によって異なるが、ロードバランサ自体にクライアントからアクセスできるIPアドレスが与えられ、あたかもロードバランサがサービスを提供しているように見せる構成を取ることが多い(図1)。
ロードバランサは専用のハードウェア製品として提供されるほか、ロードバランサ機能が搭載されたルーター製品もある。しかし、専用ハードウェアは比較的高価であるため、安価なLinuxサーバーをロードバランサとして利用する例も多い。Linuxサーバーをロードバランサとして使用するためのソフトウェアとして有名なのが、今回紹介する「Linux Virtual Server(LVS)」だ。
ロードバランサを提供するLinux Virtual Serverと冗長化機能を提供するKeepalived
LVSはあらかじめ指定された条件に基づいてリクエストをサーバーに振り分けるという動作を行うソフトウェアだ。Linuxカーネルに組み込んで使用するカーネルモジュールと設定や管理を行うためのipvsadmコマンドから構成されており、Red Hat Enterprise Linuxやその互換ディストリビューションであるCentOSなどでは標準でカーネルにLVS機能が組み込まれている。
また、LVSは「Keepalived」と呼ばれるソフトウェアと組み合わせて利用されることが多い。LVSにはロードバランス対象を監視する仕組みが用意されていないため、もしサービスを提供するサーバー群の一部がトラブルで停止した場合でも、それらのサーバーに対しリクエストを振り分けてしまう可能性がある。Keepalivedはサービスの稼働状態を監視するソフトウェアで、サービスが停止していたらそのサーバーへのリクエストの振り分けをやめるようLVSの設定を変更する、という機能を持っている。
Keepalivedにはロードバランサ自体の稼働状況を監視し、ロードバランサが停止していたら自動的にバックアップとして用意しておいたロードバランサに切り替える機能も用意されている。ロードバランサを使っている場合、サービスを提供するサーバーが稼働していたとしても、ロードバランサ自体が停止してしまったら外部からサービスへのアクセスができなくなってしまう。keepalibedを使ってLVS自体を冗長化することで、サービスの冗長化をより完全なものとすることが可能となる。
以下ではRed Hat Enterprise Linux(RHEL) 6.3互換のCentOS 6.3を使用し、まずLVSを使った基本的なロードバランサ設定について紹介する。続けてKeepalivedを用いたサービスの稼働状態の監視、そして最後にKeepalivedによるロードバランサの冗長化について解説していく。
LVS環境の構築とロードバランシング設定
LVSを使ってロードバランサを構築するには、ロードバランサとして使用するサーバー側のLinuxカーネルにLVSをあらかじめ組み込んでおく必要がある。RHELおよびその互換OSでは、デフォルトでカーネルモジュール(ip_vsモジュール)としてLVSを組み込めるようになっているので、特別な設定は不要だ。ただし、カーネルのカスタマイズなどを行っている場合は、LVSを有効にできるように設定してカーネルをビルドしておく必要がある。
LVSでは「ipvsadm」というコマンドを使用してロードバランサの設定を行う。RHELやその互換環境では同名のパッケージでこのコマンドが提供されているので、あらかじめインストールを行っておく。
# yum install ipvsadm
LVSを使ったロードバランサを実現するためのネットワーク構成
ロードバランサはサーバーの代わりにクライアントからリクエストを受け取り、そのリクエストを一定のルールでサーバーに転送する処理を行う。LVSではTCP/IPレベルでパケットを転送する「レイヤ4スイッチング」という方式でこれを実現している。パケットの転送方式としてはNATおよびダイレクトルーティング、トンネリングという3つが用意されている(表1)。
転送方式 | 説明 |
---|---|
NAT | IPパケットに対しロードバランサでNATを行ってパケットをサーバーに転送する |
ダイレクトルーティング | IPパケットを書き換えずにパケットをサーバーに転送する |
トンネリング | IPパケットをカプセル化した上でサーバーに転送する |
NAT方式はロードバランサでNATを行ってパケットを転送する方式で、ロードバランサはローカルネットワークとWANの接続部分に設置する。この方式はサーバーがローカルネットワーク内にある場合など、サーバーとクライアントが直接接続できない場合でも利用できるのが特徴だ。いっぽう、ダイレクトルーティング方式やトンネリング方式はクライアントからサーバーへの通信についてはロードバランサを経由するが、サーバーからクライアントへの通信についてはロードバランサを経由しないのが特徴となる。さらにトンネリング方式ではロードバランサとサーバー間の通信にカプセル化されたIPパケットが利用されるため、ロードバランサとサーバーが別のネットワーク上にあっても利用できるのが特徴だ。
LVSではネットワーク構成に応じたパケット転送方式を選択できるが、もっとも一般的なのNATを利用する構成だ。その理由として、よりセキュリティを向上させることが可能である点が挙げられる。サーバーをインターネットから直接アクセスできないローカルネットワーク内に設置し、ロードバランサーに対してのみインターネットからのアクセスが可能な構成にすることで、サーバーを狙った攻撃をブロックすることができる。また、もしロードバランサが攻撃された場合でも、ロードバランサ上ではサービスは運用されていないため、サービスへの被害を最小限に抑えることができる。
NATによるパケット転送を使ったロードバランサ環境の構築
以下ではNATによるパケット転送を使ったロードバランサ環境の構築について紹介していく。今回使用するネットワーク構成は、次の図2のようになる。
ネットワークの設定
ロードバランサとして使用するマシンには2つのネットワークインターフェイス(NIC)を搭載しており、eth0はWAN(インターネット)に、eth1はLANに接続されている。また、サービスを運用するサーバーは2台で、LAN経由でロードバランサに接続されている。なお、ロードバランサとして使用するマシンにはLVSが使用する専用のIPアドレス(仮想IPアドレス)を用意しておく必要がある。このIPアドレスがクライアントに向けて公開するIPアドレスとなり、クライアントはこのIPアドレスに向けてリクエストを送信する。Linuxには「IPエイリアス」という、1つのNICに2つ以上のIPアドレスを割り当てる機能があり、これを利用してWAN側のNICに対しLVS用のIPアドレスを割り当てておく。今回の構成ではeth0がWAN側のNICになっているので、これに対し203.0.113.100というIPアドレスをLVSに割り当てている。
eth0にIPエイリアスを利用して203.0.113.100というIPアドレスを付与するには、まず/etc/sysconfig/network-scripts/ディレクトリ内にifcfg-eth0:0というファイルを作成し、次のようにIPアドレスやネットマスクなどの情報を記述しておく。
DEVICE=eth0:0 ONBOOT=yes NETMASK=255.255.255.0 TYPE=Ethernet IPADDR=203.0.113.100
続いてserviceコマンドでネットワークを再起動すると、eth0:0というデバイスに203.0.113.100というIPアドレスが割り当てられ利用できるようになる。eth0:0というのは「eth0の1つめのエイリアス」を意味している。
# sevice network restart
ネットワークを再起動したら、ifconfigコマンドでeth0:0デバイスが有効になっていることを確認しておこう。
# ifconfig eth0 Link encap:Ethernet HWaddr 00:22:4D:67:EA:B2 inet addr:203.0.113.1 Bcast:133.242.98.143 Mask:255.255.255.240 : : eth0:1 Link encap:Ethernet HWaddr 00:22:4D:67:EA:B2 inet addr:203.0.113.100 Bcast:133.242.98.143 Mask:255.255.255.240 : :
また、IPパケット転送を有効にするようシステム設定の変更も行っておく。具体的には/etc/sysctl.confをエディタで開き、以下のように「net.ipv4.ip_forward」の値を「1」に変更する。
# vi /etc/sysctl.conf : : # Controls IP packet forwarding net.ipv4.ip_forward = 1 ←値を「1」に変更して有効にする
/etc/sysctl.confファイルの変更後、syscrl -pコマンドを実行すると変更が反映される。
# /sbin/sysctl -p
ロードバランサの設定
次に、ipvsadmコマンドを使ってロードバランシング設定を行っていく。まず、念のためipvsadm -CコマンドでLVSの設定をクリアしておく。
# ipvsadm -C
LVSでは、ロードバランシングするIPアドレスおよびポートの組み合わせを「仮想サービス」と呼び、これがクライアントの接続先となる。仮想サービスは「ipvsadm -A」コマンドで登録できる。今回はeth0:0に割り当てられた203.0.113.2というIPアドレスが仮想サービスのIPアドレスとなり、このIPアドレスと利用するポート番号の組み合わせを仮想サービスとして登録しておく。たとえば80番ポートへのリクエストをロードバランシング対象とするには以下のようにする。
# ipvsadm -A -t 203.0.113.100:80
続いて、「ipvsadm -a」コマンドで仮想サービスに対しパケットの転送先を登録する。たとえば192.168.100.21の80番ポートと、192.168.100.22の80番ポートを転送先とするには以下のようにする。
ipvsadm -a -t 203.0.113.100:80 -r 192.168.100.21:80 -m ipvsadm -a -t 203.0.113.100:80 -r 192.168.100.22:80 -m
以上でLVSの設定は完了だ。最後に、ipvsadm -lコマンドでロードバランシング設定を確認しておこう。
# 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 wlc -> 192.168.100.21:http Masq 1 0 0 -> 192.168.100.22:http Masq 1 0 0
サーバー側の設定
NATによるパケット転送を利用する場合、ロードバランサがサーバーのネットワークゲートウェイとして設定されている必要がある。サービスを提供する(ロードバランスされる)サーバー側でsystem-config-networkコマンドの実行、もしくは/etc/sysconfig/network-scripts/ifcfg-eth*ファイルの編集などを行い、設定を変更しておこう。今回の例の場合、ロードバランサのLAN側IPアドレスである192.168.100.1をデフォルトゲートウェイに指定する。
以上の設定が完了したら、クライアントから仮想サービスに接続を行い、正しくサーバーに接続できるかテストしてみよう。また、どのサーバーにリクエストが振り分けられているかは、ipvsadm -lコマンドの出力中「ActiveConn」および「InActConn」項目で確認できる。たとえば以下のように出力された場合、192.168.100.21に対し3つ、192.168.100.22に対し4つの接続が行われていることになる。
# 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 wlc -> 192.168.100.21:http Masq 1 3 2 -> 192.168.100.22:http Masq 1 4 1
LVS設定の保存と復元
ipvsadmコマンドで行ったLVSの設定は、そのままではロードバランサとして使用しているLinuxマシンを再起動するとリセットされてしまう。そのため、RHELやその互換環境では設定をファイルに保存しておき、再起動時に自動的に設定を復元する機能が用意されている。設定をファイルに保存するには、以下のように「ipvsadm save」引数付きでserviceコマンドを使用する。
# service ipvsadm save ipvsadm: Saving IPVS table to /etc/sysconfig/ipvsadm: [ OK ]
すると、「/etc/sysconfig/ipvsadm」ファイルにその時点での設定が保存され、ipvsadmサービスの起動時に自動的に復元される。再起動時に自動的にipvsadmサービスが起動するようにするには、以下のようにchkconfigコマンドでipvsadmサービスを有効にしておけばよい。
# chkconfig ipvsadm on