Solaris8 でアクトスタンバイ

IPMPを使っているSolaris8を2台使って,簡単なアクトスタンバイ系を作る方法についてのメモです.IPアドレス,ホスト名とインタフェースが以下のようになっている場合を考えます.

サーバ#1
10.10.10.10     host00b2  代表アドレス, nodename
10.10.10.11     host01b0  bge0 に割り振るアドレス
10.10.10.12     host02b1  bge1 に割り振るアドレス
サーバ#2
10.10.10.13     host03b2  代表アドレス, nodename
10.10.10.14     host04b0  bge0 に割り振るアドレス
10.10.10.15     host05b1  bge1 に割り振るアドレス

ネットワークは10.10.10.0/24で,デフォルトゲートウェイは10.10.10.253だとします.そうすると,サーバ#1, #2 の/etc/hostname.*, /etc/nodename は以下のようになります.

サーバ#1

/etc/hostname.bge0
host00b2 netmask + broadcast + group IPMP1 up \
addif host01b0 deprecated -failover netmask + broadcast + up

/etc/hostname.bge1
host02b1 netmask + broadcast + group IPMP1 deprecated -failover standby up

/etc/nodename
host00b2
サーバ#2

/etc/hostname.bge0  -- (1)
host03b2 netmask + broadcast + group IPMP1 up \
addif host04b0 deprecated -failover netmask + broadcast + up

/etc/hostname.bge1
host05b1 netmask + broadcast + group IPMP1 deprecated -failover standby up

/etc/nodename
host03b2

アクトスタンバイを作り出す方法として,サーバ#1のネットワークが切れた時にサーバ#2のIPアドレスを変更して,サーバ#1のIPアドレスに付け替えてみます.つまり,

サーバ#2

/etc/hostname.bge0  -- (2)
host00b2 netmask + broadcast + group IPMP1 up \
addif host04b0 deprecated -failover netmask + broadcast + up

となっている状態を作りだすわけです.これを実現するshスクリプト(toggle_if)は以下のようになります.

#!/bin/sh
#  /etc/toggle_if

GATE='10.10.10.253'

case "$1" in       # 引数は wakeup か sleep としています
wakeup)            # wakeupはサーバ#2のアドレスを使います
	/sbin/ifconfig bge0 unplumb
	/sbin/ifconfig bge1 unplumb
                   # unplumbはインタフェースを削除します
	/sbin/ifconfig bge0 plumb
	/sbin/ifconfig bge1 plumb
                      # plumbはインタフェースを新規作成します
	cp -f /etc/wakeup_hostname.bge0 /etc/hostname.bge0
                      # wakeup_hostname.bge0 は上記(1)です
	IFCMD=`cat /etc/hostname.bge0`
	/sbin/ifconfig bge0 $IFCMD > /dev/null 2>&1
                      # bge0 へのアドレス設定
	IFCMD=`cat /etc/hostname.bge1`
	/sbin/ifconfig bge1 $IFCMD > /dev/null 2>&1
                      # bge1 へのアドレス設定
	ping $GATE > /dev/null 2>&1
                      # 収容スイッチのARPテーブルを更新します

	/usr/bin/logger -p daemon.notice 'wakeup to #2 addr'
                      # syslog に変更を登録します
                      # kernel がIPアドレス変更を出力するので
                      # それだけでも判断可能です
	;;
sleep)             # sleepはサーバ#1のアドレスを使います
	/sbin/ifconfig bge0 unplumb
	/sbin/ifconfig bge1 unplumb
                      # unplumbはインタフェースを削除します
	/sbin/ifconfig bge0 plumb
	/sbin/ifconfig bge1 plumb
                      # plumbはインタフェースを新規作成します

	cp -f /etc/sleep_hostname.bge0 /etc/hostname.bge0
                      # wakeup_hostname.bge0 は上記(2)です
	IFCMD=`cat /etc/hostname.bge0`
	/sbin/ifconfig bge0 $IFCMD > /dev/null 2>&1
                      # bge0 へのアドレス設定
	IFCMD=`cat /etc/hostname.bge1`
	/sbin/ifconfig bge1 $IFCMD > /dev/null 2>&1
                      # bge1 へのアドレス設定

	/usr/bin/logger -p daemon.notice 'sleep to #1 addr'
                      # 収容スイッチのARPテーブルを更新します
	ping $GATE > /dev/null 2>&1
                      # syslog に変更を登録します
                      # kernel がIPアドレス変更を出力するので
                      # それだけでも判断可能です
	;;
*)
	echo "Usage: $0 {wakeup | sleep}"
                      # 引数が wakeup でも sleep でもなければ
                      # 間違い
	exit 1
	;;
esac

これでインタフェースアドレス変更をサーバリブートなしで実行できるようになりました.でもこれで終わりではありません.アクトスタンバイを実現するためには,サーバ#2からサーバ#1のインタフェースが生きているかどうかを確認する必要があります.サーバ#1でbge0, bge1に割り振ったアドレスはdeprecated 宣言しているので,このアドレスからのパケット送出はできませんが,外部からこのアドレスに対してパケットを受信した際にはこのアドレスからの返信は可能です.

つまり,10.10.10.11, 10.10.10.12 へのping が可能です.このため,両方へのping が止まったことで10.10.10.10がダウンしたと判断することができます.この方法を使ったスクリプト(ifwatchdog)は以下のようになります.

#!/bin/sh
#   /etc/ifwatchdog

## target configurations
#    TARGET_IF0: サーバ#1 の代表アドレス
#    TARGET_IF1: サーバ#1 bge0 に割り振ったアドレス
#    TARGET_IF2: サーバ#1 bge1 に割り振ったアドレス
#    GW:         サーバ#1, #2を収容するスイッチのアドレス
#    IF_CFG:     サーバ#2 bge0 の設定ファイル名
#    IF_NAME:    サーバ#2 のノード名
#    TOGGLE:     アドレス変更スクリプト
#    DEBUG:      デバッグモード 0/1 (1: デバッグモードON)

TARGET_IF0='10.10.10.10'
TARGET_IF1='10.10.10.11'
TARGET_IF2='10.10.10.12'
GW='10.10.10.253'
IF_CFG='/etc/hostname.bge0'
IF_NAME='host03b2'
TOGGLE='/etc/toggle_if'
DEBUG=0

if [ $DEBUG -eq 1 ]
then
	OUTPUT=''
              # デバッグ中は標準出力
else
	OUTPUT='/dev/null'
              # デバッグ中でなければ出力しない
fi

## check interface mode
#    sleep:  サーバ#1 のアドレスを使うモード
#    wakeup: サーバ#2 のアドレスを使うモード

/usr/bin/grep $IF_NAME $IF_CFG > $OUTPUT 2>&1
RES_IF=$?
              # どちらのモードなのかを設定ファイルから判断
              # 0 だとwakeup モード(サーバ#2アドレス)
              # 1 だとsleep モード (サーバ#1アドレス)
if [ $RES_IF -eq 0 ]
then
	MODE='WAKEUP'
	if [ $DEBUG -eq 1 ]
	then
		echo "using my, server#2's name"
	fi
else
	MODE='SLEEP'
	if [ $DEBUG -eq 1 ]
	then
		echo "using server#1's name"
	fi
fi

## check target interface
#

/usr/sbin/ping -g $GW -n $TARGET_IF1 3 > $OUTPUT 2>&1
RES_IF1=$?
/usr/sbin/ping -g $GW -n $TARGET_IF2 3 > $OUTPUT 2>&1
RES_IF2=$?
             # サーバ#1 のインタフェースの死活監視
             # -g $GW: 収容スイッチ経由(スイッチARPテーブル更新のため)
             # -n $TARGET*: 出力時にホスト名に変換しない
             # 3: 1秒に1回,全3回チェック

## do something
#

if [ $RES_IF1 -eq 0 ] || [ $RES_IF2 -eq 0 ]
then
             # サーバ#1 は生きている
	if [ $MODE = 'SLEEP' ]
	then
	         # サーバ#1 のアドレスを使っていたのでwakeupモードへ
		if [ $DEBUG -eq 1 ]
		then
			echo WAKEUP
		else
			$TOGGLE wakeup
			/usr/sbin/ping -n $TARGET_IF0 2 > /dev/null 2>&1
		fi
	else
            	# サーバ#2 のアドレスを使っているのでそのまま
		if [ $DEBUG -eq 1 ]
		then
			echo ALREADY WAKEUP: DO NOTHING
		fi
	fi
else
         # サーバ#1 はダウンしている
	if [ $MODE = 'WAKEUP' ]
	then
            	# サーバ#2 のアドレスを使っているのでsleepモードへ
		if [ $DEBUG -eq 1 ]
		then
			echo SLEEP
		else
			$TOGGLE sleep
		fi
	else
   	         # サーバ#1 のアドレスを使っているのでそのまま
		if [ $DEBUG -eq 1 ]
		then
			echo ALREADY SLEEP: DO NOTHING
		fi
	fi
fi

ネットワークインタフェースを結線してからIPMPを使った代表アドレスが使えるようになるまではだいたい1分ぐらいかかります.詳しくはmpathdのマニュアルを参照してください.経験則では,監視スクリプトを2分ぐらいごとに動かせばよいようです.