CTDBによるHA NFS
参考資料
クラスタ全体像の説明
下記のネットワーク構成で、GlusterFSのボリュームをNFSで公開します。
-------------
| NFS Cient |
-------------
|
| Service Network
---------------------------------------------------------
| 192.168.122.101 | 192.168.122.102 | 192.168.122.103 |192.168.122.104
| eth0 | eth0 | eth0 | eth0
------------- ------------- ------------- -------------
| gluster01 | | gluster02 | | gluster03 | | gluster04 |
------------- ------------- ------------- -------------
| eth1 | eth1 | eth1 | eth1
| 192.168.1.101 | 192.168.1.102 | 192.168.1.103 | 192.168.1.104
---------------------------------------------------------
Internal Network
この際、Service NetworkのIPアドレスとして、CTDBによるFloating IPをアサインして、ノード障害時にFloating IPの引き継ぎを行う構成を行います。
Internal Networkは、glusterデーモンの通信、および、CTDBデーモンのハートビート通信に使用します。
なお、CTDBは、元々は、Sambaのクラスタ構成におけるロックマネージャとして開発されましたが、その後、Floating IPの引き継ぎ機能(IP Failover機能)などが追加され、Samba以外のクラスタ型の共有ファイルシステムとも組み合わせて利用できるようになりました。ここでの構成手順は、Configuring CTDBに記載の手順をベースに、GlusterFSに対応するように修正を加えています。
CTDBのクラスタ監視機構
具体的な構成手順の前に、CTDBのクラスタ監視機構を簡単に説明しておきます。
ノード間の死活監視
ノード間の死活確認は、Internal Networkによるハートビートを通じて行います。ここでは、簡易的に、glusterデーモンの通信経路(ノード間のデータ転送経路)とハートビート経路を共有しています。ただし、後述の注意にあるように、本番環境ではハートビートは専用のネットワーク経路を用意することをお勧めします。
Split-brainへの対応
共有ファイルシステム上にロックファイルを用意して、クラスタマスタ(Recovery Master)の選出を行います。該当ファイルにPOSIX Lockを取得することで、排他的にクラスタマスタが選出されます。ネットワーク障害でハートビートが分断して、クラスタとしての Split-brain状態になった場合、クラスタマスタのいる「島」がFloating IPを引き継いで、サービスを継続します。ロックファイルを配置する共有ファイルシステムとしては、小さなGlusterFSボリュームを用意して、各ノードでマウントして利用します。
カスタムスクリプトによるノード監視
各ノードで定期的に監視スクリプトを実行して、何らかの問題を検知した場合は、該当ノードのFloating IPを強制的に他ノードに引き継ぎます。デフォルトで用意されている監視スクリプトでは、Floating IPをアサインしたNICのLink Downの検知などを行なっていますので、Service NetworkのNIC障害が発生した場合なども、自動的にFloating IPの引き継ぎが行われます。
(注意)
Internal Networkとハートビート経路を共有する場合、Internal Networkの障害時にハードビート経路切断と(GlusterFSボリューム上のロックファイルによる)ロック情報の共有不可のニ重障害となり、クラスタの動作が不安定になる危険性があります。一方、Service Networkとハートビート経路を共有する構成の場合、Service NetworkのLink Downが発生すると、上述のノード監視によって、Floating IPの引き継ぎが発生しますが、ハートビート切断が同時に発生するため、該当ノードがクラスタマスタの場合、引き継ぎ処理に失敗する場合があります。
ハートビートには、専用の独立したネットワーク経路を使用することで、このような複合障害を回避することができます。もしくは、ハートビートを他のネットワーク経路と共有する場合は、各ネットワーク経路はBondingで冗長化しておき、CTDBによるIP Failoverはノード障害の対応のみに使用するという方法が考えられます。
ハートビート経路をService Networkと共有する場合は、カスタム監視スクリプトで問題を回避する方法も考えられます。カスタム監視スクリプト「Ping Check」を参照ください。
GlusterFSとボリュームの構成
前述のネットワーク構成を持った4ノードの GlusterFSクラスタを構成します。ここでは、次の/etc/hostsを使用して、Internal NetworkのIPがホストネームに一致するようにした状態で、ホストネームを指定して「gluster peer probe」を実行してます。これにより、Internal Networkがglusterデーモンの通信経路として使用されるようになります。
# cat /etc/hosts
192.168.1.101 gluster01
192.168.1.102 gluster02
192.168.1.103 gluster03
192.168.1.104 gluster04
CTDBのハートビートは、TCP4379を使用するので、このポートをiptablesで許可しておきます。
# cat /etc/sysconfig/iptables | grep 4379
-A INPUT -m state --state NEW -m tcp -p tcp --dport 4379 -j ACCEPT
続いて、ロックファイルを配置するためのボリュームを作成します。ここでは、LVMで最小サイズ(4MB)のLVを作成して、それをブリック(/brick/lock)としたボリュームlockvolを作成しています。冗長性を最大限とするため、4ノード全体でのレプリカ構成としています。
# gluster vol info lockvol
Volume Name: lockvol
Type: Replicate
Volume ID: 2b1787e9-dfda-4837-8ac9-d7e30106e9c9
Status: Started
Number of Bricks: 1 x 4 = 4
Transport-type: tcp
Bricks:
Brick1: gluster01:/brick/lock
Brick2: gluster02:/brick/lock
Brick3: gluster03:/brick/lock
Brick4: gluster04:/brick/lock
NFSで公開するボリュームは、2x2のReplica - Distributed構成としています。
# gluster vol info nfsvol
Volume Name: nfsvol
Type: Distributed-Replicate
Volume ID: a8dfc606-5a47-49c4-8e75-ba0b386588a8
Status: Started
Number of Bricks: 2 x 2 = 4
Transport-type: tcp
Bricks:
Brick1: gluster01:/brick/vol00
Brick2: gluster02:/brick/vol00
Brick3: gluster03:/brick/vol00
Brick4: gluster04:/brick/vol00
CTDBの導入と構成
各ノードでctdbパッケージをインストールします。(RHEL6の場合、ctdbパッケージは、Resilient Storage Add-onのリポジトリに含まれています。)
# yum isntall ctdb
ロックボリューム内に全ノード共通の設定ファイルを用意します。これは、gluster01のみで実施します。
ロックボリュームをマウントします。
# mkdir -p /gluster/lock
# mount -t glusterfs localhost:/lockvol /gluster/lock
各ノードのハートビート経路のIPアドレスを列挙したファイルを用意します。
# cat /gluster/lock/nodes
192.168.1.101
192.168.1.102
192.168.1.103
192.168.1.104
CTDBデーモンの設定ファイルを用意します。
# cat /gluster/lock/ctdb
CTDB_RECOVERY_LOCK=/gluster/lock/lockfile
CTDB_PUBLIC_ADDRESSES=/etc/ctdb/public_addresses
CTDB_NODES=/etc/ctdb/nodes
# tunables
CTDB_SET_DeterministicIPs=1
CTDB_SET_RecoveryBanPeriod=120
CTDB_SET_KeepaliveInterval=5
CTDB_SET_KeepaliveLimit=5
CTDB_SET_MonitorInterval=15
最後の5行の設定は必須ではありませんが、それぞれ、次の意味のオプションになります。
DeterministicIPs : 各ノードに対するFloating IPの割り当てを固定化します。全ノードが正常稼働している場合、各ノードには必ず同じFloating IPが割り当てられます。ただし、割り当て順をユーザが明示することはできません。CTDBの内部ロジックで決定されます。
ReoveryBanPeriod : 障害検知されてクラスタから除外されたノードは、除外発生後、この時間(秒)は再度、クラスタに参加することが許可されません。障害が繰り返して、クラスタからの除外と参加が頻繁に繰り返すことを防止するパラメータです。デフォルトは300ですが、ここでは、障害テストを円滑にするために少し小さな値に変更しています。
KeepaliveInterval / KeepaliveLimit : ハートビートの通信間隔(秒)とハートビート切断と判断するまでの通信失敗回数です。これらの積がハートビート切断検知時間になります。
MonitorInterval : 後述の「monitor」イベントの発行間隔(秒)です。
ここで、一旦、ロックボリュームをアンマウントしておきます。
# umount /gluster/lock
ここからは、全ノードで共通の作業です。
ロックボリュームのマウントポイント作成と、ロックボリューム上の設定ファイルへのシンボリックリンクを作成します。
# mkdir -p /gluster/lock
# mv /etc/sysconfig/ctdb /etc/sysconfig/ctdb.orig
# ln -s /gluster/lock/ctdb /etc/sysconfig/ctdb
# ln -s /gluster/lock/nodes /etc/ctdb/nodes
このノードにアサイン可能なFloating IPを列挙したファイルを作成します。ここでは、全ノードでお互いにFloating IPを引き継げるように、全ノードで共通に、すべてのFloating IPを記述しておきます。
# cat /etc/ctdb/public_addresses
192.168.122.201/24 eth0
192.168.122.202/24 eth0
192.168.122.203/24 eth0
192.168.122.204/24 eth0
glusterデーモンとCTDBデーモンは連携して起動する必要があるので、自動起動は停止しておきます。
# service glusterd stop
# chkconfig glusterd off
# chkconfig ctdb off
CTDB起動/停止スクリプトの用意
gluster01からgluster01〜gluster04への公開鍵SSH認証を設定しておいて、次のスクリプトを用意します。
ctdb_start.sh
#!/bin/sh -x
ssh gluster01 service glusterd start
ssh gluster02 service glusterd start
ssh gluster03 service glusterd start
ssh gluster04 service glusterd start
sleep 5
ssh gluster01 mount -t glusterfs localhost:/lockvol /gluster/lock
ssh gluster02 mount -t glusterfs localhost:/lockvol /gluster/lock
ssh gluster03 mount -t glusterfs localhost:/lockvol /gluster/lock
ssh gluster04 mount -t glusterfs localhost:/lockvol /gluster/lock
sleep 5
ssh gluster01 service ctdb start
ssh gluster02 service ctdb start
ssh gluster03 service ctdb start
ssh gluster04 service ctdb start
ctdb_stop.sh
#!/bin/sh -x
ssh gluster01 service ctdb stop
ssh gluster02 service ctdb stop
ssh gluster03 service ctdb stop
ssh gluster04 service ctdb stop
sleep 5
ssh gluster01 umount /gluster/lock
ssh gluster02 umount /gluster/lock
ssh gluster03 umount /gluster/lock
ssh gluster04 umount /gluster/lock
sleep 5
ssh gluster01 service glusterd stop
ssh gluster02 service glusterd stop
ssh gluster03 service glusterd stop
ssh gluster04 service glusterd stop
それぞれ、「glusterデーモン起動、ロックボリュームのマウント、CTDBデーモンの起動」を全ノードで順次実施/停止しています。あくまでサンプルですので、例外処理などは入れていません。
注)GlusterFSのEvent Hook機能を利用して、glusterデーモン起動時に自動的にこれらを実施することも可能です。RHS2.0ではそのためのスクリプトが事前に用意されています。
CTDBの起動と動作確認
gluster01で起動スクリプトを実行します。
# ./ctdb_start.sh
+ ssh gluster01 service glusterd start
Starting glusterd: [ OK ]
+ ssh gluster02 service glusterd start
Starting glusterd: [ OK ]
+ ssh gluster03 service glusterd start
Starting glusterd: [ OK ]
+ ssh gluster04 service glusterd start
Starting glusterd: [ OK ]
+ sleep 5
+ ssh gluster01 mount -t glusterfs localhost:/lockvol /gluster/lock
+ ssh gluster02 mount -t glusterfs localhost:/lockvol /gluster/lock
+ ssh gluster03 mount -t glusterfs localhost:/lockvol /gluster/lock
+ ssh gluster04 mount -t glusterfs localhost:/lockvol /gluster/lock
+ sleep 5
+ ssh gluster01 service ctdb start
Starting ctdbd service: [ OK ]
+ ssh gluster02 service ctdb start
Starting ctdbd service: [ OK ]
+ ssh gluster03 service ctdb start
Starting ctdbd service: [ OK ]
+ ssh gluster04 service ctdb start
Starting ctdbd service: [ OK ]
しばらく待つと、次のコマンドで全ノードのステータスがOKになります。
# ctdb status
Number of nodes:4
pnn:0 192.168.1.101 OK (THIS NODE)
pnn:1 192.168.1.102 OK
pnn:2 192.168.1.103 OK
pnn:3 192.168.1.104 OK
Generation:515898200
Size:4
hash:0 lmaster:0
hash:1 lmaster:1
hash:2 lmaster:2
hash:3 lmaster:3
Recovery mode:NORMAL (0)
Recovery master:0
Recovery master(この例では、pnn:0 192.168.1.101)は、ロックファイルで選出されたクラスタマスタを表します。
次のコマンドでFloating IPの割り当て状況が確認できます。
# ctdb ip
Public IPs on node 0
192.168.122.201 node[3] active[] available[eth0] configured[eth0]
192.168.122.202 node[2] active[] available[eth0] configured[eth0]
192.168.122.203 node[1] active[] available[eth0] configured[eth0]
192.168.122.204 node[0] active[eth0] available[eth0] configured[eth0]
各ノードの実際のIPは、ipコマンドで確認します。
# ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 52:54:00:b6:e2:a4 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.101/24 brd 192.168.122.255 scope global eth0
inet 192.168.122.204/24 brd 192.168.122.255 scope global secondary eth0
inet6 fe80::5054:ff:feb6:e2a4/64 scope link
valid_lft forever preferred_lft forever
特定ノード(この例ではgluster02)を再起動すると、該当ノードのFloating IPは他のノードに引き継がれます。CTDBデーモンのログは/var/log/log.ctdbに出力されています。
# ssh gluster02 reboot
# ctdb status
Number of nodes:4
pnn:0 192.168.1.101 OK (THIS NODE)
pnn:1 192.168.1.102 DISCONNECTED|UNHEALTHY|INACTIVE
pnn:2 192.168.1.103 OK
pnn:3 192.168.1.104 OK
Generation:1290868
Size:3
hash:0 lmaster:0
hash:1 lmaster:2
hash:2 lmaster:3
Recovery mode:NORMAL (0)
Recovery master:0
# ctdb ip
Public IPs on node 0
192.168.122.201 node[3] active[] available[eth0] configured[eth0]
192.168.122.202 node[2] active[] available[eth0] configured[eth0]
192.168.122.203 node[0] active[eth0] available[eth0] configured[eth0]
192.168.122.204 node[0] active[eth0] available[eth0] configured[eth0]
今回の設定では、NFSクライアントからのアクセスは約1分間停止した後、エラーなど発生せずにアクセスが再開しました。
gluster02で、起動処理を行うと、Floating IPは元の状態に戻ります。切り戻し時のNFSクライアントからのアクセス停止はありませんでした。
# ssh gluster02 service glusterd start
Starting glusterd: [ OK ]
# ssh gluster02 mount -t glusterfs localhost:/lockvol /gluster/lock
# ssh gluster02 service ctdb start
Starting ctdbd service: [ OK ]
# ctdb ip
Public IPs on node 0
192.168.122.201 node[3] active[] available[eth0] configured[eth0]
192.168.122.202 node[2] active[] available[eth0] configured[eth0]
192.168.122.203 node[1] active[] available[eth0] configured[eth0]
192.168.122.204 node[0] active[eth0] available[eth0] configured[eth0]
前述のDeterministicIPsを設定しているので、必ず、最初にCTDBデーモンを起動した時と同じ配置になります。この設定がない場合、障害/復旧のパターンによっては、Floating IPの配置が最初と変わる場合があります。
監視スクリプトのカスタマイズ
CTDBの動作に伴う各種イベントが事前に定義されており、イベントが発生するごとに、下記のスクリプトが番号順にすべて実行されます。
# ls /etc/ctdb/events.d/
00.ctdb 11.natgw 20.multipathd 41.httpd 61.nfstickle
01.reclock 11.routing 31.clamd 50.samba 70.iscsi
10.interface 13.per_ip_routing 40.vsftpd 60.nfs 91.lvs
各スクリプトは、イベントに対応したハンドラを実装しており、イベントに伴う自動化を実現します。イベントの種類とハンドラの書き方は、READMEを参照してください。
特に、15秒ごとに「monitor」イベントが発行されるようになっており、このイベントをノードの定期監視に利用できます。たとえば、「10.interface」では、ethtoolコマンドで、Floating IPを持つNICのLink Statusを確認して、Link Downを検知すると、該当ノードを強制的に「UNHEALTHY」ステータスにして、Floating IPの引き継ぎを発生します。
gluster02のeth0をLink Downした場合の例
# ctdb status
Number of nodes:4
pnn:0 192.168.1.101 OK (THIS NODE)
pnn:1 192.168.1.102 UNHEALTHY
pnn:2 192.168.1.103 OK
pnn:3 192.168.1.104 OK
Generation:1068935853
Size:4
hash:0 lmaster:0
hash:1 lmaster:1
hash:2 lmaster:2
hash:3 lmaster:3
Recovery mode:NORMAL (0)
Recovery master:0
この他に、独自にmonitorイベントのハンドラを追加して、glutsterデーモンの障害を検知してIP Failoverを発生させるなどの作りこみも可能と思われます。
monitorイベントの発行間隔は、/gluster/lock/ctdbのパラメータで変更可能です。
CTDB_SET_MonitorInterval=15