読者です 読者をやめる 読者になる 読者になる

複数サーバで一括コマンド、スクリプト実行

複数サーバでコマンドやスクリプトを一括実行したい><
というときのメモ書きと自作スクリプトの紹介。


事前に『SSHでパスワードなしログイン & sudo』の設定が完了してる前提です。
※セキュリティや作業ミス時の影響範囲などを十分に考慮する必要があります。

シェルでベタ打ち

シェルでfor文、while文書くのを苦にしない人はこれで充分でしょう

$ for i in site1-app0{1..3};do echo "[$i]";ssh $i 'sudo crontab -l';done
$ cat site1-app.list | while read l;do echo "[$l]";ssh -n $l 'sudo crontab -l';done

ツールを使う

コマンド一括実行ツールもいろいろあります

capistranoRailsのデプロイなどに使われるツールですが、独自タスクを定義すればけっこうなんでもできちゃいますし、複数台に対する擬似的なシェルが使えたり、もちろんコマンド実行もできたりします。
これらのツールは各サーバで並列にコマンドやタスクを実行できるため、サーバ台数が多いときに非常に高速でオペレーションを実施できます。
※tomahawkはまだ使ったことないので今度試してみる

ちょっと便利に作業するためのスクリプト作ってみた

対象サーバの管理とスクリプトの実行機能が欲しかったので、3つのスクリプトを作ってみました

タグを指定してサーバのリストを出力するスクリプト
[mikeda@admin work]$ cat list/all_servers
site1-app01  site1,app
site1-app02  site1,app
site1-app03  site1,app,standby
site1-db01   site1,db
site1-db02   site1,db
test01       test,app,mail
...

[mikeda@admin work]$ ./print_sv site1 app
site1-app01
site1-app02
site1-app03
まとめてコマンドを実行するスクリプト
[mikeda@admin work]$ ./print_sv site1 app | ./ssh_run_cmd hostname
[site1-app01]
site1-app01

[site1-app02]
site1-app02

[site1-app03]
site1-app03
まとめてスクリプトを実行するスクリプト

まず実行したい処理をスクリプトで記述します。
例)apacheコンフィグをSubversionからアップデートしてgracefulするスクリプト

#!/bin/sh -x

sudo svn up /etc/httpd/conf /etc/httpd/conf.d
sudo /etc/init.d/httpd configtest && sudo /etc/init.d/httpd graceful

まとめて実行

$ ./print_sv site1 app | ./ssh_run_task task/apache_config_update.sh
[site1-app01]
+ sudo svn up /etc/httpd/
A    /etc/httpd/conf/httpd.conf
リビジョン 2 に更新しました。
リビジョン 2 です。
+ sudo /etc/init.d/httpd configtest
Syntax OK
+ sudo /etc/init.d/httpd graceful

[site1-app02]
+ sudo svn up /etc/httpd/
A    /etc/httpd/conf/httpd.conf
リビジョン 2 に更新しました。
リビジョン 2 です。
+ sudo /etc/init.d/httpd configtest
Syntax OK
+ sudo /etc/init.d/httpd graceful

[site1-app03]
+ sudo svn up /etc/httpd/
A    /etc/httpd/conf/httpd.conf
リビジョン 2 に更新しました。
リビジョン 2 です。
+ sudo /etc/init.d/httpd configtest
Syntax OK
+ sudo /etc/init.d/httpd graceful

実運用ではテスト用のサーバで事前に動作確認したほうがいいでしょう

[mikeda@admin work]$ echo site1-app03 | ./ssh_run_task task/httpd_config_update.sh
[mikeda@admin work]$ ./print_sv site1 app | grep -v site1-app03 | ./ssh_run_task task/apache_config_update.sh

ソースコード

print_sv
#!/usr/bin/perl
use strict;
use warnings;

my @tags = @ARGV;

open my $fh, "<", "list/all_servers";
while(<$fh>){
  next if /^\s*#/;
  chomp;

  my ($hostname, $sv_tags) = split;

  if($sv_tags){
    my @sv_tags = split ',', $sv_tags;
    print "$hostname\n" if check_tags(\@tags, \@sv_tags);
  }
}
close $fh;

sub check_tags {
  my ($tags, $sv_tags) = @_;
  my %check;
  $check{$_} = 0 for @$tags;
  for(@$sv_tags){
    $check{$_} = 1 if exists $check{$_};
  }
  return ! scalar(grep {$_ == 0} values %check);
}
ssh_run_cmd
#!/bin/bash
sleep_time=1

while read host;do
  echo "[$host]"
  ssh -n $host "$@"
  echo

  sleep $sleep_time
done
ssh_run_task
#!/bin/bash
sleep_time=1

script=$1
shift
remote_path=/tmp/`basename $script`

while read host;do
  echo "[$host]"
  scp -q $script $host:$remote_path
  ssh -n $host "chmod u+x $remote_path; $remote_path $@; /bin/rm $remote_path"
  sleep $sleep_time
  echo
done


sleep入れてるのはビビリだからです!
(スリープ中にCtrl+C押すと全部止められます。)




大量の手順書のスクリプト化、効率的な運用を模索中!