- 2011/08/04 17:50 クラスタの基本構成まで書いた。
- 2011/08/05 18:50 サービスリソースの構成も書いた。
前提ソフトウェア
# yum groupinstall "High Availability"High Availabilityグループで入るのは下記のパッケージ︵とその前提パッケージ︶なので、Fedoraでがんばる方はこれらと同等パッケージをご使用ください。
# rpm -q cman ccs omping rgmanager cman-3.0.12-41.el6_1.1.x86_64 ccs-0.16.2-35.el6.x86_64 omping-0.0.1-4.el6.x86_64 rgmanager-3.0.12-11.el6_1.1.x86_64
VM環境の準備
![f:id:enakai00:20110804143052p:image:w640 f:id:enakai00:20110804143052p:image:w640](http://cdn-ak.f.st-hatena.com/images/fotolife/e/enakai00/20110804/20110804143052.png)
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.7.201 node01 192.168.7.202 node02 192.168.8.201 node01m 192.168.8.202 node02m 192.168.9.201 node01h 192.168.9.202 node02h・両ノードのrootユーザ同士でSSHの公開鍵認証を設定して、パスワード無しのSSHが打てるようにしておく。
共有ストレージの準備
# yum install scsi-target-utils # mkdir -p /var/lib/tgtd/cluster01 # cd /var/lib/tgtd/cluster01 # dd if=/dev/zero of=volume01.img bs=1M count=100 # dd if=/dev/zero of=volume02.img bs=1M count=1000targetedモードでSELinuxを動かしている場合は、Volumeファイルは/var/lib/tgtd/以下に置く必要があるので注意してください。続いて、/etc/tgt/targets.confの末尾に下記を追加します。
<target iqn.2011-08.com.example.yourhost:tgt01> backing-store /var/lib/tgtd/cluster01/volume01.img backing-store /var/lib/tgtd/cluster01/volume02.img </target>最後にtgtdサービスを起動します。
# chkconfig tgtd on # service tgtd start # tgt-admin -s Target 1: iqn.2011-08.com.example.yourhost:tgt01 System information: Driver: iscsi State: ready I_T nexus information: LUN information: LUN: 0 Type: controller SCSI ID: IET 00010000 SCSI SN: beaf10 Size: 0 MB, Block size: 1 Online: Yes Removable media: No Readonly: No Backing store type: null Backing store path: None Backing store flags: LUN: 1 Type: disk SCSI ID: IET 00010001 SCSI SN: beaf11 Size: 105 MB, Block size: 512 Online: Yes Removable media: No Readonly: No Backing store type: rdwr Backing store path: /var/lib/tgtd/cluster01/volume01.img Backing store flags: LUN: 2 Type: disk SCSI ID: IET 00010002 SCSI SN: beaf12 Size: 1049 MB, Block size: 512 Online: Yes Removable media: No Readonly: No Backing store type: rdwr Backing store path: /var/lib/tgtd/cluster01/volume02.img Backing store flags: Account information: ACL information: ALL上記のようにvolume01.imgとvolume02.imgがLUNとして構成されていればOKです。それぞれこの後で、Quorum Diskと共有データ領域として使用します。 node01とnode02では、それぞれ次の手順でiSCSI LUNを認識させます。
# chkconfig iscsi # service iscsi start # iscsiadm -m discovery --type sendtargets --portal 192.168.8.1 # service iscsi restartfdiskで見て、100MBの/dev/sdaと1GBの/dev/sdbが認識されていればOKです。︵仮想マシンに接続した仮想ディスクは、virtioドライバを使っているので/dev/vdXXの前提です。︶なお、iSCSIについては、プロのためのLinuxシステム構築・運用技術の第3章に詳しく書いてあります。
クラスタ構成の準備
# chkconfig ricci on # service ricci startまた、リモート管理の際にricciユーザのパスワードで認証するため、事前にパスワードの設定が必要です。
# passwd ricciクラスタのトポロジーを管理するcmanとリソースの監視を行うrgmanagerは自動起動しないようにします。障害などでノードが再起動した際に、障害が残ったノードが勝手にクラスタに参加するのを防ぐためです。
# chkconfig cman off # chkconfig rgmanager offクラスタを起動・停止するためのスクリプトを4つ用意します。それぞれ、ローカルノードのクラスタの開始・停止と、全ノードのクラスタの開始・停止です。 /usr/local/bin/clstart
#!/bin/sh service cman start service rgmanager start/usr/local/bin/clstop
#!/bin/sh service rgmanager stop service cman stop/usr/local/bin/clstart_all
#!/bin/sh ssh node01 /usr/local/bin/clstart & ssh node02 /usr/local/bin/clstart & wait/usr/local/bin/clstop_all
#!/bin/sh ssh node01 /usr/local/bin/clstop & ssh node02 /usr/local/bin/clstop & wait実行権も忘れずに設定します。
# chmod u+x /usr/local/bin/clst*続いて、Quorum Diskをフォーマットします。これは、node01からのみ実施します。
# mkqdisk -c /dev/sda -l qdisk01 mkqdisk v3.0.12 Writing new quorum disk label 'qdisk01' to /dev/sda. WARNING: About to destroy all data on /dev/sda; proceed [N/y] ? y Warning: Initializing previously initialized partition Initializing status block for node 1... (中略) Initializing status block for node 15... Initializing status block for node 16...メモメモ Quorum Diskは、各ノードが定期的に生存情報を書き込むことで、お互いの状態を確認しあいます。このコマンドの出力を見ると16ノード分の﹁状態書き込みエリア﹂が確保されていることが分かります。現在の仕様では、Quorum Diskを使用する場合は最大16ノード構成になるため、ここでは最大ノード数分のエリアを確保しています。 両方のノードで次のコマンドを実行して、Quorum Diskとして認識されることを確認します。
# mkqdisk -L mkqdisk v3.0.12 /dev/block/8:0: /dev/disk/by-id/scsi-1IET_00010001: /dev/disk/by-path/ip-192.168.8.1:3260-iscsi-iqn.2011-08.com.example.yourhost:tgt01-lun-1: /dev/sda: Magic: eb7a62c2 Label: qdisk01 Created: Thu Aug 4 16:37:37 2011 Host: node01 Kernel Sector Size: 512 Recorded Sector Size: 512データ領域の共有ディスクをフォーマットします。これもnode01のみで実施します。
# mkfs.ext4 /dev/sdb両方のノードで/data01にマウントできることを確認します。両ノードで同時にマウントしないように注意してください。
# mkdir /data01 # mount /dev/sdb /data01 # umount /data01
クラスタ構成ファイルの作成
<?xml version="1.0"?> <cluster config_version="1" name="cluster01"> <cman expected_votes="3"/> <clusternodes> <clusternode name="node01h" nodeid="1" votes="1"> <fence> <method name="virsh_reboot"> <device name="kvmhost01" port="RHCSvm01"/> </method> </fence> </clusternode> <clusternode name="node02h" nodeid="2" votes="1"> <fence> <method name="virsh_reboot"> <device name="kvmhost01" port="RHCSvm02"/> </method> </fence> </clusternode> </clusternodes> <totem token="20000"/> <quorumd interval="1" label="qdisk01" master_wins="1" tko="10" votes="1"/> <fencedevices> <fencedevice name="kvmhost01" agent="fence_virsh" ipaddr="192.168.8.1" login="root" passwd="XXXXX" option="reboot"/> </fencedevices> </cluster>ポイントだけ簡単に説明します。
Quorumの設定
Quorumはハートビートネットワークが分断して、クラスタが複数の島に分かれたときに生き残る島を決定する仕組みです。これには、島が持っている"votes"の値を計算する必要があります。(2ノード構成の場合は、1対1に分かれるしかないのであまり深い意味はありませんが・・・。)
まず、各ノードは1vote持っており、Quorum Diskも1vote持っているので、すべてが正常に稼働している時はクラスタ全体で3votesになります。これをここで指定します。
<cman expected_votes="3"/>
クラスタに参加するノードの設定
"clusternode"タグに1ノードずつ記載します。
<clusternode name="node01h" nodeid="1" votes="1"> <fence> <method name="virsh_reboot"> <device name="kvmhost01" port="RHCSvm01"/> </method> </fence> </clusternode>
nameオプションは、ハートビートネットワークのアダプタ名を指定します。nodeidは重複しない値を指定すること。
fenceタグは、ハートビートが切断するなどして、クラスタマネージャがこのサーバを強制再起動すると判断した時に用いる再起動方法です。node01が障害と判断すると、node02がここに指定された方法でnode01を再起動します。したがって、この方法はnode02から実行できる必要があります。ここで指定するmethodとdeviceの実体は、この後のfencedeviceで定義されます。
<fencedevices> <fencedevice name="kvmhost01" agent="fence_virsh" ipaddr="192.168.8.1" login="root" passwd="XXXXX" option="reboot"/> </fencedevices>
ここでは、KVMのホストLinuxにlibvirtで接続して、VMを強制再起動するという仕組みを用いています。先に説明したように、ハートビート・ネットワークが切れているかもしれない状況で実施するものですので、ハートビートネットワークとは独立した管理ネットワーク経由で接続するようにIPを指定しています。ホストLinuxのrootパスワードが入っているのが気になる人は、SSH公開鍵認証も利用できます。passwdオプションの代わりにidentity_fileオプションで秘密鍵を指定します。先のclusternode側の設定にあるportオプションはlibvirtから見えるVM名を指定します。
Quorum Diskの設定
Quorum Diskに関する設定はここです。
<totem token="20000"/> <quorumd interval="1" label="qdisk01" master_wins="1" tko="10" votes="1"/>
各ノードは、interval(1秒)ごとにQuorum Diskに生存情報を書き込みます。tko(10回)連続して生存情報が確認されないノードは死亡したと判断されて、先のFencedeviceで強制再起動されます。あるいは、Quorum Diskにtko回連続で書き込めないことに自分で気づいた場合は、自発的に再起動します。つまり、Quorum Diskによる障害検知は10秒以内に行われます。Quorum Diskは、ハートビートよりも"確実"な障害検知を提供する仕組みなので、ハートビート切断による障害検知は、これより遅くする必要があります。
Quroum Disk的にはノードは生きているのに、ハートビート切断が起きた場合にどうなるか。。。。ですが、ここでは、master_winsオプションを指定しているので、内部的に決定されるマスターノードが生き残って、相手のノードは強制再起動されます。
ちなみに・・・・
あまり推奨される構成ではありませんが、サービスネットワークとハートビートネットワークを兼用する構成の場合、この方法では困ることがあります。例えば、サービス用のNICの障害でハートビートが切れた場合、どちらになるかよく分からない非マスターノードではなくて、NIC障害がおきたノードの方に死亡してもらう必要があります。このような場合は、master_winsオプションを外して、代わりに、heuristicを指定します。
<quorumd interval="1" tko="10" votes="1" label="qdisk01"> <heuristic program="/root/bin/pingcheck.sh" score="1" interval="2" tko="3"/> </quorumd>
programで指定されたシェルをinterval(2秒)ごとに実行して、tko(3回)連続して0以外のリターンコードを返すとそのノードは自発的に死亡します。例えば、ゲートウェイにpingが通るか確認するシェルを利用すれば、NIC障害のノードが自爆して、もう一方のノードが生き残ります。
なお、cluster.confに文法的な間違いがないかどうかは、次のコマンドで確認ができます。
# ccs_config_validate Configuration validates
クラスタの起動
# clstart_all Starting cluster: Checking if cluster has been disabled at boot... [OK] Checking Network Manager... Starting cluster: Checking if cluster has been disabled at boot... [OK] Checking Network Manager... [OK] Global setup... [OK] Loading kernel modules... [OK] Global setup... [OK] Loading kernel modules... [OK] Mounting configfs... [OK] Starting cman... [OK] Mounting configfs... [OK] Starting cman... [OK] Starting qdiskd... [OK] Starting qdiskd... [OK] Waiting for quorum... [OK] Starting fenced... [OK] Starting dlm_controld... [OK] Waiting for quorum... [OK] Starting fenced... [OK] Starting dlm_controld... [OK] Starting gfs_controld... [OK] Unfencing self... [OK] Joining fence domain... [OK] Starting gfs_controld... [OK] Unfencing self... [OK] Joining fence domain... [OK] Starting Cluster Service Manager: [OK] [OK] Starting Cluster Service Manager: [OK]両ノードの/var/log/messagesをじっくり眺めてクラスタの起動の様子を堪能してください。起動が完了したら次のコマンドで状態を確認します。
# clustat Cluster Status for cluster01 @ Thu Aug 4 17:40:28 2011 Member Status: Quorate Member Name ID Status ------ ---- ---- ------ node01h 1 Online, Local node02h 2 Online /dev/block/8:0 0 Online, Quorum Disk # cman_tool status Version: 6.2.0 Config Version: 1 Cluster Name: cluster01 Cluster Id: 8208 Cluster Member: Yes Cluster Generation: 12 Membership state: Cluster-Member Nodes: 2 Expected votes: 3 Quorum device votes: 1 Total votes: 3 Node votes: 1 Quorum: 2 Active subsystems: 10 Flags: Ports Bound: 0 177 Node name: node01h Node ID: 1 Multicast addresses: 239.192.32.48 Node addresses: 192.168.9.121メモメモ 上記のコマンド出力の最後にMulticast addressが表示されているのは、ハートビートにマルチキャストを利用しているためです。実環境では、ハートビート・ネットワークのスイッチは、マルチキャストを通すように設定が必要です。 また、ここではシェルスクリプトとSSHを利用して、両方のノードのクラスタサービスを同時に起動している点に注意してください。1ノードずつ順番にクラスタサービスを起動してはいけません。1ノードだけクラスタサービスを起動すると、相手ノードの状態が分からないので、ノード障害と誤検知して、相手ノードの強制再起動を実行してしまいます。 ・・・・いま、﹁あー。誤検知するのか。だめだなぁ﹂と思ったあなたは反省してください。仮に、相手ノードが障害で一時的にフリーズ状態だったらどうなるでしょう? 強制再起動せずにほっておいて、そのうちフリーズから回復して、突然、両ノードから共有ファイルにアクセスしたらどうなるでしょう??? HAクラスタは障害が発生している状況の下でその役割を果たすソフトウェアですので、常に安全サイドを考えて動作します。HAクラスタを運用する際は、クラスタの仕組みを理解した上で、常にそれぞれのノードの状態を考えながら操作してください。 この後は、それぞれのノードでハートビートネットワークのアダプタをifdownするなどして、擬似ハートビート障害を起こして何がおきるか確認してください。Quorum Diskへのアクセス障害を起こしたい時は、iptablesでiSCSIパケットをブロックするなどしてください。
# iptables -A INPUT -m tcp -p tcp --sport 3260 -j REJECT擬似障害で強制再起動されたノードは、再起動後に次のコマンドで自ノードのクラスタサービスを起動すると再びクラスタに参加します。
# clstart Starting cluster: Checking if cluster has been disabled at boot... [ OK ] Checking Network Manager... [ OK ] Global setup... [ OK ] Loading kernel modules... [ OK ] Mounting configfs... [ OK ] Starting cman... [ OK ] Starting qdiskd... [ OK ] Waiting for quorum... [ OK ] Starting fenced... [ OK ] Starting dlm_controld... [ OK ] Starting gfs_controld... [ OK ] Unfencing self... [ OK ] Joining fence domain... [ OK ] Starting Cluster Service Manager: [ OK ]
サービスリソースの定義
<rm> <failoverdomains> <failoverdomain name="dom01" ordered="1" restricted="1"> <failoverdomainnode name="node01h" priority="1"/> <failoverdomainnode name="node02h" priority="2"/> </failoverdomain> </failoverdomains> <service autostart="0" domain="dom01" name="service01"> <ipaddress="192.168.7.99" monitor_link="on"/> <fsdevice="/dev/sdb" fstype="ext4" mountpoint="/data01" name="data_fs"> <script file="/etc/init.d/myappl" name="myappl"/> </fs> </service> </rm>例によってポイントだけ。
failoverドメイン
serviceタグ
設定変更の反映
<cluster config_version="2" name="cluster01">node01で次のコマンドを実行します。
# cman_tool version -rパスワードの入力を求められた場合は、先に設定したricciユーザのパスワードを入力します。cluster.confが自動的にコピーされて設定が反映されます。次のコマンドで各ノードが認識している現在の設定が確認できます。
# ccs_config_dumpもちろんクラスタサービスを停止して、cluster.confを手で各ノードにコピーしてもかまいません。
サービスの起動
# clustat Cluster Status for cluster01 @ Thu Aug 4 18:34:23 2011 Member Status: Quorate Member Name ID Status ------ ---- ---- ------ node01h 1 Online, Local, rgmanager node02h 2 Online, rgmanager /dev/block/8:0 0 Online, Quorum Disk Service Name Owner (Last) State ------- ---- ----- ------ ----- service:service01 (none) disabledサービスは定義されていますが、disabledになっています。これは、autostart="0"を指定しているので自動起動しないためです。次のコマンドでservice01を起動(enable)します。
# clusvcadm -e service01 Local machine trying to enable service:service01...Success service:service01 is now running on node01hきちんと起動しました。
# clustat Cluster Status for cluster01 @ Thu Aug 4 18:34:46 2011 Member Status: Quorate Member Name ID Status ------ ---- ---- ------ node01h 1 Online, Local, rgmanager node02h 2 Online, rgmanager /dev/block/8:0 0 Online, Quorum Disk Service Name Owner (Last) State ------- ---- ----- ------ ----- service:service01 node01h startedここでは、コマンドを実行したローカルノード︵node01h︶でサービスが起動していますが、-mオプションでサービスを起動するノードを明示することもできます。 サービスの手動引き継ぎと停止は次のとおりです。
# clusvcadm -r service01 Trying to relocate service:service01...Success service:service01 is now running on node02h # clusvcadm -d service01 Local machine disabling service:service01...Success先ほどと同様に擬似的に障害を起こして、きちんと引き継ぎが行われることを確認してください。 意図通りにサービスが起動しない場合は、次のコマンドでサービスの定義内容がどのように解釈されているかを確認することができます。
# rg_test test /etc/cluster/cluster.conf同じく、各リソースの起動・停止順序が次のコマンドで表示されます。
# rg_test noop /etc/cluster/cluster.conf start service service01 # rg_test noop /etc/cluster/cluster.conf stop service service01