PacemakerとDRBDを使ったNFSクラスタの構築

初めに

DRBDの開発会社のLINBIT社では、DRBDやPacemamkerを使った利用事例としてHow-to Guidesをこちらで公開しています。ここで紹介されているDRBDとPacemakerを使ったNFSサーバーのクラスタ構築方法(NFS High Availability Clustering Using DRBD and DRBD Reactor on RHEL 9)を元に、実際に構築して動かしてみました。今回のBlogではその手順を紹介します。

検証の環境

KVMを使った仮想環境上に2つのサーバを用意しました。OSは元の記事に合わせてAlmaLinux 9.5をインストールして、ホスト名、DRBDでレプリケーションするデバイス、ネットワークアドレスは以下のようになります。

ホスト名デバイス名ネットワーク1ネットワーク2ネットワーク3
node1/dev/vdb192.168.3.8610.0.0.8610.0.1.86
node2/dev/vdb192.168.3.8710.0.0.8710.0.1.87

※システムの全体設定としては、ファイヤーウォールとSELinuxは停止しています。
 本番環境での構築ではファイヤーウォールは設定されることをお勧めします。

DRBDとPacemakerのインストール

コンパイル済みのDRBDのパッケージは、ELRepoで公開されていますが、今回のAlmaLinuxではインストールが出来ませんでした。このため、過去の記事で紹介したソースコードからDRBDをインストールする方法使ってDRBDのパッケージを作成するか、DRBDのデモライセンスを申請して、DRBDのバイナリーを入手してください。デモライセンスの申請はこちらのページから行えます。

PacemakerはRed HatやAlmaLinuxのレポジトリで公開されているので、以下のコマンドでリポジトリを登録すればそちらからもダウンロードができます。

RHEL:

# dnf config-manager --set-enabled rhel-9-for-x86_64-highavailability-rpms

AlmaLinux:

# dnf config-manager --set-enabled highavailability

DRBDのインストールは次のコマンドを実行してください。

# dnf install drbd kmod-drbd 

DRBDはPacemakerの中から起動するため、OSの起動時に起動しないようにします。次のコマンドを実行して、自動起動を無効にします。

# systemctl disable drbd

Pacemakerは次のコマンドでインストールしてください。

# dnf install pacemaker corosync pcs

DRBDの設定と初期化

DRBDの設定ファイルを作成して、DRBDを初期化します。
node1、node2の両ノードの/etc/drbd.dにr0.resという名前のファイルを作成します。
今回の環境では設定ファイルを次のようになります。

  resource r0 {
	protocol C;
	device /dev/drbd0;
	disk /dev/vdb;
	meta-disk internal;

	on node1 {
		address 10.0.0.86:7788;
	}
	on node2 {
		address 10.0.0.87:7788;
	}
  }

次に、両ノードで次のコマンドを実行して、DRBDのメタデータを作成します。

  # drbdadm create-md r0
  initializing activity log
  initializing bitmap (32 KB) to all zero
  Writing meta data...
  New drbd meta data block successfully created.
  success

メタデータの作成後、両ノードで次のコマンドを実行して、DRBDを起動します。


  # drbdadm up r0
  # drbdadm status
  r0 role:Secondary
  disk:Inconsistent
  node2 role:Secondary
  peer-disk:Inconsistent

片側のノードで初期同期のコマンドを実行します。ここではnode1での実行例を紹介します。

  # drbdadm --force primary r0
  # drbdadm secondary r0
  # drbdadm status
  r0 role:Secondary
  disk:UpToDate open:yes
  node2 role:Secondary
    replication:SyncSource peer-disk:Inconsistent done:10.88

drbdadm statusを実行した時に上記のような表示になった場合は、同期中で全体の10.88%の同期が終了した事が判ります。100%になったら同期は終了し、次のような表示になります。

  # drbdadm status
  r0 role:Secondary
  disk:UpToDate open:yes
  node2 role:Secondary
    peer-disk:UpToDate

次にDRBDデバイスをXFSでフォーマットします。

# mkfs.xfs /dev/drbd0

最後にマウントするディレクトリを作成します。

# mkdir /nfsdata

※LINBITが公開しているドキュメントではマウントディレクトリは/mnt/drbdですが、
 こちらのBlogでは/nfsdataに変更しています。

Pacemakerの初期設定

/etc/corosync/corosync.confを両ノードで作成して、Pacemakerを起動します。
今回の環境ではcorosync.confは次のようになります。

    totem {
      version: 2
      secauth: off
      cluster_name: cluster
      transport: knet
      rrp_mode: passive
    }
    nodelist {
      node {
  	ring0_addr: 10.0.0.86
  	ring1_addr: 10.0.1.86
  	nodeid: 1
  	name: node1
      }	      
      node {
  	ring0_addr: 10.0.0.87
  	ring1_addr: 10.0.1.87
  	nodeid: 2
  	name: node2
      }
    }
    quorum {
        provider: corosync_votequorum
        two_node: 1
    }
    logging {
        to_syslog: yes
    }

設定が終わったらPacemakerを起動します。Pacemakerを起動するとCorosyncも自動的に起動します。

# systemctl start pacemaker

Pacemaker(Corsync)の起動後、ノード間の接続をcorosync-cfgtoolで確認します。以下はnode1で実行した例です。

# corosync-cfgtool -s
Local node ID 1, transport knet
LINK ID 0 udp
	addr	= 10.0.0.86
	status:
		nodeid:          1:	localhost
		nodeid:          2:	connected
LINK ID 1 udp
	addr	= 10.0.1.86
	status:
		nodeid:          1:	localhost
		nodeid:          2:	connected

Pacemakerの状態をcrm_monコマンドで確認します。
次のようになればPacemakerは正常に起動しています。

# crm_mon -fr1
Cluster Summary:
  * Stack: corosync (Pacemaker is running)
  * Current DC: node1 (version 2.1.8-3.el9-3980678f0) - partition with quorum
  * Last updated: Tue Nov 19 17:23:41 2024 on node1
  * Last change:  Tue Nov 19 17:23:24 2024 by hacluster via hacluster on node1
  * 2 nodes configured
  * 0 resource instances configured

Node List:
  * Online: [ node1 node2 ]

Full List of Resources:
  * No resources

Migration Summary:

NFSクラスターの設定入力

引き続き、どちらかのノードでpcsコマンドを使い、Pacemakerの設定を入力していきます。
まず、クォーラムの設定とフェンシング(Stonith)の設定を無効にします。

  # pcs property set no-quorum-policy=ignore
  # pcs property set stonith-enabled=false

※フェンシング(stonith)が使える方はtrueにして、フェンシングリソースを設定してください。

次にDRBDのリソースを登録します。

# pcs cluster cib drbdconf
# pcs -f drbdconf resource create p_drbd_r0 ocf:linbit:drbd \
  drbd_resource=r0 \
  op start interval=0s timeout=240s \
  stop interval=0s timeout=100s \
  monitor interval=31s timeout=20s \
  role=Unpromoted monitor interval=29s timeout=20s role=Promoted
# pcs -f drbdconf resource promotable p_drbd_r0 \
  promoted-max=1 promoted-node-max=1 clone-max=2 clone-node-max=1 notify=true
# pcs cluster cib-push drbdconf

登録するとPacemakerの状態は次のようになります。

# crm_mon -frD
Node List:
  * Online: [ node1 node2 ]

Full List of Resources:
  * Clone Set: p_drbd_r0-clone [p_drbd_r0] (promotable):
    * Promoted: [ node1 ]
    * Unpromoted: [ node2 ]

次にファイルシステムのマウントの設定を追加して、DRDBリソースがPromote状態(Primary)になったらマウントする制約条件も設定します。

# pcs -f drbdconf resource create p_fs_drbd0 ocf:heartbeat:Filesystem \
  device=/dev/drbd0 directory=/nfsdata fstype=xfs \
  options=noatime,nodiratime \
  op start interval="0" timeout="60s" \
  stop interval="0" timeout="60s" \
  monitor interval="20" timeout="40s"
# pcs -f drbdconf constraint order promote p_drbd_r0-clone then start p_fs_drbd0
# pcs -f drbdconf constraint colocation \
  add p_fs_drbd0 with p_drbd_r0-clone INFINITY with-rsc-role=Promoted
# pcs cluster cib-push drbdconf

ここまで設定すると、DRBDのデバイスが/nfsdataにマウントされるようになります。

# crm_mon -frD1
Node List:
  * Online: [ node1 node2 ]

Full List of Resources:
  * Clone Set: p_drbd_r0-clone [p_drbd_r0] (promotable):
    * Promoted: [ node1 ]
    * Unpromoted: [ node2 ]
  * p_fs_drbd0	(ocf:heartbeat:Filesystem):	 Started node1

Migration Summary:

NFSの設定の前に/nfsdataがマウントされているノード(上記の場合はnode1)で次のコマンドを実行してディレクトリとそのオーナーとグループを整えます。

# mkdir -p /nfsdata/exports/dir1
# chown nobody:nobody /nfsdata/exports/dir1

NFS関連のリソースの設定をする前に、NFSのプログラムのインストールとサービスの起動を行います。

# dnf install nfs-utils rpcbind
# systemctl enable rpcbind --now

プログラムのインストールとサービスの起動が終わったら、NFSのリソースの設定を行います。

# pcs -f drbdconf resource create p_nfsserver ocf:heartbeat:nfsserver \
  nfs_shared_infodir=/nfsdata/nfs_shared_infodir nfs_ip=192.168.3.85 \
  op start interval=0s timeout=40s \
  stop interval=0s timeout=20s \
  monitor interval=10s timeout=20s
# pcs -f drbdconf constraint colocation add p_nfsserver with p_fs_drbd0 INFINITY
# pcs -f drbdconf constraint order p_fs_drbd0 then p_nfsserver
# pcs cluster cib-push drbdconf
# pcs -f drbdconf resource create p_exportfs_dir1 ocf:heartbeat:exportfs \
  clientspec=192.168.3.0/24 directory=/nfsdata/exports/dir1 fsid=1 \
  unlock_on_stop=1 options=rw,sync,no_root_squash \
  op start interval=0s timeout=40s \
  stop interval=0s timeout=120s \
  monitor interval=10s timeout=20s
# pcs -f drbdconf constraint order p_nfsserver then p_exportfs_dir1
# pcs -f drbdconf constraint colocation add p_exportfs_dir1 with p_nfsserver INFINITY
# pcs cluster cib-push drbdconf

※LINBITの資料ではp_exportfs_dir1リソースのoptionsの設定は”rw,sync”のみですが、
 no_root_squashを追加するとrootアカウントでNFSクライアントの書き込みが可能になります。

ここまの設定でPacemakerの状態は次のようになります。

# crm_mon -frD1
Node List:
  * Online: [ node1 node2 ]

Full List of Resources:
  * Clone Set: p_drbd_r0-clone [p_drbd_r0] (promotable):
    * Promoted: [ node1 ]
    * Unpromoted: [ node2 ]
  * p_fs_drbd0	(ocf:heartbeat:Filesystem):	 Started node1
  * p_nfsserver	(ocf:heartbeat:nfsserver):	 Started node1
  * p_exportfs_dir1	(ocf:heartbeat:exportfs):	 Started node1

最後にバーチャルIP(192.168.3.85)の設定を入力すれば、NFSクラスターは完成します。

# pcs -f drbdconf resource create p_virtip_dir1 ocf:heartbeat:IPaddr2 \
  ip=192.168.3.85 cidr_netmask=24 \
  op monitor interval=20s timeout=20s \
  start interval=0s timeout=20s \
  stop interval=0s timeout=20s
# pcs -f drbdconf constraint order p_exportfs_dir1 then p_virtip_dir1
# pcs -f drbdconf constraint colocation add p_virtip_dir1 with p_exportfs_dir1 INFINITY
# pcs cluster cib-push drbdconf

以上で必要なリソースがすべて登録されました。Pacemakerの状態を確認してみます。

# crm_mon -frD1
Node List:
  * Online: [ node1 node2 ]

Full List of Resources:
  * Clone Set: p_drbd_r0-clone [p_drbd_r0] (promotable):
    * Promoted: [ node1 ]
    * Unpromoted: [ node2 ]
  * p_fs_drbd0	(ocf:heartbeat:Filesystem):	 Started node1
  * p_nfsserver	(ocf:heartbeat:nfsserver):	 Started node1
  * p_exportfs_dir1	(ocf:heartbeat:exportfs):	 Started node1
  * p_virtip_dir1	(ocf:heartbeat:IPaddr2):	 Started node1

Migration Summary:

node1でshowmountコマンドを実行すると、正常に動作していることが確認できます。

  # showmount -e node1
  Export list for node1:
  /nfsdata/exports/dir1 192.168.3.0/24

動作確認

別のLinux機からクラスターの仮想IPアドレス192.168.3.85へアクセスしNFSサーバとしての動作を確認します。

# mkdir /mnt/test_nfs_mount
# mount 192.168.3.85:/nfsdata/exports/dir1 /mnt/test_nfs_mount
# dd if=/dev/zero of=/mnt/test_nfs_mount/write_test.out bs=1M count=1024

マウントしたディレクトリにファイルが書き込めれば、NFSサーバーとしての設定は問題ありません。
次に障害試験を行って見ましょう。NFSクラスタのプライマリノード(現在はnode1)を電源スイッチを
押して強制終了すると、セカンダリノードのnode2へフェールオーバーします。

まとめ

LINBIT社が公開しているドキュメントを元に、NFSクラスタを構築してみました。
構築を通じてリソースエージェントのnfsserverやexporfsの推奨される設定が確認できました。
是非、NFSクラスタを構築する際の参考にして下さい。