複数サーバに一括でコマンド投入する手法はpssh, tomahawk, ansible , 初心に戻ってのssh forループなど様々ありますが自分は、
- yum一発で簡単にインストールできる
- 各サーバ間での設定ファイルなどの差分が一発でわかる
の2点からpdsh(Parallel Distributed Shell) を利用していました。
特に 各サーバ間での設定ファイルなどの差分が一発でわかる のメリットが大きかったです。
数百台運用していた時に完全にansible化できていなかった(運用途中でansible使い出した)ため、例えばWebサーバの用途ごとに apache や cron の設定が微妙に違うサーバ群を操作する場合など重宝してました。
今回はAWS上のEC2 (Amazon Linux)を3台使用して手順を紹介していきます。
pdshの使用方法
インストール
epel リポジトリを利用します。
$ sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
pdsh は環境に合わせて利用できるように機能がパッケージごとに分割されています。
$ yum search pdsh
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
194 packages excluded due to repository priority protections
===================================================================================== N/S matched: pdsh ======================================================================================
pdsh-mod-dshgroup.x86_64 : Provides dsh-style group file support for pdsh
pdsh-mod-genders.x86_64 : Provides libgenders support for pdsh
pdsh-mod-netgroup.x86_64 : Provides netgroup support for pdsh
pdsh-mod-nodeupdown.x86_64 : Provides libnodeupdown support for pdsh
pdsh-mod-torque.x86_64 : Provides support for running pdsh under Torque jobid
pdsh-rcmd-rsh.x86_64 : Provides bsd rcmd capability to pdsh
pdsh-rcmd-ssh.x86_64 : Provides ssh rcmd capability to pdsh
pdsh.x86_64 : Parallel remote shell program
一般的な環境では、pdsh本体とpdsh-mod-dshgroup(-g オプションでグループ指定できるようにする)をインストールすれば十分だと思います。
pdsh-rcmd-sshは依存関係で自動的にインストールされます。
$ sudo yum install -y pdsh pdsh-mod-dshgroup
...
==============================================================================================================================================================================================
Package Arch Version Repository Size
==============================================================================================================================================================================================
Installing:
pdsh x86_64 2.31-1.el7 epel 119 k
pdsh-mod-dshgroup x86_64 2.31-1.el7 epel 7.3 k
Installing for dependencies:
ncurses-compat-libs x86_64 6.0-8.20170212.amzn2.1.3 amzn2-core 308 k
pdsh-rcmd-ssh x86_64 2.31-1.el7 epel 8.1 k
Transaction Summary
==============================================================================================================================================================================================
Install 2 Packages (+2 Dependent packages)
...
$
$ rpm -ql pdsh
/usr/bin/dshbak
/usr/bin/pdcp
/usr/bin/pdsh
/usr/bin/rpdcp
/usr/lib64/pdsh
/usr/lib64/pdsh/execcmd.so
...
インストール後、-L オプションでモジュールを確認できます。
% pdsh -L
3 modules loaded:
Module: misc/dshgroup
Author: Mark Grondona <mgrondona@llnl.gov>
Descr: Read list of targets from dsh-style "group" files
Active: yes
Options:
-g groupname target hosts in dsh group "groupname"
-X groupname exclude hosts in dsh group "groupname"
Module: rcmd/exec
Author: Mark Grondona <mgrondona@llnl.gov>
Descr: arbitrary command rcmd connect method
Active: yes
Module: rcmd/ssh
Author: Jim Garlick <garlick@llnl.gov>
Descr: ssh based rcmd connect method
Active: yes
%
pdsh
それではpdshを試していきたいと思います。
前提として、sshを利用してアクセスするので、
- IPアドレス : 172.31.0.10 〜 12
- ホスト名 : ip-172-31-0-10 〜 12
の3台において、10のサーバ から他のサーバへ公開鍵認証でログインできる状態であるとします。
-w でターゲットを直接指定します。ホスト名、IPどちらも指定できます。
$ pdsh -w ip-172-31-0-10,ip-172-31-0-11,ip-172-31-0-12 whoami
ip-172-31-0-12: ec2-user
ip-172-31-0-11: ec2-user
ip-172-31-0-10: ec2-user
$
$
$ pdsh -w 172.31.0.10,172.31.0.11,172.31.0.12 whoami
172.31.0.11: ec2-user
172.31.0.12: ec2-user
172.31.0.10: ec2-user
$
正規表現チックに [ ] で指定もできます。
$ pdsh -w ip-172-31-0-1[0-2] whoami
ip-172-31-0-12: ec2-user
ip-172-31-0-11: ec2-user
ip-172-31-0-10: ec2-user
$
$ pdsh -w ip-172-31-0-1[0-1],ip-172-31-0-12 whoami
ip-172-31-0-12: ec2-user
ip-172-31-0-11: ec2-user
ip-172-31-0-10: ec2-user
$
$ pdsh -w ip-172-31-[0-1]-1[0-2] whoami
ip-172-31-0-11: ec2-user
ip-172-31-0-12: ec2-user
ip-172-31-0-10: ec2-user
ip-172-31-1-12: ssh: connect to host ip-172-31-1-12 port 22: No route to host
pdsh@ip-172-31-0-10: ip-172-31-1-12: ssh exited with exit code 255
ip-172-31-1-10: ssh: connect to host ip-172-31-1-10 port 22: No route to host
pdsh@ip-172-31-0-10: ip-172-31-1-10: ssh exited with exit code 255
ip-172-31-1-11: ssh: connect to host ip-172-31-1-11 port 22: No route to host
pdsh@ip-172-31-0-10: ip-172-31-1-11: ssh exited with exit code 255
$
-g でターゲットをリスト化し、そのファイルを指定して実行できます。
. (ドット)のカレントディレクトリから指定してください。
$ cat hoge/list.txt
ip-172-31-0-10
ip-172-31-0-11
ip-172-31-0-12
$
$
$ pdsh -g ./hoge/list.txt whoami
ip-172-31-0-11: ec2-user
ip-172-31-0-12: ec2-user
ip-172-31-0-10: ec2-user
$
以下のようにDSHGROUP_PATH にファイルを置けばグループ名のみで指定できます。
自分は↑で運用しちゃってましたが、こちらが本来の使い方と思われます。
$ cat ~/.dsh/group/hoge
ip-172-31-0-10
ip-172-31-0-11
$
$
$ cat /etc/dsh/group/fuga
ip-172-31-0-12
$
$
$ pdsh -g hoge,fuga whoami
ip-172-31-0-12: ec2-user
ip-172-31-0-11: ec2-user
ip-172-31-0-10: ec2-user
$
そして自分が一番ありがたかった出力を整形する dshbak です。パイプで渡すと表示が同じものを取りまとめて表示してくれます。
100台中、数台だけ違うサーバがいるなどの環境を運用するときマジ助かってましたmm
$ pdsh -g ./hoge/list.txt uptime | dshbak -c
----------------
ip-172-31-0-10
----------------
12:41:10 up 41 min, 1 user, load average: 0.02, 0.01, 0.00
----------------
ip-172-31-0-[11-12]
----------------
12:41:10 up 41 min, 0 users, load average: 0.00, 0.00, 0.00
$
pdcp/rpdcp
pdcp で一括でターゲットへコピーできます。-r ,-p など通常のcpコマンドと同様のオプションもあります。
注意事項としてpdcp はターゲット自体にpdshがインストールされている必要があります。それこそpdshでサクッとインストールしちゃいましょう。
$ pdsh -g hoge,fuga cat /var/tmp/hoge.txt
ip-172-31-0-11: cat: /var/tmp/hoge.txt: No such file or directory
pdsh@ip-172-31-0-10: ip-172-31-0-11: ssh exited with exit code 1
ip-172-31-0-12: cat: /var/tmp/hoge.txt: No such file or directory
pdsh@ip-172-31-0-10: ip-172-31-0-12: ssh exited with exit code 1
ip-172-31-0-10: testes
$
$
$ pdcp -g hoge,fuga ./hoge.txt /var/tmp
$
$
$ pdsh -g hoge,fuga cat /var/tmp/hoge.txt
ip-172-31-0-11: testes
ip-172-31-0-12: testes
ip-172-31-0-10: testes
$
rpdcpで逆にターゲットからローカルへコピーできます。ファイル末尾にターゲット名が付与されます。
$ rpdcp -g hoge,fuga /var/tmp/hoge.txt /var/tmp
$
$
$ ls -1 /var/tmp
...
hoge.txt.ip-172-31-0-10
hoge.txt.ip-172-31-0-11
hoge.txt.ip-172-31-0-12
$
Tips
デフォルトではssh鍵は.ssh/id_rsa を見に行ってますが 環境変数、PDSH_SSH_ARGS、PDSH_SSH_ARGS_APPENDでsshオプションを上書き・追加することで指定できます。
$ export PDSH_SSH_ARGS_APPEND='-i ~/hoge.pem'
tail -f もできちゃいます。
$ pdsh -g hoge,fuga "sudo tail -f /var/log/messages"
ip-172-31-0-10: Oct 29 00:49:30 ip-172-31-0-10 dhclient[3008]: XMT: Solicit on eth0, interval 130140ms.
ip-172-31-0-10: Oct 29 00:49:51 ip-172-31-0-10 systemd: Started Session 187 of user ec2-user.
....
ip-172-31-0-12: Oct 29 00:50:01 ip-172-31-0-12 systemd: Started Session 185 of user root.
ip-172-31-0-12: Oct 29 00:50:01 ip-172-31-0-12 systemd: Starting Session 185 of user root.
....
p-172-31-0-11: Oct 29 00:49:48 ip-172-31-0-11 ec2net: [rewrite_aliases] Rewriting aliases of eth0
ip-172-31-0-11: Oct 29 00:49:51 ip-172-31-0-11 systemd: Started Session 189 of user ec2-user.
pdshというよりsudoの挙動ですが、リダイレクトしたいときはsh -c で対応できます。
$ pdsh -w ip-172-31-0-1[0-2] 'sudo "tail -1 /var/log/messages > /var/log/hoge.log"'
ip-172-31-0-11: sudo: tail -1 /var/log/messages > /var/log/hoge.log: コマンドが見つかりません
pdsh@ip-172-31-0-10: ip-172-31-0-11: ssh exited with exit code 1
ip-172-31-0-12: sudo: tail -1 /var/log/messages > /var/log/hoge.log: コマンドが見つかりません
pdsh@ip-172-31-0-10: ip-172-31-0-12: ssh exited with exit code 1
ip-172-31-0-10: sudo: tail -1 /var/log/messages > /var/log/hoge.log: コマンドが見つかりません
pdsh@ip-172-31-0-10: ip-172-31-0-10: ssh exited with exit code 1
$
$
$ pdsh -w ip-172-31-0-1[0-2] 'sudo tail -1 /var/log/messages > /var/log/hoge.log'
ip-172-31-0-11: bash: /var/log/hoge.log: Permission denied
pdsh@ip-172-31-0-10: ip-172-31-0-11: ssh exited with exit code 1
ip-172-31-0-12: bash: /var/log/hoge.log: Permission denied
pdsh@ip-172-31-0-10: ip-172-31-0-12: ssh exited with exit code 1
ip-172-31-0-10: bash: /var/log/hoge.log: Permission denied
pdsh@ip-172-31-0-10: ip-172-31-0-10: ssh exited with exit code 1
$
$
$ pdsh -w ip-172-31-0-1[0-2] 'sudo sh -c "tail -1 /var/log/messages > /var/log/hoge.log"'
$
今回は以上です〜ノシ
参考
あざ━━ヾ(゚Θ゚)ノ━━すっ♪
pdsh(1) – Linux man page
並列SSH pdsh(Parallel Distributed Shell)
sudo で書き込みをしたい
pdsh – HostListExpressions.wiki