fence_sshを試してみた

概要

fence_sshは、リモートノードをクラスタから安全に隔離するためのフェンシングエージェントです。SSHを利用してノードへのアクセスを行い、再起動や電源オフなどの操作を実行します。このエージェントはSSHを用いるため、対象ノードがハングアップして接続が確立できない場合にはフェンシングが機能しません。そのため、このエージェントは完全なフェンシングエージェントではなく、本番環境よりもテスト用途に適したツールです。
クラスタ環境での信頼性が重要な場合は、他のハードウェアベースのフェンシングエージェントの利用をおすすめします。

公式GitHubリポジトリでさらに詳しい情報を確認できます: リンク

今回はこのfence_sshを使ったPacemakerでのフェンシング設定について解説します。

今回の環境

2ノードのLinuxサーバで、OSはRockyLinux 8.10をインストールしています。
ホスト名はnode1とnode2になります。
PacemakerはLINBIT社のデモライセンスで入手したものを利用しています。デモライセンスは デモライセンス申請ページ から申請できます。

パッケージのインストール

まずfence_sshの開発サイト(リンク)からfence_sshをダウンロードしてください。
ダウンロードしたファイルを/usr/sbinにコピーして、chmod コマンドで実行権を付与します。

# wget https://raw.githubusercontent.com/nannafudge/fence_ssh/refs/heads/master/fence_ssh
# mv fence_ssh /usr/sbin
# chmod 755 /usr/sbin/fench_ssh

また、fence_sshの実行にsshpassコマンドも必要になるため、これをdnf(yum)でインストールします。

# dnf install sshpass

パッケージのインストールが終わったら、次はアカウントの設定を行います。

アカウントの設定

rootアカウントでfence_sshを動かすことも可能で、設定も簡単ですが、今回はPacemakerをインストールするとシステムに追加されるhaclusterのアカウントを使って設定する例を紹介します。

パスワード設定

管理者アカウントで次のコマンドを実行して、haclusterのパスワードを設定してください。
また、haclusterアカウントはログインシェルが無効(nologin)になっているため、usermodコマンドでログインシェルをbashに変更します。

  # echo 'hacluster:Pa55w0rd' | sudo chpasswd
  # usermod -s /bin/bash hacluster

sudoersの設定

fence_sshではSSHで相手のノードにログインしてshutdownコマンドを実行します。
したがってhaclusterアカウントでshutdownコマンドを実行できるようにsuderの設定を行う必要があります。/etc/sudoersの最後に次の行を追加してください。

hacluster ALL=(ALL) NOPASSWD: /sbin/shutdown

SSHによる疎通確認

以上でアカウントの設定が終わりました。相手のノードにSSHでログインができるか確認してください。

  # sshpass -p 'Pa55w0rd' ssh hacluster@node2
  Activate the web console with: systemctl enable --now cockpit.socket

  Last login: Wed Nov  6 09:47:46 2024 from 192.168.3.51
  [hacluster@node2 ~]$

疎通確認が成功したら、次はパッケージfence_sshの試験を行います。

パッケージの単体試験

コマンドとしてfence_sshを実行して相手ノードが再起動できるかテストします。
次のように入力します。

  # fence_ssh -h node2 -u hacluster -s true -p 'Pa55w0rd' -o reboot

node1から実行して、node2が再起動すれば正常に動作しています。
もし動作しない場合は、次のようにbashのデバッグオプションをつけて実行してエラー箇所を調べて下さい。

  # bash -x /usr/sbin/fence_ssh -h ・・・・

Pacemakerの設定

過去に投稿したフェンシングの記事 (リンク) と同じく、Dummyリソースエージェントを使って
fence_sshの動作を確認します。Pacemakerの設定は以下のようになります。

node 1: node1
node 2: node2
primitive stonith1 stonith:fence_ssh \
        params hostname=node1 user=root pcmk_host_list=node1 \
        op monitor interval=60s \
        meta provides=unfencing
primitive stonith2 stonith:fence_ssh \
        params hostname=node2 user=root pcmk_host_list=node2 \
        op monitor interval=60s \
        meta provides=unfencing
primitive test Dummy \
        op start interval=0s timeout=30s \
        op monitor interval=10s timeout=60s \
        op stop interval=0s timeout=30s on-fail=fence
location l_stonith1 stonith1 -inf: node1
location l_stonith2 stonith2 -inf: node2
property cib-bootstrap-options: \
        stonith-enabled=true \
        no-quorum-policy=ignore \
        have-watchdog=false \
        cluster-infrastructure=corosync \
        cluster-name=cluster2 \
        dc-version=2.0.5.linbit-2.0.el8-ba59be712

testリソースのstopの引数にon-fail=fenceがあるので、停止に失敗するとフェンシングが発動して障害が発生したノードを相手ノードが再起動します。

動作確認

フェンシングの動作を確認します。testリソースに停止のエラーを発生させて、fence_sshが起動するか確認します。

testリソースを定義しているDummyリソースエージェントは/usr/lib/ocf/resource.d/heartbeat/Dummyにあるシェルスクリプトです。
このファイルの119行目は次のようになっています。

  dummy_stop() {
     dummy_monitor
     if [ $? =  $OCF_SUCCESS ]; then
         rm ${OCF_RESKEY_state}
     fi
     return $OCF_SUCCESS
 }

dummy_stop()testリソースが停止の時に呼ばれる定義なので、ここにsleep命令を入れて30秒以上処理時間が経過するように書き換えると、Pacemakerはtestリソースの停止が失敗したと判断します。

  dummy_stop() {
     sleep 32  # ← 追加行
     dummy_monitor
     if [ $? =  $OCF_SUCCESS ]; then
         rm ${OCF_RESKEY_state}
     fi
     return $OCF_SUCCESS
  }

node1のDummyリソースエージェントにのみ修正してください。

node1でtestリソースが動いていることを確認して、node1のPacemakerを停止します。Pacemakerの停止でtestリソースも停止しようとしますが、sleep 32の定義ににより停止に失敗します。この結果フェンシングが発動して、node1はnode2から停止されます。