ダイエット中で炭水化物の量が気になる尾藤正人です。
前回のエントリベンチャー流サーバ構築のススメ(ソフトウェア編)では、主にOS周りのことについて書きました。複数台のサーバを管理するのに重要なのは極力構成を同じにすることです。そうすることで管理コストが大幅に下がります。
以前Klabさんのサーバ管理者向け無精のすすめ ~ちょっと便利なツールの紹介~というエントリで同期ツールの紹介がありましたが、ウノウでも同じような感じの独自ツールを作って同期をとっています。今回はこの同期ツールの紹介をしたいと思います。
僕が shell scripter ということもあってスクリプトは全て sh で。zsh の特殊な記法が使いたかったので zsh で書いています。
凡例
全てのコマンドは最後に対象とするホスト名を指定します。all というは特殊な指定で全てのサーバに対してリクエストが送られます。
共通関数
全てのスクリプトから読み込まれる共通関数です。
function absdirname()
{
local dir=`dirname $1`
if [ "x$dir" = "x." ]; then
dir=$PWD
elif ! echo $dir|grep '^/' > /dev/null; then
dir=$PWD/$dir
fi
cd $dir
echo $PWD
}
function absfilename()
{
local dir=`absdirname $1`
if [ "x$dir" = "x/" ]; then
dir=""
fi
echo $dir/`basename $1`
}
function get_servers()
{
local servers i=1 max=12
while [ $i -le $max ]; do
servers=(${servers[@]} "s$i");
i=`expr $i + 1`
done
echo ${servers[@]};
}
dir_diff.sh directory host
ディレクトリ以下にあるファイルの diff を表示します。zsh の "<()" という記法を使ってます。これを使うと標準出力をファイルのように扱えて直接 diff に渡せるので便利です。
#!/bin/zsh
source `dirname $0`/sh_functions
PROGRAM_NAME=`basename $0`
function usage()
{
echo Usage: $PROGRAM_NAME directory host
exit $1
}
function _dir_diff()
{
if [ -z "$1" -o -z "$2" ]; then
echo "Lack of arguments" 1>&2
return 1
fi
local source=`absfilename $1`
diff -u <(ssh root@$2 find $source|sort) <(sudo find $source|sort)|grep '^\(+\|-\)'
}
# check arguments
if [ -z "$1" -o -z "$2" ]; then
usage 1
fi
if [ "x$2" != "xall" ]; then
_dir_diff $1 $2
exit $?
fi
for host in `get_servers`; do
echo ++++++++++++++++++++++++++++++++++++++
echo + diff from $host
echo ++++++++++++++++++++++++++++++++++++++
_dir_diff $1 $host
echo
done
rpm_diff.sh host
rpm パッケージの diff を表示します。サーバ間でパッケージの過不足がないかどうか確認するのに使います。
#!/bin/zsh
source `dirname $0`/sh_functions
PROGRAM_NAME=`basename $0`
function usage()
{
echo Usage: $PROGRAM_NAME host
exit $1
}
function _rpm_diff()
{
if [ -z "$1" ]; then
echo "You must specify a host name" 1>&2
return 1
fi
diff -u <(ssh root@$1 rpm -qa|sort) <(rpm -qa|sort)|grep '^\(+\|-\)'
}
# check arguments
if [ -z "$1" ]; then
usage 1
fi
if [ "x$1" != "xall" ]; then
_rpm_diff $1
exit $?
fi
for host in `get_servers`; do
echo ++++++++++++++++++++++++++++++++++++++
echo + diff from $host
echo ++++++++++++++++++++++++++++++++++++++
_rpm_diff $host
echo
done
xdiff.sh source host
ファイルの diff をとります。設定ファイルがちゃんと同期されてるかどうか確認したりするのに便利です。
#!/bin/zsh
source `dirname $0`/sh_functions
PROGRAM_NAME=`basename $0`
function usage()
{
echo Usage: $PROGRAM_NAME source host
exit $1
}
# check arguments
if [ -z "$1" -o -z "$2" ]; then
usage 1
fi
if [ "x$2" != "xall" ]; then
_xdiff $1 $2
exit $?
fi
for host in `get_servers`; do
echo ++++++++++++++++++++++++++++++++++++++
echo + diff from $host
echo ++++++++++++++++++++++++++++++++++++++
_xdiff $1 $host
echo
done
xexec.sh command [options ...] host
host で指定されたサーバでコマンドを実行します。ライブラリが更新されたときに一気に全サーバで ldconfig 実行したりとか、他にもいろいろ使えます。
#!/bin/zsh
source `dirname $0`/sh_functions
PROGRAM_NAME=`basename $0`
function usage()
{
echo "Usage: $PROGRAM_NAME command [options ...] host"
exit $1
}
function _xexec()
{
if [ -z "$1" -o -z "$2" ]; then
echo "Lack of arguments" 1>&2
return 1
fi
ssh root@$2 $1
}
# check arguments
if [ -z "$1" -o -z "$2" ]; then
usage 1
fi
host=
command=
while [ -n "$1" ]; do
command="$command $host"
host=$1
shift
done
if [ "x$host" != "xall" ]; then
_xexec $command $host
exit $?
fi
for host in `get_servers`; do
echo ++++++++++++++++++++++++++++++++++++++
echo + execute $command on $host
echo ++++++++++++++++++++++++++++++++++++++
_xexec $command $host
if [ $? -ne 0 ]; then
echo "Failed to execute on $host" 1>&2
exit $?
fi
echo
done
xrsync.sh source host
その名の通り rsync します。ファイルを一斉にシンクロするのに便利です。
#!/bin/zsh
source `dirname $0`/sh_functions
PROGRAM_NAME=`basename $0`
function usage()
{
echo Usage: $PROGRAM_NAME source host
exit $1
}
function _xrsync()
{
if [ -z "$1" -o -z "$2" ]; then
echo "Lack of arguments" 1>&2
return 1
fi
local opts source host
while [ -n "$1" ]; do
opts="$opts $source"
source=$host
host=$1
shift
done
local source=`absfilename $source`
local destination=`dirname $source`
local opts="-auvz -e ssh $opts"
eval sudo rsync $opts $source root@$host:$destination
}
# check arguments
if [ -z "$1" -o -z "$2" ]; then
usage 1
fi
host=
arguments=
while [ -n "$1" ]; do
arguments=(${arguments[@]} $host)
host=$1
shift
done
if [ "x$host" != "xall" ]; then
_xrsync ${arguments[@]} $host
exit $?
fi
for host in `get_servers`; do
echo ++++++++++++++++++++++++++++++++++++++
echo + rsync to $host
echo ++++++++++++++++++++++++++++++++++++++
_xrsync ${arguments[@]} $host
if [ $? -ne 0 ]; then
echo "Failed to execute on $host" 1>&2
exit $?
fi
echo
done
xscp.sh source [source ...] host
こっちは scp 版。ちょっとしたファイルを同期したときに便利。
#!/bin/zsh
source `dirname $0`/sh_functions
PROGRAM_NAME=`basename $0`
function usage()
{
echo "Usage: $PROGRAM_NAME source [source ...] host"
exit $1
}
function _xscp()
{
if [ -z "$1" -o -z "$2" ]; then
echo "Lack of arguments" 1>&2
return 1
fi
local sources host
while [ -n "$1" ]; do
sources=(${sources[@]} $host)
host=$1
shift
done
local opts="-pr"
local source destination
for source in ${sources[@]}; do
source=`absfilename $source`
destination=`dirname $source`
eval sudo scp $opts $source root@$host:$destination
done
}
# check arguments
if [ -z "$1" -o -z "$2" ]; then
usage 1
fi
host=
sources=
while [ -n "$1" ]; do
sources=(${sources[@]} $host)
host=$1
shift
done
if [ "x$host" != "xall" ]; then
_xscp ${sources[@]} $host
exit $?
fi
for host in `get_servers`; do
echo ++++++++++++++++++++++++++++++++++++++
echo + scp to $host
echo ++++++++++++++++++++++++++++++++++++++
_xscp ${sources[@]} $host
if [ $? -ne 0 ]; then
echo "Failed to execute on $host" 1>&2
exit $?
fi
echo
done
まとめ
サーバ間の同期を取るためにウノウで導入しているツール群を紹介しました。こういう細かいツールを最初に作っておくと、作業が効率よく進み非常に楽になります。ぜひ、みなさんの環境でも導入してみてはいかがでしょうか。
何回か続けてきたベンチャー流サーバ構築のススメですが、おかげさまでみなさんから多くのトラックバック、コメント、ブックマークをいただきました。今回で大体サーバ構築に関するトピックは網羅したかと思います。何かありましたら、トラックバックなりコメントなりをいただければ幸いです。