Multihost SSH wrapperによる複数ノードでのコマンド実行。

仕事で複数ノードから同時に別々のWebサーバに対してabで負荷を掛ける必要があったので、普段なら dsh を使うところなのですが、複数ノードにコマンド発行できるサーバはあいにくCentOS 5.5でした。不幸な事に tomahawk も導入されていませんでした。複数ノードに対してsshができるパッケージが無いかなと思って探してみたらちゃんとあるではありませんか。

$ yum search ssh
(snip)
mussh.noarch : Multihost SSH wrapper
(snip)

特に依存関係もないFedora Projectがパッケージベンダーとなっているrpmパッケージです。

$ rpm -qi mussh
Name        : mussh                        Relocations: (not relocatable)
Version     : 0.7                               Vendor: Fedora Project
Release     : 1.el5                         Build Date: Wed Jul 11 10:29:43 2007
Install Date: Mon Mar 12 18:06:01 2012         Build Host: ppc3.fedora.redhat.com
Group       : Applications/System           Source RPM: mussh-0.7-1.el5.src.rpm
Size        : 32686                            License: GPL
Signature   : DSA/SHA1, Wed Jul 11 12:36:32 2007, Key ID 119cc036217521f6
Packager    : Fedora Project <http://bugzilla.redhat.com/bugzilla>
URL         : http://www.sourceforge.net/projects/mussh
Summary     : Multihost SSH wrapper
Description :
Mussh is a shell script that allows you to execute a command or script
over ssh on multiple hosts with one command. When possible mussh will use
ssh-agent and RSA/DSA keys to minimize the need to enter your password
more than once.

この実体(/usr/bin/mussh)は単なるシェルスクリプトでした。なお、Debianにも同じパッケージ名musshで存在します。Sidの場合はバージョン1.0です。使い方はmanマニュアルとREADME, EXAMPLEを見れば分かりますが下記に例示しておきます。

複数ノードからそれぞれ別のノードにabを掛ける。

この手のツールは、同じコマンドを同時に実行させてやることはできても、違うコマンドを実行させることができません。なので、実際にabを実行するノード上に次のようなワンライナーを用意してやります。

#!/bin/dash
ab -k -c $1 -n $2 xxx.xxx.xxx.xxx/

別のノードでは、IPアドレスを別のサーバのものにしたワンライナーを用意しておきます。1対1で対応していたので楽ですね。

musshを導入したホストでは次のようなシェルスクリプトを用意します。

#!/bin/sh

CONN=1000
INCR=10000
REQ_BEGIN=100000
REQ_END=300000
DATE=$(date +%Y%m%d-%H%M%S)

func_mussh () {
mussh -h user1@xxx.xxx.xxx.xxx user2@yyy.yyy.yyy.yyy zzz.zzz.zzz.zzz \
        -m3 -b \
        -i /home/user/test/id_rsa \
        -c "sh ab.sh $1 $2"
}

for i in $(seq $REQ_BEGIN $INCR $REQ_END)
do
echo "request: $i"
func_mussh $CONN $i > log/ab-${i}-${DATE}.log
sleep 10
done
  • “-h”オプションでコマンドを実行させたいノードを半角スペース区切りで羅列します。ユーザが異なる場合はSSHラッパーなので上記のように”user@”をprefixで指定してやります
  • “-mN”で並列度を指定します。上記では3台のノードに対して同時に実行するために”-m3”と指定しています
  • “-b”をつけることで出力をノード毎にまとめてくれます。こうすると、関数func_musshでリダイレクトしている結果が、
user2@yyy.yyy.yyy.yyy: This is ApacheBench, Version 2.3 <$Revision: 655654 $>
user2@yyy.yyy.yyy.yyy: Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
user2@yyy.yyy.yyy.yyy: Licensed to The Apache Software Foundation, http://www.apache.org/
(snip)
user2@yyy.yyy.yyy.yyy: 95%      9
user2@yyy.yyy.yyy.yyy: 98%     20
user2@yyy.yyy.yyy.yyy: 99%     33
user2@yyy.yyy.yyy.yyy: 100%    421 (longest request)
user1@xxx.xxx.xxx.xxx: This is ApacheBench, Version 2.3 <$Revision: 655654 $>
user1@xxx.xxx.xxx.xxx: Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
user1@xxx.xxx.xxx.xxx: Licensed to The Apache Software Foundation, http://www.apache.org/
user1@xxx.xxx.xxx.xxx: Benchmarking aaa.aaa.aaa.aaa (be patient)
user1@xxx.xxx.xxx.xxx: Completed 1000 requests
user1@xxx.xxx.xxx.xxx: Completed 2000 requests
(snip)

のように対象ノード毎にまとめられた形で出力されます。

  • “-i”オプションを使うとSSH公開鍵認証の秘密鍵を指定します。これもOpenSSHのsshコマンドと同じですね
  • “-c”オプションで実行させたいコマンドを指定します。今回はseqコマンドでリクエスト数を10000ずつ増分させるようにループ処理しています。セミコロン”;”で区切れば複数コマンドを渡すこともできます

musshでできないこと

musshでは対話形式のコマンドには対応していません。なので、 visiblepwを有効にしてやっても 使えないものは使えません。sudoを使いたければ、特定コマンドだけをパスワードなしで実行できるユーザを用意してやるか、mussh自体がシェルスクリプトなのでsudo対応できるようにしてやるようにパッチでも書くと良いかもしれませんが、そもそもsudoで実行する必要があるようなコマンドをリモートホストから実行する、という運用自体が微妙ですね…。良い案があれば教えてください。 [1]

[1]セキュアOSを使う、という以外のワークアラウンドでw。