DRBD*1による、分散ファイルシステムを構築してみる。DRBDはネットワーク経由のミラーリングシステムを提供する。
これにより、2台のマシン間でデータをリアルタイムで同期でき、いつ、どちらがダウンしてもデータは無事となる。
ここでは、NFSサーバをACT/STB構成で構築する。DRBD 8.0からは、ACT/ACT構成ができるようだが、自分の用途ではACT/STBで十分なのと、ファイルシステムの制限があるので使用しない。
以下の条件を満たすシステムを構築する。
まずは、パッケージをインストール。
# apt-get install drbd8-utils heartbeat nfs-kernel-server
設定ファイルは、以下のようになる。両マシンで同一の設定にするため、片方で設定をした後、もう片方にファイルコピーすることをおすすめする。
resource r0 { handlers { outdate-peer "/usr/lib/heartbeat/drbd-peer-outdater -t 5"; split-brain "/usr/lib/drbd/notify-split-brain.sh root"; } protocol C; #ローカルとリモート両方の書き込み終了で完了 syncer { rate 50M; #同期で利用するバンド幅を50MBitにする verify-alg sha1; #オンライン照合を有効にしてアルゴリズムを選択 } disk { on-io-error detach; #下位デバイスがエラーを返したときに低レベルデバイスを切り離す fencing resource-only; #ノードが切り離されたプライマリの時に他ノードを期限切れにする } device minor 0; #DRBDのブロックデバイス名(/dev/drbd0) disk /dev/sdb1; #データを保存するブロックデバイス名 meta-disk internal; #メタデータを下位デバイスの最後に作成 net { cram-hmac-alg sha1; #認証アルゴリズム shared-secret "passwd"; #認証パスワード } on drbd1 { #DRBDデバイス1 address 192.168.100.168:7789; } on drbd2 { #DRBDデバイス2 address 192.168.100.169:7789; } }
関連コマンドのパーミッションを変える。
drbd1# chgrp haclient /sbin/drbdsetup drbd1# chmod o-x /sbin/drbdsetup drbd1# chmod u+s /sbin/drbdsetup drbd1# chgrp haclient /sbin/drbdmeta drbd1# chmod o-x /sbin/drbdmeta drbd1# chmod u+s /sbin/drbdmeta drbd2# chgrp haclient /sbin/drbdsetup drbd2# chmod o-x /sbin/drbdsetup drbd2# chmod u+s /sbin/drbdsetup drbd2# chgrp haclient /sbin/drbdmeta drbd2# chmod o-x /sbin/drbdmeta drbd2# chmod u+s /sbin/drbdmeta
続いて、両マシンで、DRBDの初期化、起動を行う。サービスの起動は、相手の起動を待つので、近い時間に実行する。
drbd1# drbdadm create-md r0 drbd2# drbdadm create-md r0 drbd1# /etc/init.d/drbd start drbd2# /etc/init.d/drbd start
この時点での、DRBDの状態は、以下のようになっている。この時点では、どちらもセカンダリで同期状態にはなっていない。
drbd1# cat /proc/drbd version: 8.3.7 (api:88/proto:86-91) srcversion: EE47D8BF18AC166BE219757 0: cs:Connected ro:Secondary/Secondary ds:Inconsistent/Inconsistent C r---- ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:1048308
片方のマシンをプライマリにする。
drbd1# drbdsetup /dev/drbd0 primary -o
この時点での、DRBDの状態は、以下のようになっている。
drbd1# cat /proc/drbd version: 8.3.7 (api:88/proto:86-91) srcversion: EE47D8BF18AC166BE219757 0: cs:SyncSource ro:Primary/Secondary ds:UpToDate/Inconsistent C r---- ns:66944 nr:0 dw:0 dr:67144 al:0 bm:4 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:981364 [>...................] sync'ed: 6.7% (981364/1048308)K finish: 0:17:31 speed: 820 (640) K/sec
裏では同期中だが、ファイルシステムを作成して、マウントする。
drbd1# mkfs.xfs /dev/drbd0 drbd1# mkdir /mnt/drbd0 drbd1# mount /dev/drbd0 /mnt/drbd0
プライマリでファイルを作成し、プライマリとセカンダリを入れ替えて、ファイルが見えることを確認する。
drbd1# echo abcdefg > /mnt/drbd0/test drbd1# umount /mnt/drbd0 drbd1# drbdadm secondary r0 drbd2# drbdadm primary r0 drbd2# mount /dev/drbd0 /mnt/drbd0 drbd2# cat /mnt/drbd0/test
DRDBが動作してるふたつのマシン間で、それぞれを監視してシステムとしてのサービスを継続させるため、HeartBeatを使用する。
以下のような設定ファイルを、新規に作成する。認証キーは適当に作成する。
crm yes logfacility local0 keepalive 1 warntime 3 deadtime 5 initdead 60 mcast eth0 225.0.0.1 694 1 0 respawn hacluster /usr/lib/heartbeat/dopd apiauth dopd gid=haclient uid=hacluster node drbd1 node drbd2
監視対象リソースの指定。仮想IPアドレスは192.168.0.201、DRBDはr0を監視、ファイルシステムは/dev/drbd0を監視(マウント)とする。
drbd1 192.168.0.201 drbddisk::r0 Filesystem::/dev/drbd0::/mnt/drbd0
監視対象指定を新形式(Version 2)に変換。
# /usr/lib/heartbeat/haresources2cib.py
認証キー。sha1、md5のいずれかを選択する。
auth 1 1 sha1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
認証キーのパーミッションを変更。
drbd1# chmod go-r /etc/ha.d/authkeys
以上で設定は完了したので、先ほど編集した3つのファイルをもう片方にコピーして、heartbeatを両ノードで起動する。
drbd1# scp -p /etc/ha.d/ha.cf drbd2:/etc/ha.d/ drbd1# scp -p /etc/ha.d/haresources drbd2:/etc/ha.d/ drbd1# scp -p /etc/ha.d/authkeys drbd2:/etc/ha.d/ drbd1# /usr/lib/heartbeat/haresources2cib.py drbd2# /usr/lib/heartbeat/haresources2cib.py drbd1# /etc/init.d/heartbeat start drbd2# /etc/init.d/heartbeat start
起動状態を見てみる。
drbd1# crm_mon -1 Your configuration was internally updated to the latest version (pacemaker-1.0) ============ Last updated: Sun Apr 24 17:54:39 2011 Stack: Heartbeat Current DC: drbd1 (a427ae8e-5212-4ab3-be28-f195975d4119) - partition with quorum Version: 1.0.9-74392a28b7f31d7ddc86689598bd23114f58978b 2 Nodes configured, unknown expected votes 1 Resources configured. ============ Online: [ drbd1 drbd2 ] Resource Group: group_1 IPaddr_192_168_0_201 (ocf::heartbeat:IPaddr): Started drbd1 drbddisk_2 (heartbeat:drbddisk): Started drbd1 Filesystem_3 (ocf::heartbeat:Filesystem): Started drbd1
マスター側でheartbeatを停止させて、フェイルオーバーすることを確認。さらに、マスター側が復帰したときにフェイルバックすることも確認。
drbd1# ls -l /mnt/drbd0/ drbd1# /etc/init.d/heartbeat stop drbd2# ls -l /mnt/drbd0/ drbd1# /etc/init.d/heartbeat start drbd1# ls -l /mnt/drbd0/
クラスタが起動したときに、自分で指定した特定のコマンドを実行してみる。
クラスタと連動するコマンドの種類はいくつかあり、ここではLSBをつかう。この場合、コマンドは"/etc/init.d/"配下に置く必要がある。
ここでは、"/etc/init.d/haupcmd"のコマンドにする。このコマンドには、start,stop,restart,reload,force-reload,statusを用意しておくらしいが、start,stop,statusしか実際に受け取ったのは確認できていない。startは起動時、stopは停止時、statusは定期的にチェック(後述)するときに実行された。
コマンドが用意できたら、crmで指定する。configureから、以下のように登録したあと、グループの最後に追加する。
primitive haupcmd lsb:haupcmd
このとき、以下のように引数を追加すれば、指定した間隔でstatusを引数に実行される。正常時は0、異常時は3の終了コードを返すと良い。
primitive haupcmd lsb:haupcmd op monitor interval="120s" timeout="60s"
クラスタ内のすべてのノードにコマンドを追加した後、"commit"で反映。
指定したコマンドが、startを引数に実行されるはず。
HeartBeatと連携するように設定する。
NFS用のディレクトリを作成し、NFS情報を保存するディレクトリをDRBD上に移動する。
drbd1# /etc/init.d/nfs-kernel-server stop drbd1# /etc/init.d/nfs-common stop drbd2# /etc/init.d/nfs-kernel-server stop drbd2# /etc/init.d/nfs-common stop drbd1# mkdir /mnt/drbd0/nfsdata drbd1# chown nobody:nogroup /mnt/drbd0/nfsdata drbd1# mv /var/lib/nfs /mnt/drbd0/ver_lib_nfs drbd1# ln -s /mnt/drbd0/ver_lib_nfs /var/lib/nfs drbd2# rm -r /var/lib/nfs drbd2# ln -s /mnt/drbd0/ver_lib_nfs /var/lib/nfs
続いて、クラスタ設定にNFSを追加する。
drbd1 192.168.0.201 drbddisk::r0 Filesystem::/dev/drbd0::/mnt/drbd0 nfs-kernel-server
drbd1# rm /var/lib/heartbeat/crm/cib.xml* drbd1# /usr/lib/heartbeat/haresources2cib.py drbd1# scp -p /etc/ha.d/haresources drbd2:/etc/ha.d drbd2# rm /var/lib/heartbeat/crm/cib.xml* drbd2# /usr/lib/heartbeat/haresources2cib.py
さらに、NFSサービスの自動起動を止める。HeartBeatがデーモンを管理するため。
drbd1# update-rc.d nfs-kernel-server remove drbd1# update-rc.d nfs-common remove drbd2# update-rc.d nfs-kernel-server remove drbd2# update-rc.d nfs-common remove
最後に、方ノードのHeartBeatを落として、正常に切り替わることを確認して完了。
ノードを切り替えて書き込みができるようになるまで1分40秒程度かかるが、データのロストはなかった。
iSCSIもHeartBeatと連携するように設定する。
iSCSIの監視は、有効ノード側がiSCSIターゲットにリソースを追加する方式なので、/etc/ha.d/haresources への記述はしない。紛らわしいので、このファイルは中身を空にしておく。
crmコマンドを使って、/var/lib/heartbeat/crm/cib.xml を更新する。マスタ側で実行すれば、設定も同期される。
# crm crm(live)# configure crm(live)configure# primitive iSCSI_Target ocf:heartbeat:iSCSITarget params implementation="iet" iqn="iqn.2001-04.com.example:storage.disk2.sys1.xyz" tid="1" op monitor interval="10s" crm(live)configure# primitive iSCSI_Target_LUN0 ocf:heartbeat:iSCSILogicalUnit params implementation="iet" target_iqn="iqn.2001-04.com.example:storage.disk2.sys1.xyz" lun="0" path="/dev/drbd2" op monitor interval="10s" crm(live)configure# edit crm(live)configure# commit
editコマンドでは、起動順番を指定するため、"group"の行を以下のように変更する。
group group_1 drbddisk_1 Filesystem_2 nfs-kernel-server_3 iSCSI_Target iSCSI_Target_LUN0 IPaddr_192_168_0_201
crmで、アップグレードしろと怒られる場合は、以下のコマンドを実行する。
# cibadmin --upgrade --force
debian squeezeの場合、シャットダウン時のサービス終了順が、iscsitargetの後にheartbeatなので、順番を変える。こうしないと、iSCSIがうまく切り替えれない。
# Required-Start: $remote_fs $network $time $syslog iscsitarget # Required-Stop: $remote_fs $network $time $syslog iscsitarget
定を有効にするため、update-rc.dを実行する。
# update-rc.d heartbeat remove # update-rc.d heartbeat defaults
運用中に、動作状況を確認するコマンドをあげる。
HeartBeatの動作状況(リアルタイム) | crm_mon |
---|---|
HeartBeatの動作状況(現在状態) | crm_mon -1 |
DRBDの状態 | /etc/init.d/drbd status |
NFSサーバの公開状態 | exportfs -v |
NFSサーバのマウント情報 | showmount -a |
ネットワークから切り離された場合など、両ノードでアクティブになったときに整合性がとれなくなる可能性がある。その場合は、手動で回復させる*2。
drbd1をマスタにして、drbd2に同期させる(drbd2のデータは消える)場合は、以下のように行う。
drbd2# drbdadm secondary r0 drbd2# drbdadm -- --discard-my-data connect r0 debd1# drbdadm connect r0
以下のようなエラーになった場合、
drbd2# drbdadm -- --discard-my-data connect r0 0: Failure: (125) Device has a net-config (use disconnect first)
次のようにする。
drbd2# drbdadm disconnect r0 drbd2# drbdadm -- --discard-my-data connect r0
パッケージなどをインストールした後、/etc/drbd.d/sdb1.resをコピーし、drbdadm create-md r0を実行後、DRBDを起動するだけ。すぐに同期が始まる。
スプリットブレインになるのをなるべく減らすため、dopdを使おうとしたが、どうもうまく動かない。
outdate-peerの動作を見ると、環境変数DRBD_PEERに対向ホスト名が設定されると書いてある。ということは、設定ファイルに対向ホスト名の情報が必要だと言うこと。つまり、floatingでのIPアドレスのみの指定では、ホスト名がわからないのでだめと言うことに。
on xxxx でホスト名を指定する方法にするとうまく動作した。