改めて学ぶDRBD Reactor BASIC

以前公開した「DRBD Reactorで作る2ノードNFSクラスター」の記事では、DRBD Reactorを用いた高可用性(HA)クラスタの構築手法をご紹介しました。しかし、NFSサーバーは関連サービスやエクスポート設定など依存関係が多く、DRBD Reactorの「シンプルにサービスを起動・制御する」という基本思想を理解するための最初の一歩としては、少し難易度が高かったかもしれません。

そこで今回は「改めて学ぶDRBD Reactor BASIC」と題し、より構成がシンプルで分かりやすい「MySQL (MariaDB)」を題材に、DRBD Reactorの基本動作とリソース定義のステップを解説します。複雑なクラスターリソースマネージャー(CRM)に比べて、設定が簡素で軽量であるDRBD Reactorの真価を実感していただけるはずです。

1. システム構成の全体像

今回は、タイブレーカー(3台目のディスクレスノード)を用意しない、完全な2ノード構成で解説します。

  • ノード構成: node1 (Active) / node2 (Standby)
  • IPアドレス(サービス用、同期用)
    • node1: 192.168.3.31 / 10.30.0.31
    • node2: 192.168.3.32 / 10.30.0.32
  • DRBDリソース: /dev/drbd0(MariaDBのデータ領域 /var/lib/mysql を同期します)
  • フェンシング: テスト環境で手軽に試せる「sshを使ったフェンシング(自作ラッパースクリプト)」を利用します
  • 管理対象サービス: mariadb.service と クライアント接続用の仮想IP(VIP: 192.168.3.30

2. 事前準備(ステップ1)

DRBDのインストールとリソース作成、および初期同期を行います。

dnf -y install drbd kmod-drbd lvm2 resource-agents drbd-reactor
dnf -y install mariadb-server

DRBDの設定ファイル(/etc/drbd.d/mysql_res.res)は次のようになります。

resource mysql_res {
    net {
        # 通信断時にI/Oを停止してフェンシングを要求する(2ノード構成で必須)
        fencing resource-and-stonith;
    }

    handlers {
        # フェンシング実行時に呼び出すスクリプトを指定
        fence-peer "/usr/local/bin/fence_ssh_wrapper.sh";
    }

    options {
        # DRBD Reactor(Promoter)を正常動作させるための必須設定
        auto-promote no;
        on-suspended-primary-outdated force-secondary;
    }

    volume 0 {
        device    /dev/drbd0;
        disk      /dev/vdb;  # 実際の環境に合わせて変更します。
        meta-disk internal;
    }

    on node1 {
        address   10.30.0.31:7777;
        node-id   0;
    }

    on node2 {
        address   10.30.0.32:7777;
        node-id   1;
    }
}

この設定ファイルを両ノードに配置し、以下のコマンドを node1node2 で実行します。

drbdadm create-md mysql_res
drbdadm up mysql_res

node1 で初期同期を開始します。

drbdadm primary --force mysql_res

初期同期が開始されたら、node1 でファイルシステムの作成とMariaDBのデータディレクトリへのマウントを実行します。

mkfs.xfs /dev/drbd0
mount /dev/drbd0 /var/lib/mysql

ディスクのマウント後、node1 でMariaDBを起動してデータベースを初期化します。

systemctl start mariadb
# MariaDBのデータベースが初期化される

DBの初期化が終わったら、DRBDディスクのマウントを解除して、Secondaryに降格させます。

systemctl stop mariadb
umount /dev/drbd0
drbdadm secondary mysql_res

ここで最も重要なポイントがあります。OS起動時のMariaDBの自動起動は必ず無効化(disable)しておいてください。このコマンドは node1node2 の両方で実行します。

systemctl disable --now mariadb

サービスの起動や停止のタイミングは、すべてDRBD ReactorのPromoterプラグインに一任するためです。

また、この後の手順で使用する「sshを使ったフェンシング」を機能させるため、事前に両ノード間でパスワードなしのSSH鍵認証(ssh-keygen および ssh-copy-id)を設定しておいてください。

3. DRBD側のフェンシング設定(ステップ2)

2ノード構成の場合、3台目による多数決(クォーラム)でのスプリットブレイン対策ができません。そのため、通信断絶時にお互いがプライマリ(昇格状態)になろうとするのを防ぐため、相手ノードを確実に隔離(強制停止)する「フェンシング(STONITH)」の設定が必須となります

⚠️ 重要:本番環境でのフェンシングに関する注意 本記事ではテスト環境向けに「sshを使ったフェンシング」を解説していますが、この方法はネットワーク(通信回線)自体の障害時には相手ノードにSSH到達できず、フェンシングが失敗する致命的な弱点があります。 本番運用においては、HP iLOやDELL iDRAC、IPMIといったアウトオブバンドのハードウェア管理ネットワークを利用した確実なフェンシングを強く推奨します

フェンススクリプトコード(/usr/local/bin/fence_ssh_wrapper.sh)

DRBDの fence-peer ハンドラが呼び出される際、環境変数を利用して相手ノードを特定します。DRBD 9の高度な変数(動的マッピング)を利用することで、柔軟かつ手軽にSSH経由で相手をクラッシュ(強制再起動)させるラッパースクリプトを配置します。

#!/bin/bash
# /usr/local/bin/fence_ssh_wrapper.sh

RESOURCE=$DRBD_RESOURCE
# 間接参照を用いて、DRBDの変数から動的に対向ノードのホスト名を取得します
PEER_ID_VAR="DRBD_NODE_ID_${DRBD_PEER_NODE_ID}"
PEER="${!PEER_ID_VAR}"    # node1ではnode2、node2ではnode1の値がセットされます。

# SysRqトリガーを送り込み、相手を強制再起動(隔離)させます
ssh -i /root/.ssh/id_rsa root@$PEER "echo c > /proc/sysrq-trigger"

if [ $? -eq 0 ]; then
    # LINBITの仕様に基づき、フェンシング成功時は終了コード「7」を返します。
    # これにより、生き残ったノード側のI/Oフリーズが解除され、Primaryへの昇格が可能になります。
    exit 7
else
    # フェンシング失敗
    exit 5
fi

※スクリプト作成後は、両ノードで必ず chmod +x /usr/local/bin/fence_ssh_wrapper.sh を実行し、実行権限を付与してください。

4. DRBD Reactor(Promoterプラグイン)の設定(ステップ3:コア部分)

DRBDイベントの発生(Syslog出力など)を自前でパースして自動フェイルオーバーさせるような、独自のHAモニタープログラムを開発する必要はありません。DRBD Reactorの Promoter プラグインを使用すれば、内部APIと直接連携し、以下のようなTOMLファイル(/etc/drbd-reactor.d/mysql.toml)を一つ書くだけで安全な状態管理が可能です。

[[promoter]]
id = "mysql"

[promoter.resources.mysql_res]
on-drbd-demote-failure = "reboot"
start = [
    # 1. ファイルシステムのマウント
    # 複数行の引数も """ で囲むことで綺麗に記述できます
    """ocf:heartbeat:Filesystem fs_mysql device=/dev/drbd0 \
       directory=/var/lib/mysql fstype=xfs run_fsck=no""",
    
    # 2. データベースの起動
    "mariadb.service",
    
    # 3. 仮想IP(VIP)の付与
    "ocf:heartbeat:IPaddr2 db_virtip ip=192.168.3.30 cidr_netmask=24 nic=enp1s0"
]

※このファイルを node1 で作成し、scp 等で node2 へコピーしてください。

解説のポイント:

  • start リストの順番が命: DRBD Reactorは、この配列の上から順番に処理を実行します。ストレージ(Filesystem)→ DBエンジン(mariadb.service)→ 接続口(IPaddr2)という論理的な起動順序と完全に一致しています。停止時は自動的に逆順で安全に処理されます。
  • マウントにはOCFリソースエージェントを利用: systemdのマウントユニットを使うことも可能ですが、OCFの Filesystem エージェントを使用することで、万が一プロセスがファイルシステムを掴んで離さない場合でも、安全にプロセスをキルしてアンマウント処理を完了させてくれるため実運用に向いています。
  • 独自サービスへの応用: mariadb.service の部分を、皆様が独自で開発・管理されたアプリケーションサービス(systemdユニット名)に書き換えるだけで、どのようなサービスでもノーコードで安全にHA化できます。

💡 コラム:DRBD Reactorの徹底したデータ保護能力(自動ロールバックとMask仕様)

もし自作のHAスクリプトで運用している場合、「VIPの付与に失敗した」「NIC名の文字数制限に引っかかった」といった予期せぬエラー時に、DBだけが起動したままになるなどの中途半端な状態(スプリットブレインの温床)を生む危険性があります。

しかし、DRBD Reactorは start 配列の途中でエラーを検知すると、即座に起動済みのサービスを停止し、DRBDをSecondaryへ降格させる自動ロールバックを実行します。

さらに、自分が待機系(Secondary)である間は、管理対象のsystemdターゲットをカーネルレベルで mask(完全封印) 状態にします。これにより、管理者のオペレーションミスで待機側でDBを起動してしまうような事故を物理的にブロックします。このOS(systemd)と密接に連携した徹底的な安全機構こそが、Reactorを使う最大のメリットです。

5. 動作確認とフェイルオーバーテスト(ステップ4)

設定が完了したら、両ノードでDRBD Reactorサービスを有効化して起動します。

systemctl enable --now drbd-reactor

ステータスは drbd-reactorctl status mysql コマンドで確認できます。定義したリソースが順番に起動し、緑色のインジケータ()が灯ることで、稼働状態が視覚的にわかります。

フェイルオーバーのテスト:

試しに、稼働中の node1 のネットワークを iptables で強制的に遮断する(あるいは電源を落とす)などして、擬似障害を起こしてみてください。

  1. DRBDが通信断を検知し、自動的に fence-peer ハンドラから fence_ssh_wrapper.sh が発動します。
  2. ダウンした(あるいは孤立した)node1 が強制的に再起動(隔離)されます。
  3. 生き残った node2 側は相手の隔離成功(終了コード7)を確認すると、安全にプライマリ(Primary)に昇格します。
  4. DRBD Reactorが昇格イベントを検知し、配列に定義された通りに「Filesystemマウント」→「MariaDB起動」→「VIP付与」を自動実行し、サービスを引き継ぎます。

まとめ

2ノードの最小構成であっても、DRBDの堅牢なフェンシング機構とDRBD Reactorを組み合わせることで、Pacemakerより簡単にセットアップができます。

TOMLファイルに起動したいサービスを並べるだけで、商用製品に劣らない安全でシンプルなHAシステムが手に入ります。ぜひ、手元のテスト環境でその手軽さと確実性を体感してみてください。