linux

Linux pdsh/pdcp 複数サーバに一括でコマンド実行/コピーする

複数サーバに一括でコマンド投入する手法はpssh, tomahawk, ansible , 初心に戻ってのssh forループなど様々ありますが自分は、

  • yum一発で簡単にインストールできる
  • 各サーバ間での設定ファイルなどの差分が一発でわかる

の2点からpdsh(Parallel Distributed Shell) を利用していました。

特に「差分が一発でわかる」のメリットが大きかったです。

数百台運用していた時に完全にansible化できていなかった(運用途中でansible使い出した)ため、例えばWebサーバの用途ごとに apache や cron の設定が微妙に違うサーバ群を操作する場合など重宝してました。

今回はAWS上のEC2 (Amazon Linux)を3台使用して手順を紹介していきます。

スポンサーリンク

手順

インストール

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
$ 

補足

デフォルトでは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