PacemakerのQuorumを試してみる

クラスタ管理の中核を担うPacemakerには、クラスタ全体の安定性とデータ整合性を維持するための重要な仕組みの一つとして「Quorum(過半数)」があります。Quorumは、クラスタ内でのノード数や状況に応じて、どのようにサービスを継続または停止するかを判断する役割を果たします。この機能を適切に設定し運用することで、障害発生時にもクラスタ全体が不要な分断やデータ不整合を回避できるようになります。

本記事では、Quorumの基本的な概念を解説するとともに、実際にPacemaker上で設定や動作を試してみる手順を詳しくご紹介します。クラスタシステムの信頼性を高めたいと考えている方にとって、Quorumの動作を理解し、効果的に運用できるようになることは非常に有益です。それでは、具体的な検証を進めながら、PacemakerのQuorumを深掘りしていきましょう!

構成

検証にはCorosyncとPacemakerのバージョンが、Corosync 3.1.0 、Pacemaker 2.0.5の環境を使いました。
※LINBITのデモライセンスを使うと、これが最新のバージョンになります。

仮想環境に3ノードのLinuxゲストOSを構築して、ホスト名とIPアドレスを次のようにします。

ホスト名IPアドレス1IPアドレス2IPアドレス3
node1192.168.3.4610.0.0.4610.0.1.46
node2192.168.3.4710.0.0.4710.0.1.47
node3192.168.3.4810.0.0.4710.0.1.47

ネットワークの構成は下図のようになります。

Corosyncの設定

Corosyncは設定ファイル(/etc/corosync/corosync.conf)を定義して設定します。最低限の設定は次のようになります。

totem {
    version: 2
    cluster_name: cluster2
    secauth: off
    transport: knet
    rrp_mode: passive
}

nodelist {
    node {
        name: node1
        ring0_addr: 10.0.0.46
        ring1_addr: 10.0.1.46
        nodeid: 1
    }
    node {
        name: node2
        ring0_addr: 10.0.0.47
        ring1_addr: 10.0.1.47
        nodeid: 2
    }
    node {
        name: node3
        ring0_addr: 10.0.0.48
        ring1_addr: 10.0.1.48
        nodeid: 3
    }
}

logging {
    to_logfile: yes
    logfile: /var/log/cluster/corosync.log
    to_syslog: yes
}

quorum {
    provider: corosync_votequorum
    expected_votes: 3
}

Corosyncの設定はこちらのページで2ノード構成のCorosync ver 3.0の設定がありますので、比較してみて下さい。nodelist {}node3の設定が追加され、quorum {}設定がexpected_votes: 3に変わっているのが2ノード構成のポイントになります。

Corosyncの動作確認

設定が終わったら次のコマンドを実行してください。コマンドはnode1、node2、node3すべてのノードで実行します。

[root@node1 ~]# systemctl start corosync

Corosyncがちゃんと起動されたかはcorosync-cfgtoolで確認します。このように表示されれば問題ありません。

[root@node1 ~]# corosync-cfgtool -s
Printing link status.
Local node ID 1
LINK ID 0
        addr    = 10.0.0.46
        status:
                nodeid  1:      localhost
                nodeid  2:      connected
                nodeid  3:      connected
LINK ID 1
        addr    = 10.0.1.46
        status:
                nodeid  1:      localhost
                nodeid  2:      connected
                nodeid  3:      connected

nodeid2:、nodeid3がconnectedにならない場合は、node2、node3のCorosyncでエラーが発生していないか、ネットワークの設定が正しいか、ファイヤーウォールが疎通を邪魔していないか等を調べてみて下さい。
なお、以下の表示はnode2のcorosyncが停止している場合の表示例です。

[root@node1 ~]# corosync-cfgtool -s
Printing link status.
Local node ID 1
LINK ID 0
        addr    = 10.0.0.46
        status:
                nodeid  1:      localhost
                nodeid  2:      disconnected
                nodeid  3:      connected
LINK ID 1
        addr    = 10.0.1.46
        status:
                nodeid  1:      localhost
                nodeid  2:      disconnected
                nodeid  3:      connected

Pacemakerの起動と設定入力

systemctlコマンドでPacemakerを起動します。

[root@node1 ~]# systemctl start pacemaker

このコマンドはnode1、node2、node3で実行します。なおPacemakerを起動すると自動的にCorosyncも起動するのですが、今回はCorosyncの動作確認のために、先にCorosyncを起動し動作確認するため別々に起動しています。
Pacemakerの関連プロセスが起動するので、psコマンドで確認してみて下さい。(fオプションをつけて実行します。)

[root@node1 ~]# ps axf
  PID TTY      STAT   TIME COMMAND
    2 ?        S      0:00 [kthreadd]
    4 ?        S<     0:00  \_ [kworker/0:0H]
 ・・・・・・  
 8583 ?        SLsl   0:09 /usr/sbin/corosync -f
 8790 ?        Ss     0:00 /usr/sbin/pacemakerd -f
 8791 ?        Ss     0:00  \_ /usr/libexec/pacemaker/pacemaker-based
 8792 ?        Ss     0:00  \_ /usr/libexec/pacemaker/pacemaker-fenced
 8793 ?        Ss     0:00  \_ /usr/libexec/pacemaker/pacemaker-execd
 8794 ?        Ss     0:00  \_ /usr/libexec/pacemaker/pacemaker-attrd
 8795 ?        Ss     0:00  \_ /usr/libexec/pacemaker/pacemaker-schedulerd
 8796 ?        Ss     0:00  \_ /usr/libexec/pacemaker/pacemaker-controld

また、crm_monでPacemakerの状態を確認すると、node1、node2、node3がOnlineになっていることが判ります。

[root@node1 ~]# crm_mon -frAD1
Cluster Summary:
  * Stack: corosync
  * Current DC: node1 (version 2.0.5.linbit-1.0.el7-ba59be712) - partition with quorum
  * Last updated: Mon Jan 27 17:35:46 2025
  * Last change:  Mon Jan 27 17:35:42 2025 by hacluster via crmd on node1
  * 3 nodes configured
  * 0 resource instances configured

Node List:
  * Online: [ node1 node2 node3 ]

Full List of Resources:
  * No resources

Migration Summary:

3ノード構成のクラスタの動作を確認するため、Dummyリソースエージェントを使って
testリソースを定義します。crm configure editで次のように設定します。

node 1: node1
node 2: node2
node 3: node3
primitive test Dummy \
        op start interval=0s timeout=30s \
        op monitor interval=10s timeout=60s \
        op stop interval=0s timeout=30s
property cib-bootstrap-options: \
        stonith-enabled=false \
        no-quorum-policy=stop \
        have-watchdog=false \
        cluster-infrastructure=corosync \
        cluster-name=cluster2

node情報やpropertyの情報は自動的に設定されるので、入力すべき情報は、
primitive ~ timeout=30sstonith-enable=falseno-quourum-poclicy=stopになります。
設定を入力して保存すると、testリソースが動き始めます。

[root@node1 ~]# crm_mon -frAD1
Cluster Summary:
  * Stack: corosync
  * Current DC: node1 (version 2.0.5.linbit-1.0.el7-ba59be712) - partition with quorum
  * Last updated: Tue Jan 28 13:31:04 2025
  * Last change:  Mon Jan 27 17:59:24 2025 by hacluster via crmd on node1
  * 3 nodes configured
  * 1 resource instance configured

Node List:
  * Online: [ node1 node2 node3 ]

Full List of Resources:
  * test        (ocf::heartbeat:Dummy):  Started node1

Migration Summary:

testリソースはnode1で起動してます。

Quorumのテスト

no-quorum-policyの値で3ノードクラスタはどのように動作するかテストしてみます。
node1はeth1とeth2のネットワークI/Fでnode2、node3と通信しています。このネットワークを
iptablesコマンドでふさぎ、node2、node3からnode1を隔離します。
node1で次のコマンドを実行します。

# eth1の通信を遮断
[root@node1 ~]# iptables -A INPUT -i eth1 -j DROP
[root@node1 ~]# iptables -A OUTPUT -o eth1 -j DROP

# eth2の通信を遮断
[root@node1 ~]# iptables -A INPUT -i eth2 -j DROP
[root@node1 ~]# iptables -A OUTPUT -o eth2 -j DROP

node1のeth1とeth2の通信が塞がれて、node2、node3と通信ができなくなります。

その結果node1のtestリソースは停止して、node2にフェールオーバーします。これはno-quorum-policystopに設定されているからで、node1はクラスターメンバーが1台なのでノード数の過半数を下回ったので停止し、node2、node3のクラスターメンバーは2台なのでこちらでtestリソースが起動しました。
node1でcrm_mon -frADを使ってでクラスターの状態を見ると次のようになります。

Cluster Summary:
  * Stack: corosync
  * Current DC: node1 (version 2.0.5.linbit-1.0.el7-ba59be712) - partition WITHO
UT quorum
  * Last updated: Tue Jan 28 13:46:07 2025
  * Last change:  Mon Jan 27 17:58:54 2025 by root via cibadmin on node1
  * 3 nodes configured
  * 1 resource instance configured

Node List:
  * Online: [ node1 ]
  * OFFLINE: [ node2 node3 ]

Full List of Resources:
  * test        (ocf::heartbeat:Dummy):  Stopped

Migration Summary:

node2でcrm_mon -frADを使ってクラスターの状態を見ると次のようになります。

Cluster Summary:
  * Stack: corosync
  * Current DC: node2 (version 2.0.5.linbit-1.0.el7-ba59be712) - partition with
quorum
  * Last updated: Tue Jan 28 13:53:45 2025
  * Last change:  Mon Jan 27 17:59:24 2025 by hacluster via crmd on node1
  * 3 nodes configured
  * 1 resource instance configured

Node List:
  * Online: [ node2 node3 ]
  * OFFLINE: [ node1 ]

Full List of Resources:
  * test        (ocf::heartbeat:Dummy):  Started node2

Migration Summary:

次にネットワークを元に戻して、node1へtestリソースを戻します。
次のコマンドをnode1で実行してください。

[root@node1 ~]# iptables -D INPUT -i eth1 -j DROP
[root@node1 ~]# iptables -D OUTPUT -o eth1 -j DROP
[root@node1 ~]# iptables -D INPUT -i eth2 -j DROP
[root@node1 ~]# iptables -D OUTPUT -o eth2 -j DROP
[root@node1 ~]# crm resource move test node1
[root@node1 ~]# crm resource clear test

crm resource move~でリソースを移動した後には、必ずcrm resource clear~を実行してください。

次にno-quorum-policy=ignoreを設定します。

[root@node1 ~]# crm configure property no-quorum-policy=ignore

設定後に、node1で次のコマンドを実行します。

# eth1の通信を遮断
[root@node1 ~]# iptables -A INPUT -i eth1 -j DROP
[root@node1 ~]# iptables -A OUTPUT -o eth1 -j DROP

# eth2の通信を遮断
[root@node1 ~]# iptables -A INPUT -i eth2 -j DROP
[root@node1 ~]# iptables -A OUTPUT -o eth2 -j DROP

eth1、eth2の通信が遮断され、通信ができなくなります。この状態でno-quorum-policy=ignoreが設定されているため、node1ではtestリソースが動き続け、node2でもtestリソースが起動します。この現象をスプリットブレインと呼び、サービスが2ノードで起動するため、データ損失のリスクが高まります。しかし、3ノード構成でQuorum設定を適切に利用することで、スプリットブレインの発生を防止できます。