DRBD+Heartbeat で NFS Server をクラスタ化してみる

今回は DRBD + Heartbeat で NFS Server を HA クラスタ 構成にしてみます。

結論としては、F/O 時にイマイチうまくできなかったのですが、過程も大事ということでメモ。

テストにあたって Setup of high availability NFS servers を参考にしました。

DRBD のインストールや設定については DRBD on CentOS 5 の記事のような感じです。
Heartbeat との組み合わせについては MySQL DRBD Heartbear HA の記事のように設定しています。
OS 環境は同じく VMWare Server 上の CentOS 5 を使用します。

環境

OS ホスト名 実IPアドレス 仮想IPアドレス DRBDデバイス名 NFS マウントポイント
CentOS 5 toire 192.168.159.128 192.168.159.130 /dev/drbd0 /data
CentOS 5 ohuro 192.168.159.129 192.168.159.130 /dev/drbd0 /data

NFS Server の準備

NFS がインストールされていなかったので、yum でインストールしました。

# yum -y install nfs-utils

プライマリの設定

NFS 共有のディレクトリを作成します。/data としました。

toire# mkdir /data
toire# mount -t ext3 /dev/sdb1 /data
toire# mkdir /data/userdata

/var/lib/nfs を共有ディスクに移動してシンボリックリンクを作成します。

toire# cp -R /var/lib/nfs /data
toire# mv /var/lib/nfs /var/lib/_nfs
toire# ln -s /data/nfs /var/lib/nfs

セカンダリの設定

/var/lib/nfs を削除してシンボリックリンクを作成します。

ohuro# mv /var/lib/nfs /var/lib/_nfs
ohuro# ln -s /data/nfs /var/lib/nfs

プライマリ、セカンダリ両方の設定

/etc/exports を編集します。テストなので簡素にしました。

/data/userdata *(rw,sync)

エクスポートします。

# exportfs -a

/etc/ha.d/haresourses を設定します。

toire drbddisk::r0 Filesystem::/dev/drbd0::/data::ext3 192.168.159.130/24 nfs

プライマリの /data をアンマウントします。

toire# umount /dev/sdb1

Heartbeat と DRBD を起動

# modprobe drbd
# /etc/init.d/heartbeat start
# /etc/init.d/drbd start

プライマリ側で drbdadm コマンドを実行します。

toire# drbdadm primary r0

プライマリの状態を確認するとこんな感じになります。

toire# cat /proc/drbd
version: 8.0.6 (api:86/proto:86)
SVN Revision: 3048 build by buildsvn@c5-i386-build, 2008-02-06 01:17:51
0: cs:Connected st:Primary/Secondary ds:UpToDate/UpToDate C r---
ns:552 nr:408 dw:960 dr:242 al:3 bm:23 lo:0 pe:0 ua:0 ap:0
resync: used:0/31 hits:0 misses:0 starving:0 dirty:0 changed:0
act_log: used:0/257 hits:135 misses:3 starving:0 dirty:0 changed:3

そしてセカンダリの状態を確認するとこんな感じになります。

ohuro# cat /proc/drbd
version: 8.0.6 (api:86/proto:86)
SVN Revision: 3048 build by buildsvn@c5-i386-build, 2008-01-06 01:17:51
0: cs:Connected st:Secondary/Primary ds:UpToDate/UpToDate C r---
ns:408 nr:552 dw:960 dr:53 al:5 bm:5 lo:0 pe:0 ua:0 ap:0
resync: used:0/31 hits:0 misses:0 starving:0 dirty:0 changed:0
act_log: used:0/257 hits:97 misses:5 starving:0 dirty:0 changed:5

プライマリでデバイスがマウントされているかを確認します。(/dev/drbd0 がマウントされてることが確認できます)

toire# df
Filesystem           1K-ブロック    使用   使用可 使用% マウント位置
/dev/mapper/VolGroup00-LogVol00
3555040   1078772   2292768  32% /
/dev/sda1               101086     16041     79826  17% /boot
tmpfs                    95304         0     95304   0% /dev/shm
/dev/drbd0             2063404     35920   1922668   2% /data

テストしてみる

クライアントのホストからマウントしてみます。(クライアントは別途用意しました)

client# mount 192.168.113.135:/data/userdata /mnt/mpoint

無事にマウントできれば OKです。

うまくいかなかったところ

この状態でプライマリサーバの Heartbeat のシャットダウンを試みたところ、シャットダウン途中で固まってしまい、クライアントのほうでも共有にアクセスすると、固まってしまった。
しばらくすると、プライマリサーバの OS 自体がシャットダウンをはじめました。
(split-brain 状態になって DRBD の何かのハンドラ(pri-lost-after-sb とか)が呼ばれたとか?)
そんで、プライマリサーバがシャットダウンされると、セカンダリサーバが DRBD ようやくプライマリに昇格して、クライアントから共有が見えるようになりました。
要調査です。

次に試すかもしれないこと

setup of high availability NFS servers を見て、NFS のロックサービスの設定をしていないことに気づいた。
つまり NFS Server がダウンしたことを rpc.statd がクライアントに通知できていないからなのかも。
/etc/init.d/nfslock を以下のようにするといいかも。あとで試すかも。

start() {
...
echo -n $"Starting NFS statd: "
...
daemon rpc.statd "$STATDARG" -n <cluster_host_name>
....
}
2008年 2月 6日 | Filed under Linux
タグ:

awk で GET データを受け取る

awk で GET データを受け取ることはあまり無いと思うが、ちょっとやってみたのでメモ。

GET かどうかを判定して、”&” でデータを区切った後に、入力データだけを取り出す。
その後はデコードしたり、文字チェックしたりすればいいですかね。

method=ENVIRON["REQUEST_METHOD"];
if(ENVIRON["QUERY_STRING"]){
if(method=="GET"){
str=ENVIRON["QUERY_STRING"];
split(str, a, "&");
# field parse
field1=substr(a[1], index(str, "=") + 1);
field2=substr(a[2], index(str, "=") + 1);
# decode したりあれこれする
・・・
・・・
}
}
2008年 2月 1日 | Filed under Linux
タグ:

sed で携帯の IP アドレスリストを作る

sed だけでほとんどやっつけてみたいということで。
コマンドラインから無理やり携帯の IP アドレスリストを取得してみた。

各社のウェブサイトに curl でアクセスして HTML をいじるので、リニューアルされたら即アウト。
「今のところ取れる」というだけの話。ナマモノのようだ。

DoCoMo

リストになっているところから IP アドレスっぽいのを抜き出した。

curl $DOCOMO_URL | sed -n '/^.*<li>\(\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\/[0-9]\{1,3\}\)<\/li>.*$/{s//\1/;p}'  > docomo.lst

ezweb

IP アドレスとサブネットマスクで 2 行で書かれていたので、後で N コマンドでくっつけた。
パイプで渡しているのでイマイチかもしれない。

curl $EZWEB_URL | sed -n '/^.*<div.*>\(\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\)<\/div>.*/,/^.*<div.*>\(\/[0-9]*\)<\/div>.*/{s//\1/;p}'  | sed '/^[0-9].*$/N;s/\n//' > ezweb.lst

SoftBank

テーブルの中に入ってたので抜き出した。

curl $SOFTBANK_URL | sed -n '/^.*">\(\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\)\(\/[0-9]*\).*/{s//\1\3/;p}' > softbank.lst

WILLCOM

改行コードを変換する sed を一つ入れた。

curl $WILLCOM_URL | sed 's/\r/\n/g' | sed -n '/^<td.*">\(\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\/[0-9]*\).*/{s//\1/;p}' > willcom.lst

.htaccess を作る

awk と組み合わせて、携帯から以外のアクセスを拒否する .htaccess も作ってみた。

# アクセスルール
cat << EOS > .htaccess
order deny,allow
deny from all
EOS
# DoCoMo
curl $DOCOMO_URL | sed -n '/^.*<li>\(\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\/[0-9]\{1,3\}\)<\/li>.*$/{s//\1/;p}' | awk 'NR==1{print "# docomo"}{print "allow from " $0}END{print ""}' >> .htaccess
# ezweb
curl $EZWEB_URL | sed -n '/^.*<div.*>\(\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\)<\/div>.*/,/^.*<div.*>\(\/[0-9]*\)<\/div>.*/{s//\1/;p}' | sed '/^[0-9].*$/N;s/\n//' | awk 'NR==1{print "# ezweb"}{print "allow from " $0}END{print ""}' >> .htaccess
# SoftBank
curl $SOFTBANK_URL | sed -n '/^.*">\(\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\)\(\/[0-9]*\).*/{s//\1\3/;p}' | awk 'NR==1{print "# softbank"}{print "allow from " $0}END{print ""}' >> .htaccess
# WILLCOM
curl $WILLCOM_URL | sed 's/\r/\n/g' | sed -n '/^<td.*">\(\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\/[0-9]*\).*/{s//\1/;p}' | awk 'NR==1{print "# willcom"}{print "allow from "$0}' >> .htaccess

かなり見にくくなった。

2008年 1月 22日 | Filed under Linux
タグ:

awk を書いてみる

awk というと、列を取り出すことくらいにしか使っていなかったので、他のことにも使えるように練習をしてみる。
特に何かに使うわけではないけど、練習がてら /var/log/secure ログファイルの中の、ssh の認証で 3 回以上失敗した IP アドレスと失敗回数を awk で拾ってみた。

sed -n '/Failed/s/.* sshd.*Failed password for.* \([0-9.]*\) port .*/\1/p' /var/log/secure | awk 'NR==1{oip=$1;num=1;next}{nip=$1}oip~nip{++num;next}oip!~nip{if(num>=3){print num,oip}oip=nip;num=1;next}'

練習用なので自分のために解説をすると…
まず sed で Failed した IP アドレスだけを抜く(全部 awk でできるかもしれないけど sed が楽)。

sed -n '/Failed/s/.* sshd.*Failed password for.* \([0-9.]*\) port .*/\1/p' /var/log/secure

それから awk に渡す。
まず一行目の IP をとって比較用の変数に入れてカウントして、次の行に処理を移行する。

awk 'NR==1{oip=$1;num=1;next}

次の行の IP をとって別の変数に入れて、

{nip=$1}

前の行の IP と現在の行の IP を比べて同じならカウントして次の行に評価を移行。

oip~nip{++num;next}

違う IP なら新しい IP を比較用の変数に入れてカウントを 1 に戻して次の行へ移行。もしカウントが 3以上になっていたら、カウント数と IP を表示する。

oip!~nip{if(num>=3){print num,oip}oip=nip;num=1;next}'

表示結果をいじって そのまま iptables で DROP という手を思いついたが、
ブルートフォースアタック対策は iptables で便利にできるので、このようなスクリプトは不要。
それにしても、何も対策していなかったので、このスクリプトで凄い数字が出た。

2008年 1月 14日 | Filed under Linux
タグ:

シェルスクリプト内での rsync に ssh 鍵を指定する

rsync を ssh でするとき、普通のコマンドラインなら

$ rsync -e "ssh -i /path/to/ssh_key" -avz -p -o \
--delete remoteuser@hostname:/path/to/remote/file /path/to/local_save/file

てな感じにするけれど、
シェルスクリプト内だと、”ssh -i /path/to/ssh_key” の部分が指定を見てくれないのです。何かやり方があるのかな??

でも、環境変数 RSYNC_RSH に ssh の鍵指定をしてやればOK。
man page にこんなことが書いてあります。

You  can  also choose the remote shell program using the RSYNC_RSH
environment variable, which accepts the same range  of  values  as
-e.

なので、こういう風にすればOK。

RSYNC_RSH="ssh -i /path/to/ssh_key"
# rsync -avz -p -o --delete remoteuser@hostname:/path/to/remote/file /path/to/local_save/file

2007年 12月 25日 | Filed under Linux
タグ: