さて、第2回 では単純な1+1構成と簡単なリソースの起動を試してみましたが、今回はスプリットブレイン対策を考えてみたいと思います。
スプリットブレインって?
Pacemakerを設定する上で欠かせないのがスプリットブレイン対策です。スプリットブレインとはインターコネクト(ハートビート)通信が全て切断された状態のことです。
通常はあるサーバ(DCと呼ぶ)のPacemakerがクラスタ全体の指揮をとっていますが、スプリットブレインになると、各サーバのPacemakerが勝手に指揮をとり始めます。そうなると最悪の場合、各サーバでリソースが起動し、リソースの種類によってはデータの破壊やIPアドレスの競合といった状態を引き起こしてしまいます。
図1 スプリットブレイン
こういった状態を避けるためにインターコネクト用LANは冗長化することが望ましいのですが、それでもスプリットブレインになった時の対策として、Pacemakerの機能であるSTONITHや、リソースエージェント(RA)のsfex, VIPcheckを紹介します。
STONITH
STONITHはスプリットブレイン対策として最も有効な機能のひとつで、スプリットブレインになった場合に、強制的に相手のサーバをフェンシング (再起動) することで、最悪の事態を回避します。
この機能を使うには、相手から電源を落としてもらうためのハードウェア制御ボードが必要になります。現在、標準規格のIPMIをはじめ、HP社製サーバ搭載のiLO, IBM社製サーバ搭載のIMM等、複数の制御ボードに対応しており、それぞれのハードウェアに対応したプラグインが提供されています。どのようなプラグインが用意されているかは、以下のコマンドで確認できます。
# crm ra list stonith
なお上記コマンドで表示されるプラグインは、実際に電源を制御する実プラグイン以外に、STONITHの動作を補助するためのプラグインもあり、実際にはこれら補助プラグインと実プラグインを連携させて制御します。
では実際に設定してみましょう。クラスタ制御機能(Heartbeat)の設定は、第2回 の設定を使用してください。今回は標準規格のIPMIを例に説明していきます。また説明をわかりやすくするために、他のリソースや補助プラグインは動かさず、実プラグインのみを動作させます。
ネットワーク構成はSTONITH専用にインターコネクト用LANとは別のインターフェースを用意し、相手のサーバのIPMIボードと接続してください。またIPMIボードには固定IPを割り振り、電源制御できるアカウントを用意しておいてください。今回は次のような設定を前提とします。
図2 STONITHの構成
表1 ネットワーク設定
IPMIボード IPアドレス IPMIボード ユーザID IPMIボード パスワード
pm01 192.168.100.1 ipmiuser1 ipmipass1
pm02 192.168.100.2 ipmiuser2 ipmipass2
まず、環境によってはIPMI操作用のコマンドがインストールされていない可能性がありますので、OpenIPMI-toolsをインストールします。
(各サーバで実行)
# yum -y install OpenIPMI-tools
第2回 のリソース制御機能(Pacemaker)の設定が残っている場合は一旦Pacemakerを停止し、設定をクリアします。第2回 ではcrmコマンドでクリアしましたが、今回はファイルを削除する方法でやってみます。
(各サーバで実行)
# /etc/init.d/heartbeat stop
(各サーバで実行)
# rm -f /var/lib/heartbeat/crm/*
# /etc/init.d/heartbeat start
空っぽの状態でPacemakerが起動し、両サーバがOnlineになったことを確認します。
# crm_mon -A
============
省略
============
Online: [ pm01 pm02 ]
Node Attributes:
* Node pm02:
+ pm01-eth1 : up
+ pm01-eth2 : up
* Node pm01:
+ pm02-eth1 : up
+ pm02-eth2 : up
では設定していきます。設定には通常のリソース設定と同様にcrmコマンドを使用します。crmコマンドって何?という人は第2回 を参照してください。今回は対話モードを使って設定してみたいと思います。
# crm configure
crm(live)configure#
まずはクラスタ全体の設定です。上記プロンプトで以下の設定を入力します。
property $id="cib-bootstrap-options" \
no-quorum-policy="ignore" \
stonith-enabled="true" \
startup-fencing="false"
rsc_defaults resource-stickiness="INFINITY" \
migration-threshold="1"
stonith-enabled="true" で、STONITH機能を有効にします。startup-fencingは、Pacemaker起動時に相手のサーバの状態が把握できない場合に念のために相手をフェンシングする機能で、起動時にすでにスプリットブレインになっていた場合などに有効に働きます。今回はfalse(無効)を使用します。no-quorum-policyは第2回 の時と同様、2台構成の場合はおまじないと思って、ignoreを設定しておいてください。rsc_defaultsの設定も第2回 と同様に設定します。
次にプラグインの設定です。今回はIPMIなので、external/ipmiというプラグイン(以下ipmiプラグイン)を使用します。なお、実際のプラグインの置き場所は64bit環境の場合/usr/lib64/stonith/plugins/ になります。では、ipmiプラグインにどのようなパラメータが必要なのか調べます。
# crm ra info stonith:external/ipmi
IPMI STONITH external device (stonith:external/ipmi)
ipmitool based power management. Apparently, the power off
method of ipmitool is intercepted by ACPI which then makes
a regular shutdown. If case of a split brain on a two-node
it may happen that no node survives. For two-node clusters
use only the reset method.
Parameters (* denotes required, [] the default):
hostname (string): Hostname
The name of the host to be managed by this STONITH device.
ipaddr (string): IP Address
The IP address of the STONITH device.
userid (string): Login
The username used for logging in to the STONITH device.
passwd (string): Password
The password used for logging in to the STONITH device.
interface (string, [lan]): IPMI interface
IPMI interface to use, such as "lan" or "lanplus".
stonith-timeout (time, [60s]):
How long to wait for the STONITH action to complete. Overrides the stonith-timeout cluster property
priority (integer, [0]):
The priority of the stonith resource. The lower the number, the higher the priority.
Operations' defaults (advisory minimum):
start timeout=60
stop timeout=15
status timeout=60
monitor_0 interval=3600 timeout=60
7つのパラメータがあるようです。
ではipmiプラグインを追加してみましょう。まずはpm01をフェンシングするためのリソース設定を追加します。
primitive stonith1 stonith:external/ipmi \
params \
userid="ipmiuser1" \
passwd="ipmipass1" \
ipaddr="192.168.100.1" \
hostname="pm01" \
interface="lanplus" \
op start interval="0s" timeout="60s" on-fail="restart" \
op monitor interval="300s" timeout="60s" on-fail="restart" \
op stop interval="0s" timeout="60s" on-fail="ignore"
"stonith1"は、このリソースを識別するIDで任意の文字列です。useridやpasswd, ipaddrには、IPMIボードに設定した情報を記述します。また、hostnameにはこの設定でフェンシングできるサーバ名 "pm01"を設定します。interfaceは、IPMIのバージョンに依存し、バージョン2.0の場合lanplus, バージョン1.5の場合lanを指定します。
同様にpm02をフェンシングするためのリソース設定を追加します。
primitive stonith2 stonith:external/ipmi \
params \
userid="ipmiuser2" \
passwd="ipmipass2" \
ipaddr="192.168.100.2" \
hostname="pm02" \
interface="lanplus" \
op start interval="0s" timeout="60s" on-fail="restart" \
op monitor interval="300s" timeout="60s" on-fail="restart" \
op stop interval="0s" timeout="60s" on-fail="ignore"
コラム1:IPMIボードないけどちょっとSTONITH試したい!
Pacemakerリポジトリパッケージに入っているcluster-glue-libs-develというパッケージ に external/sshというプラグインが入っています。相手のサーバにパスフレーズなしでsshログインできるようにしておけば、このプラグインは相手のサーバにsshログインし、コマンドで電源を落としてくれます。ただしログインできないような故障だと動作できないのであくまでお試し用と考え、実際の環境で使うのは避けましょう。
その他、仮想環境ではXenに対応したxen0(本体同梱) やXen, KVMに対応したlibvirt(開発中)というプラグインもあります。
以下にsshプラグインを使う場合のリソース設定例を載せておきます。
primitive stonith1 stonith:external/ssh \
params \
livedangerously="yes" \
hostlist="pm01" \
op start interval="0s" timeout="60s" on-fail="restart" \
op monitor interval="300s" timeout="60s" on-fail="restart" \
op stop interval="0s" timeout="60s" on-fail="ignore"
primitive stonith2 stonith:external/ssh \
params \
livedangerously="yes" \
hostlist="pm02" \
op start interval="0s" timeout="60s" on-fail="restart" \
op monitor interval="300s" timeout="60s" on-fail="restart" \
op stop interval="0s" timeout="60s" on-fail="ignore"
以上の設定だけで一応STONITHリソースは起動しますが、これだけではSTONITHリソースがどのサーバで起動するかわかりません。Pacemakerは自分のサーバ上のSTONITHリソースで自分のサーバをフェンシングすることができないので、pm01をフェンシングするSTONITHリソースはpm02上で、pm02をフェンシングするSTONITHリソースはpm01上で起動するように制約設定を追加します。
location location-stonith1 stonith1 \
rule 200: #uname eq pm02 \
rule -INFINITY: #uname eq pm01
location location-stonith2 stonith2 \
rule 200: #uname eq pm01 \
rule -INFINITY: #uname eq pm02
200や-INFINITY(-1000000と同等)は優先度を表すスコア値と呼ばれるもので、上3行の意味を要約すると、先ほど設定したstonith1というリソースはホスト名pm02というサーバ上ではスコア値200になり、ホスト名pm01というサーバ上では-INFINITY、つまりリソース起動禁止となります。
以上で設定完了です。設定を反映させ、設定モードを終了します。
crm(live)configure# commit
crm(live)configure# exit
実際にSTONITHリソースが起動したかどうか確認してみましょう。
# crm_mon
============
省略
============
Online: [ pm01 pm02 ]
stonith1 (stonith:external/ipmi): Started pm02
stonith2 (stonith:external/ipmi): Started pm01
stonith1, stonith2が、pm02, pm01でStartedになり、無事意図したサーバで起動しました。
実際にインターコネクト通信のケーブルを全部抜いて、フェンシングが実行されれば成功です。通信断検知直後(スプリットブレイン状態時)は相手のサーバはUNCLEANという状態になり、フェンシングが成功するとOFFLINEになります。
# crm_mon
============
省略
============
Online: [ pm01 ]
OFFLINE: [ pm02 ]
stonith2 (stonith:external/ipmi): Started pm01
なお、STONITHは通常のリソースの故障にも使うことができますので紹介しておきます。第2回 の仮想IPの設定を例にすると、以下のような設定があったと思います。
primitive vip ocf:heartbeat:IPaddr2 \
params ip="192.168.68.100" \
nic="eth0" cidr_netmask="24" \
op monitor interval="10s"
この"op" の設定には故障時の動作をon-failで定義することができます。たとえば以下のように op stop のon-failにfenceという設定をすると、リソースの停止失敗時に、STONITHでフェンシングすることできます。これによりフェイルオーバ中の中途半端な状態で止まってしまうことを防ぐことができます。第2回 の設定と組み合わせてチャレンジしてみてください。
primitive vip ocf:heartbeat:IPaddr2 \
params ip="192.168.68.100" \
nic="eth0" cidr_netmask="24" \
op start interval="0s" on-fail="restart" \
op monitor interval="10s" on-fail="restart" \
op stop interval="0s" on-fail="fence"
コラム2:補助プラグインって?
今回使用したipmiプラグインのように実際に電源を制御する実プラグイン以外に、電源を制御しない補助プラグインというものが存在します。では補助プラグインって何をしてくれるの?という疑問が湧くと思いますので、よく使われる補助プラグイン2つを紹介します。
STONITHは、スプリットブレインが発生した場合、各サーバが相手をフェンシングしようとするため、どちらのサーバが停止するかはタイミング次第です。そこで役に立つのがLinux-HA Japan提供のpm_extrasパッケージに含まれるstonith-helperプラグインです。このプラグインではあるパラメータに任意のコマンドを設定し、その戻り値によって処理を一時停止 (sleep実行)します。つまりこのプラグインを実プラグインの前に実行することで、タイミングを意図的にずらすことができるようになるわけです。その他に相手のサーバとつながっている全ネットワークインターフェースにpingを打ち、フェンシングの必要性可否を判断する機能も備えています。
2つ目は本体同梱のmeatwareというプラグインです。STONITHはフェンシングに失敗すると、成功するまでフェンシングを繰り返してしまいます。そういう場合ユーザが手動で電源を落とす必要がでてきます。ところがPacemakerはユーザが手動で電源を落としたことには気づいてくれないので、次の状態に遷移することができません。そこでmeatwareの出番です。meatwareはmeatclientコマンドが用意されており、このような状態に陥った時にユーザがこのコマンドを実行することで、Pacemakerにフェンシングが成功した旨を通知することができます。その結果次の状態に遷移することができるようになります。
図3
sfex
STONITHはPacemaker本体の機能とプラグインで実現していますが、排他制御を実現するためのリソースエージェント(RA)もいくつか存在します。その代表がsfexです。これは共有ディスクを使用している環境で使用できます。
sfexは起動されると共有ディスク上のsfex専用パーティションに所有権を定期的に書き込みます。この情報を元に、相手のサーバが生きているかどうかを判断します。つまり、相手のサーバのsfexが起動している時に自分のサーバのsfexを起動しようとするとリソース故障状態になります。もちろんsfexは単なるリソースエージェントに過ぎないので、有効に活用するにはsfexを二重起動させたくないリソースと同じグループに入れ、常にsfexを最初に起動するようにします。
なお、sfexや下記で紹介するVIPcheckだけでは、STONITHのようにリソース停止失敗時のサービス停止を防ぐことができないので、STONITHと併用することをお勧めします。なお、以下では説明を簡単にするためにSTONITHは無効にしています。
では、sfexを設定してみましょう。図4のように、ファイルシステムのマウント・アンマウントを実現するFilesystem RAとsfex RAを使い共有ディスクのダブルマウントを防いでみます。
図4 sfexの構成
まずはsfex専用パーティションの用意です。サイズは1024バイトもあれば十分です。fdiskやpartedコマンド等を使って共有ディスク上に用意しておいてください。今回は/dev/sdb1とします。ファイルシステムを作成する必要はなく、代わりに以下のコマンドで初期化します。-n は排他制御したいサーバ間で使う識別番号です。
# sfex_init -n 1 /dev/sdb1
次にリソースの設定を行います。今回、Filesystemリソースは、/dev/sdb2を/mnt/tmpにext3としてマウントするようにしたいと思います。
(どちらかのサーバ上で実行)
# mke2fs -j /dev/sdb2
(各サーバで実行)
# mkdir /mnt/tmp
各サーバでマウントができるか確認しておいてください。その際各サーバで同時にマウント(ダブルマウント)しないように注意してください。では、一旦Pacemakerの設定はクリアします。
(各サーバで実行)
# /etc/init.d/heartbeat stop
(各サーバで実行)
# rm -f /var/lib/heartbeat/crm/*
# /etc/init.d/heartbeat start
Pacemaker起動後、crmコマンドで設定していきます
# crm configure
crm(live)configure#
以下の設定を投入します。
property $id="cib-bootstrap-options" \
no-quorum-policy="ignore" \
stonith-enabled="false" \
startup-fencing="false"
primitive sfex ocf:heartbeat:sfex \
params \
index="1" \
device="/dev/sdb1" \
op start interval="0s" timeout="120s" on-fail="restart" \
op monitor interval="10s" timeout="60s" on-fail="restart" \
op stop interval="0s" timeout="60s" on-fail="block"
primitive filesystem ocf:heartbeat:Filesystem \
params \
fstype="ext3" \
device="/dev/sdb2" \
directory="/mnt/tmp" \
op start interval="0s" timeout="60s" on-fail="restart" \
op monitor interval="10s" timeout="60s" on-fail="restart" \
op stop interval="0s" timeout="60s" on-fail="block"
group group1 sfex filesystem
sfexのindexパラメータにsfex_init実行時に設定した識別番号を、deviceパラメータに用意したsfex専用パーティションを設定します。またgroupの設定により、リソースの起動順番はsfex, filesystemとなり、sfexが起動成功しない限りファイルシステムがマウントされることはありません。
ではcommitで設定反映します。
crm(live)configure# commit
以下のようにリソースが起動すれば成功です。
# crm_mon
============
省略
============
Online: [ pm01 pm02 ]
Resource Group: group1
sfex (ocf::heartbeat:sfex): Started pm01
filesystem (ocf::heartbeat:Filesystem): Started pm01
ではここでインターコネクト通信を全て抜いて、スプリットブレインを発生させて見ましょう。今回はSTONITHが動いていないので、各サーバで以下のような表示になります。
pm01側の表示
============
省略
Current DC: pm01 (519bb7a2-3c31-414a-b6b2-eaef36a09fb7) - partition with quorum
省略
============
Online: [ pm01 ]
OFFLINE: [ pm02 ]
Resource Group: group1
sfex (ocf::heartbeat:sfex): Started pm01
filesystem (ocf::heartbeat:Filesystem): Started pm01
pm02側の表示
pm02# crm_mon
============
省略
Current DC: pm02 (8c93dc22-a27e-409b-8112-4073de622daf) - partition with quorum
省略
============
Online: [ pm02 ]
OFFLINE: [ pm01 ]
Failed actions:
sfex_start_0 (node=pm02, call=4, rc=1, status=complete): unknown error
pm01側では今までリソースが起動していたので、そのまま起動し続けますが、pm02側ではsfexの起動故障が発生(Faild actionsのsfex_start_0の行)し、filesystemの起動を見事抑止してくれました。なお、あえてヘッダ部分の表示を残していますが、このようにpm01側では自分がクラスタ全体の指揮している(DC)と表示され、pm02側も自分がDCだと表示されます。これがスプリットブレインになっている証拠になります。
VIPcheck
最後に、排他制御を実現するもう一つのリソースエージェントVIPcheckを紹介します。これはLinux-HA Japan提供のpm_extrasパッケージに入っており、主に仮想IP(IPaddrやIPaddr2 RA)を使用している場合に使用可能です。
動作イメージはsfexと同じで、sfexの場合は共有ディスクを参照して相手の状態を確認しますが、VIPcheckは仮想IPを参照(ping)して相手の状態を確認します。具体的には仮想IPに対してpingを打ち、応答があれば相手のサーバでリソースが起動していると判断し、自分のサーバのVIPcheckは起動できずリソース故障状態になります。
図5 VIPcheckの構成
なお、sfexの場合、共有ディスクのケーブルが抜けて、ディスクにアクセスできない場合に起動できないのに対し、VIPcheckはネットワークケーブルが抜けてpingに応答しない場合に起動成功するので、残念ながらsfexに比べて信頼性は低いと言えるでしょう。リソース設定イメージはsfexと同じなので、今回は紹介だけにとどめておきます。
まとめ
第3回では構築応用編としてスプリットブレイン対策の機能、設定例を紹介しました。
最初からいろいろと設定された複雑な構成を見ると、Pacemakerの設定は難しそうなイメージを抱く人が多いのですが、このように一つ一つの機能を分解して見ると結構簡単ではなかったでしょうか。いよいよ次回からは運用編として、いろいろな故障を起こしてみたり、その時の復旧方法を紹介したりする予定ですのでお楽しみに。