freevrrpdはFreeBSD、NetBSD、OpenBSDのvrrpd実装。FreeBSDなら/usr/ports/net/freevrrpdにある。

vrrpはルータの多重化を行うためのプロトコルと説明されているけど、特にルータに限定しなくても、普通のホストでも使うことができる。

やっていることは、あるホストが落ちたらそのホストが持っていたIPアドレスを別のホストが引き継ぐ、というイメージ。これを、仮想IPアドレスを定義し複数のホストで共有してやることで実現する。複数のホストのグループはvrrpでグループIDで管理され、この中でプライオリティの最も高いホストがmaster(仮想IPアドレスが割り振られる)、それ以外がbackupとなり、masterが落ちるとbackupの中でプライオリティが高いホストが新しくmasterとなる。freevrrpdでは仮想IPアドレスはmasterとなるホストのIPアドレスエイリアスとして設定される。理屈としてはとてもシンプル。

↓こんなかんじ(192.168.1.253が仮想IPアドレス)

rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet6 fe80::20d:bff:fe4e:8e42%rl0 prefixlen 64 scopeid 0x2
        inet 192.168.1.3 netmask 0xffffff00 broadcast 192.168.1.255
        inet 192.168.1.253 netmask 0xffffffff broadcast 192.168.1.253
        ether 00:0d:0b:4e:8e:42
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active

設定はFreeBSDのportsで入れたら/usr/local/etc/freevrrpd.confで。同じディレクトリにfreevrrpd.conf.sampleがあり、丁寧にいろいろなコメントを記載してくれてある。

masterにしたいホストでの設定例

[VRID]
serverid = 1
interface = rl0
priority = 255
addr = 192.168.1.253/32
password = hogehoge
useVMAC = no
sendgratuitousarp = yes

backupにしたいホストでの設定例

[VRID]
serverid = 1
interface = rl0
priority = 250
addr = 192.168.1.253/32
password = hogehoge
useVMAC = no
sendgratuitousarp = yes

設定すべき項目はざっとこんなところ。

  • serveridはvrrpのグループID。紐付けたいホストで同じIDを使う。
  • interfaceはvrrpをしゃべらせたいNICを指定。
  • priorityは優先度。255が最大値で指定されているとmasterになる。
  • addrは仮想IPアドレス。
  • passwordはvrrp通信時のパスワード。グループ内で同じものを指定。
  • useVMACはMACアドレスも仮想のものを使うかどうかの指定。

仮想MACアドレスを使うと、切り替り後も同じMACアドレスで通信できるため、arpの変更が起こらない(ただし、L2SWでは変更に追従する必要がある。まあ、普通は意識しなくてよい)。仮想MACアドレスを使う場合は、切り替り時にホストのMACアドレスが書き換えられるため、もともとIPアドレスが割り振られているばあいにはそれらに影響が出る(可能性がある)。

仮想MACアドレスを使わない場合は、切り替り後に仮想IPアドレスに対応するMACアドレスが(新しいmasterホストのものに)変更される。このため他のホストにMACアドレスの変更を通知してやる必要がある。これを指示するのが、sendgratuitousarp。切り替り後に自分自身のMACアドレスが含まれたarpリクエストをブロードキャストし、結果的にMACアドレスの変更がローカルリンク内に伝播される。

これでfreevrrpdを立ち上げれば最低限のIPアドレスの切り替えは出来るようになる。仮想IPアドレスを使ったサービスの上げ下ろし(DBやhttpdのstart/stopとか)にはmasterscript、backupscriptで指定したスクリプトで行えばいいだろう。

masterscript = /usr/local/bin/master_script.sh
backupscript = /usr/local/bin/backup_script.sh

データの同期や共有ディスクの利用をきちんと考慮してあげれば、なんちゃってHAクラスタ的な使い方が出来る(んじゃないかなあ)。