今日も飽きずに過去のメモを掘り起こして記事にしました
全台、もしくは一部のサーバに対して一斉にコマンド実行したい場合があります。
調べてみると色々な方法があるみたいなので、いくつか紹介します。
他にあれば随時追加するかも。
tmux
ローカルPCにtmuxをインストールし、~/.tmux.conf
に以下の設定を追加します。
# $HOME/.tmux.conf
bind e setw synchronize-panes on
bind E setw synchronize-panes off
同じWindowに複数paneを開いてそれぞれ複数サーバにSSHログインし、<bind>+e
すると、paneで操作を同期することができます。
<bind>+E
で同期が終了します。
メリット
デメリット
- 複数panelを立ち上げてそれぞれサーバにログインするのが面倒
- panel同期後、コマンド補完ができなかったりするため、予め実行するコマンドをまとめておいて、コピペして実行した方が良い
参考URL
pdsh(Parallel Distributed Shell)
https://code.google.com/p/pdsh/
インストール
$ sudo yum --enablerepo=epel install pdsh
$ pdsh -V
pdsh-2.26 (+readline+debug)
rcmd modules: ssh,exec (default: ssh)
misc modules: (none)
基本的な使い方
$ pdsh -w foo_server[1,2] "hostname"
foo_server1: foo_server1
foo_server2: foo_server2
sudo を使う場合そのままでは渡せないので、次のように強制的にttyを飛ばすようにします。
# $HOME/.ssh/PASS
<sudoのパスワード>
$ chmod 600 ~/.ssh/PASS
$ export PDSH_SSH_ARGS="-tt"
$ pass=$(cat ~/.ssh/PASS) && pdsh -w foo_server[1,2] "echo $pass | sudo -S ls /root 2> /dev/null" 2> /dev/null | dshbak
----------------
foo_server1
----------------
hoge_dir
----------------
foo_server2
----------------
hoge_dir
sudo権限で/root
をlsコマンドで見るようにしてみました。$HOME/.ssh/PASS
からsudoパスワードを読み込むことでヒストリに残さないようにしています。dshbak
コマンドを使うことで出力を見やすくできるのでよく使っています。
メリット
- ホスト指定が正規表現で指定ができる
デメリット
pssh(pararell-ssh)
https://code.google.com/p/parallel-ssh/
インストール
$ sudo yum --enablerepo=epel install pssh
$ pssh --version
2.3.1
使い方
$ pssh -i --host=foo_server1 -l foo_user -i "cat /etc/redhat-release"
[1] 16:29:28 [SUCCESS] foo_server1
CentOS release 6.5 (Final)
複数ホストを実行したい場合は、--host(-H)
オプションを複数付けてもできるが、ホスト一覧のファイルを用意して-h
オプションで指定した方が楽です。
# hostlist.txt
foo_server1
foo_server2
$ pssh -i -h ./hostlist.txt -l foo_user -i "cat /etc/redhat-release"
[1] 17:20:19 [SUCCESS] foo_server1
CentOS release 6.5 (Final)
[2] 17:20:19 [SUCCESS] foo_server2
CentOS release 6.5 (Final)
しかし、パスフレーズ付きの秘密鍵の場合、パスワードの入力が求められます。
解決するには、苦し紛れですがソースを改変します。
# /usr/lib/python2.6/site-packages/psshlib/askpass_client.py L.69
if not prompt.strip().lower().endswith('password:'):
sys.stderr.write(prompt)
sys.stderr.write('\n')
#sys.exit(1) # コメントアウト
--ask
オプションを付けるとパスワードを聞かれるのでそれに返すとコマンドを実行できます。
Stderr
が出ていて気持ち悪いが気にしないことにします。
$ pssh --ask -i --host=foo_server1 -l foo_user -i "cat /etc/redhat-release"
Warning: do not enter your password if anyone else has superuser
privileges or access to your account.
Password:
[1] 17:07:34 [SUCCESS] foo_server1
CentOS release 6.5 (Final)
Stderr: Enter passphrase for key '/home/foo_user/.ssh/id_rsa':
sudoを使う場合は -x 'tt'
で強制的にttyを飛ばすようにすれば良いです。
# $HOME/.ssh/PASS
<sudoのパスワード>
$ chmod 600 ~/.ssh/PASS
$ pass=$(cat ~/.ssh/PASS) && pssh --ask -i -x '-tt' --host=foo_server1 -l foo_user -i "echo $pass | sudo -S ls /root" 2> /dev/null
Warning: do not enter your password if anyone else has superuser
privileges or access to your account.
Password:
[1] 17:10:59 [SUCCESS] foo_server1
[sudo] password for foo_user:
scripts
Stderr: Enter passphrase for key '/home/foo_user/.ssh/id_rsa':
tcgetattr: Invalid argument
Connection to foo_server1 closed.
メリット
デメリット
Stderr
が出てくるので気持ち悪い
最後に
ここまで書いてふと思ったのがAnsibleでもできるかなと思いました。
良い方法があれば教えてください。