DRBD + Heartbeat

サーバを運用する際の問題の一つとして故障時の対応があります。高価なシステムを構築すればストレージはSANで構築し、サービスのフェイルオーバーも高価な商用ソフトを導入することで実現することは可能です。しかしながら、「そこまでコストをかけて構築しなくても、、、」といった場合もあるかと思います。そのような場合の解決策の一つとして、本編ではDRBD + Heartbeatというオープンソース・ソフトウェアを用いて、HA Clusterを構築する方法を解説します。以下、<host_m>と<host_s>という2台のサーバを用いた構成手順を紹介します。

 

DRBDの導入

DRBDとは、Distributed Replicated Block Deviceの略で、本家WEBサイトは http://www.drbd.org/ になります。具体的にDRBDは何をするものか?というと、パーティションをネットワークを介してミラーリングを行ってくれます。ここで注意が必要なのですが、ミラーを行う場所をブロックデバイスにて指定する為、「ある特定のディレクトリ以下を全て」といったようなミラーリングは行えないということです。また、同じ理由からミラーリングを行うにはOSの再インストールが必要になることもあります。
DRBDのミラーリングは、指定したブロックデバイスに変更があったときに自動的に行われます。また、その実行はkernelモードで行われます。これまでrsync等を用いて手動で行っていた方も多いと思いますが、これらに対して速度、簡易性といった点で有利です。

また、同じくオープンソースDBのMySQLがDRBDをサポートしており、これにより冗長構成が行えるようです。

DRBDのインストール

現在のDRBDの最新版として、8.0.5がリリースされています。しかし、後述のHeartbeatと組み合わせて使用する場合、HeartbeatがサポートするDRBDは1世代前の0.7系となりますので、0.7系の最新版0.7.24を導入しましょう。(8.0系でサポートされるLinuxは2.6系のみですが、0.7系では2.4系と2.6系の両方がサポートされます。また、8.0系では機能追加等が行われており、この為導入までの設定は0.7系の方が容易と思われます。)

DRBDとHeartbeatとの対応表インストール自体は、本家サイトからdrbd-0.7.24.tar.gzをダウンロードし、ビルド、インストールを行うのですが、含まれているdrbd.spec.inを用いてrpmを作成してからインストールする方が簡単でしょう。注意点として、kernel moduleが作成され、これがビルドを行った環境のLinux Kernelのバージョンに依存してしまいます。これにより、kernelアップデートを行った場合等は再度これらを作成する等の作業が必要になってきます。

DRBDの設定

host_m、host_sの両方で、設定ファイル/etc/drbd.confを下記のように同じ記述を行います。

resource drbd0 {
protocol C;
syncer {
rate 200M;
}
disk {
on-io-error pass_on;
}
on host_m {
device /dev/drbd0;
disk /dev/hda2;
address 192.168.0.1:7789;
meta-disk internal;
}
on host_s {
device /dev/drbd0;
disk /dev/hda2;
address 192.168.0.2:7789;
meta-disk internal;
}
}

設定ファイル詳細は、< $ man drbd.conf >とすれば、英文ドキュメントによる説明を確認することが出来ます。上記を簡単に説明すると、protocolはsyncを「どの時点で完了するか?」を決定するもので、A, B, Cが指定できます。これらの意味は下記の通りとなります。

A:write IO is reported as completed, if it has reached local disk and local TCP send buffer.
(データを自分のディスクとTCP送信バッファに送った時点で完了。)

B:write IO is reported as completed, if it has reached local disk and remote buffer cache.
(データを自分のディスクと相手ノードのバッファキャッシュに送った時点で完了。)

C:write IO is reported as completed, if it has reached both local and remote disk.
(データを自分と相手のディスクに送った時点で完了。)

となっており、C > B > Aのように安全性が高くなっています。

on host_m {
  device /dev/drbd0;
  disk /dev/hda2;
  address 192.168.0.1:7789;

この部分は、「ディスクパーティション /dev/hda2 を、/dev/drbd0 に割り当てて、host_mのIP 192.168.0.1の7789番ポートを用いてsyncを行う」といった意味になっています。

また、Heartbeatと連携させる場合、host_m、host_sの双方において、/dev/drbd0部は共通である必要があります。

次にhost_m、host_sの双方において、以下のように実行します。

# /sbin/modprobe drbd <- drbd moduleを読み込む
# /sbin/lsmod | grep drbd <- モジュールがロードされているか確認する
# drbdsetup /dev/drbd0 disk /dev/hda2 internal -1
# drbdsetup /dev/drbd0 net 192.168.0.1 192.168.0.2 C
   <- host_mで実行 IPの部分は <ost_m> <host_s>の順になる
# drbdsetup /dev/drbd0 net 192.168.0.2 192.168.0.1 C
   <- host_sで実行 IPの部分は上と逆なので注意

この時点でステータスを確認すると、

[root@host_m crm]# cat /proc/drbd
version: 0.7.24 (api:79/proto:74)
SVN Revision: 2875 build by foo@host_m, 2007-07-18 09:59:41
0: cs:WFConnection st:Secondary/Unknown ld:Consistent
ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0
1: cs:Unconfigured

のように見えます。Unknownとなっているのは、host_sで実行していない為です。

更に、host_mで、< # drbdsetup /dev/drbd0 primary >として、drbdサービスのPrimaryに格上げします。/proc/drbdを確認すると、

version: 0.7.24 (api:79/proto:74)
SVN Revision: 2875 build by foo@host_m, 2007-07-18 09:59:41
0: cs:Connected st:Primary/Secondary ld:Consistent
ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0
1: cs:Unconfigured

のように、Primaryに変化しているのが確認出来ます。更に、< # drbdadm — –do-what-I-say primary all >として、syncを開始します。

動作確認

それでは、動作確認をしてみましょう。host_m、host_sの双方で、< # /etc/init.d/drbd stop >としてサービスを終了します。次に、host_mで< # /etc/init.d/drbd start >としてサービスを起動します。そうすると

[root@host_m crm]# /etc/init.d/drbd start
Starting DRBD resources: [ d0 s0 n0 ].
……..

のように表示されますので、この間にhost_s側でサービスを起動させます。この間に起動させない場合、継続するか、無視するか?の決断を迫られます。

問題なくサービスが起動したら、host_mで、

# drbdsetup /dev/drbd0 primary <- host_mをPrimaryにする
# /sbin/mkfs.ext3 /dev/drbd0
<- /dev/drbd0をext3ファイルシステムでフォーマット
# mount -t ext3 /dev/drbd0 /drbd
<- /dev/drbd0を/drbdにマウント

として、ファイルシステムをマウントします。その後、

# touch /drbd/testfile1
# dd if=/dev/zero of=/drbd/testfile2 bs=1M count=100

のようにファイルを作成します。そして、

# umount /drbd
# drbdsetup /dev/drbd0 secondary

として、ファイルシステムのアンマウント、secondaryへと格下げを行います。念の為、< # /proc/drbd >として確認を行います。
host_sにおいて、

# drbdsetup /dev/drbd0 primary <- host_mをPrimaryにする
# mount -t ext3 /dev/drbd0 /drbd <- /dev/drbd0を/drbdにマウント

として、ファイルシステムをマウント後に、< # ls -al /drbd >として先ほどhosts_mで作成したファイルが存在していることを確認します。ファイルが存在していた場合、無事動作が確認できたことになります。

Heartbeatの導入

Heartbeatは、HA Cluster構築用のオープンソース・ソフトウェアです。本家WEBサイトは http://www.linux-ha.org/ になります。
バージョン1系の頃は、【1:1】のクラスタ構築しか行えませんでしたが、バージョン2系になり、【1:多】のクラスタ構築が行えるようになっています。Heartbeatの面白い機能として、Stonith(Shoot The Other Node In The Head:相手ノードをパワーダウンさせる機能)があり、これがサポートする機器には、APCのUPSや、IPMIプロトコル、HP iLoなどがあります。これにより、OSとしてほとんど反応がないが、Virtual IPを放さないといった問題も回避することが出来ます。

Heartbeatのインストール

本家Webサイトから、heartbeat-2.1.2.tar.gzをダウンロードし、ビルド、インストールをすればよいのですが、Red Hat Linuxなどを使用している場合は、DRBDと同様にRPMパッケージでインストールしたほうが、管理しやすいと思います。その場合、CentOSのものを流用することができます。FTPサイトから、5.0/extras/SRPMS/heartbeat-2.1.2-3.el5.centos.src.rpmをダウンロードしてきます。
その後、< $ rpm -ivh heartbeat-2.1.2-3.el5.centos.src.rpm >としてインストールしてから、heartbeat.specを見て、「どのようなパッチがあたっているか?」や「危険な処理がないか?」を確認します。また、CVSで修正されたパッチを当てたい場合、ここで記述します。
< $ rpmbuild -ba heartbeat.spec >として、パッケージを作成します。今回は、heartbeat本体パッケージ(heartbeat-2.1.2-3.i386.rpm)、プラグインパッケージ(heartbeat-pils-2.1.2-3.i386.rpm)、stonithパッケージ(heartbeat-stonith-2.1.2-3.i386.rpm)を、< $ rpm -ivh heartbeat-2.1.2-3.i386.rpm heartbeat-pils-2.1.2-3.i386.rpm heartbeat-stonith-2.1.2-3.i386.rpm >としてインストールします。

Heartbeatの設定

Heartbeatバージョン2は、機能追加が多数行われており、それを全て理解し設定することは複雑です。しかし、ここではheartbeatのサービス自体が起動する為だけの設定にとどめておきます。/etc/ha.d/ha.cfを下記のように、host_m、host_s共々に記述します。詳細はHeartbeatソース内のha.cfを参照してください。

crm on
logfile /var/log/ha-log
logfacility local0
keepalive 3
deadtime 30
deadping 40
warntime 10
initdead 60
udpport 694
auto_failback off
bcast eth2
node host_m
node most_s
ping 192.168.1.254
respawn root /usr/lib/heartbeat/pingd -m 100 -d 5s -a default_ping_set

また、通信認証用のファイル/etc/ha.d/authkeysを

auth 1
1 sha1 Love Love VA Linux

のように記述します。”Love Love VA Linux”部は、ご自分の好みのフレーズで構いません。またauthkeysはパーミッションを600にしておきます。
host_m、 host_s双方で< # /etc/init.d/heartbeat start >とし、Heartbeatサービスを起動します。数分後に、/var/lib/heartbeat/crm/cib.xmlが生成されます。
< # crm_mon -i 3 >のようにしてクラスタの運用状況を確認して問題なく設定できていることを確認してください。

DRBDとの連携設定

設定ファイルの変更を行う前にheartbeatサービスを停止します。
< # /etc/init.d/heartbeat stop >
その後、 /var/lib/heartbeat/crm に移動し、cib.xmlを次のように変更します。

<cib admin_epoch="0" generated="false" have_quorum="false" ignore_dtd="false"
num_peers="0" cib_feature_revision="1
.3" epoch="9" num_updates="1" cib-last-written="Fri Jul 20 14:52:48 2007">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <attributes/>
       </cluster_property_set>
     </crm_config>
     <nodes>
       <node id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" uname="host_m" type="normal"/> ※生成されたcib.xmlを参照
       <node id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" uname="host_s" type="normal"/> ※生成されたcib.xmlを参照
     </nodes>
     <resources>
       <master_slave id="ms-drbd0">
         <meta_attributes id="ma-ms-drbd0">
           <attributes>
             <nvpair id="ma-ms-drbd0-1" name="clone_max" value="2"/>
             <nvpair id="ma-ms-drbd0-2" name="clone_node_max" value="1"/>
             <nvpair id="ma-ms-drbd0-3" name="master_max" value="1"/>
             <nvpair id="ma-ms-drbd0-4" name="master_node_max" value="1"/>
             <nvpair id="ma-ms-drbd0-5" name="notify" value="yes"/>
             <nvpair id="ma-ms-drbd0-6" name="globally_unique" value="false"/>
           </attributes>
         </meta_attributes>
         <primitive id="drbd0" class="ocf" provider="heartbeat" type="drbd">
           <instance_attributes id="ia-drbd0">
             <attributes>
               <nvpair id="ia-drbd0-1" name="drbd_resource" value="drbd0"/>
             </attributes>
           </instance_attributes>
         </primitive>
       </master_slave>
       <primitive class="ocf" provider="heartbeat" type="Filesystem" id="fs0">
         <meta_attributes id="ma-fs0">
           <attributes/>
         </meta_attributes>
         <instance_attributes id="ia-fs0">
           <attributes>
             <nvpair id="ia-fs0-1" name="fstype" value="ext3"/>
             <nvpair id="ia-fs0-2" name="directory" value="/drbd"/>
             <nvpair id="ia-fs0-3" name="device" value="/dev/drbd0"/>
           </attributes>
         </instance_attributes>
       </primitive>
     </resources>
     <constraints>
       <rsc_location id="rsc_location_group_1" rsc="ms-drbd0">
         <rule id="prefered_location_group_1" role="Master" score="100">
           <expression id="prefered_location_group_1_expr" attribute="#uname" operation="eq" value="host_m"/>
         </rule>
       </rsc_location>
       <rsc_order id="drbd0_before_fs0" from="fs0" action="start" to="ms-drbd0" to_action="promote"/>
       <rsc_colocation id="fs0_on_drbd0" to="ms-drbd0" to_role="master" from="fs0" score="infinity"/>
     </constraints>
   </configuration>
</cib>

その後、同じディレクトリにあるcib.xml.sig、cib.xml.last、cib.xml.sig.lastを削除しておきます。cib.xmlの変更と上記ファイルの削除は、host_m、host_sの双方で行います。

DRBDとの連携起動

host_m、host_sのどちらで作業を行っても構いませんが、本編では先ずhost_mで作業をします。heartbeatのサービスを起動させる前に、drbdのサービスを起動させます。drbdのサービスは、host_sと同時に上げても構いませんし、host_mだけでも問題ありません。host_mだけの場合は前述のように、host_s側を待たせないようにします。
< # /etc/init.d/drbd start >
特にPrimaryにする等の作業は必要ありません。こういった作業はHeartbeatが肩代りしてくれます。次にheartbeatサービスを起動します。

< # /etc/init.d/heartbeat start >
しばらくすると、サービスが起動しますが、状況を確認する為に、< # crm_mon -i 3 >のようにモニタリングします。正常に起動するとdrbd部がMasterのように表示され、/drbdにファイルシステムがマウントされていると思います。
更に、host_s側でもdrbd、heartbeatサービスを起動します。正常に起動するとhost_mでのcrm_monでの表示が変わります。次のテストの為に、host_s側でもcrm_monで状態を表示させておきます。ここで、先に起動したhost_m側のheartbeatサービスを停止させます。すると、host_m側のcrm_monの表示に異常が出、host_s側の表示に変更があります。host_s側のdrbd部がMasterになり、/drbdにファイルシステムがマウントされていると思います。
以上でテストは成功です。失敗している時はどこかで設定にミスがないか確認してください。

終わりに

以上の解説で、もっとも単純なDRBD + Heartbeatの設定が行えました。ここまでで説明した点は、実に単純な構成なものですが、NFS、Apache、それに付随したIPアドレスの共有等にいたる基本となります。逆にいいますと、サービスを追加していくには、設定したcib.xmlに更に付け足していくことにより可能となっています。