Amazon Web Services=AWSの話。実運用で使うかどうかは検討中なんだけど、とあるELBにぶら下がっているEC2インスタンスを自動的に取得して、それに対してデプロイ等を行うってのをPerlでやってみた。デプロイツールとしてCinnamonを使い、ELBやEC2情報を取得するのにAWS::CLIWrapperを利用した。
awscliのPerlラッパーであるAWS::CLIWrapperを使うにはそもそも「awscli」をインストールしなくてはいけないので入れる。
% sudo eazy_install awscli
これでawsコマンドが使えるようになるんだけど、補完が効いた方がいいので、設定する。zshの場合はちょっと工夫が必要で以下のようにする。どのファイルを扱うかはお好きなように。
% mkdir ~/.zsh && cd ~/.zsh % wget "https://raw.github.com/aws/aws-cli/develop/bin/aws_zsh_completer.sh" % echo "source ~/.zsh/aws_zsh_completer.sh" >> ~/.zshrc % source ~/.zshrc
ターミナルで素早くコマンドを試したい時にはこのawsコマンドを使う。
さて、ここからが本題。デプロイ先はEC2のPublic DNS Nameを利用すると仮定し、そのリストをAWS::CLIWrapperを使って取得し、Cinammonに渡せばいい。流れは以下の通り。
- elb describe-load-balancers を実行してターゲットとするELBの情報を一覧で取得する
- ELBの情報には、それぞれ組み付いているEC2インスタンスのIDのみが入っている
- ecs describe-instances を実行してEC2の情報を一覧で取得する
- 一覧をループで回して先ほどのELBと関連しているEC2のIDと比較する
- マッチしたらそのPublic DNS Nameを配列リファレンスに入れる
- Cinnamonの「Lazily evaluated」機能を使ってそのホスト情報でデプロイさせる
動作可能性の高いコードは以下の通り。具体的な設定をしたら動きました。
use AWS::CLIWrapper;
use Cinnamon::DSL;
use YAML;
my $aws = AWS::CLIWrapper->new();
role api => sub {
my $res = $aws->elb('describe-load-balancers');
die Dump $AWS::CLIWrapper::Error unless $res;
my $elb;
for my $r (@$res) {
if ( $r->{LoadBalancerName} eq 'myapp-test-elb' ) {
$elb = $r;
}
}
die get('target_elb_name') . " is not found." unless $elb;
$res = $aws->ec2('describe-instances');
die Dump $AWS::CLIWrapper::Error unless $res;
my $hosts;
for my $r ( @{ $res->{Reservations} } ) {
for my $i ( @{ $r->{Instances} } ) {
for my $elb_instance ( @{ $elb->{Instances} } ) {
if ( $i->{InstanceId} eq $elb_instance->{InstanceId} ) {
push @$hosts, $i->{PublicDnsName};
}
}
}
}
return $hosts;
},
{ deploy_to => '/home/user/www/myapp', };
task deploy => {
update => sub {
my ( $host, @args ) = @_;
my $deploy_to = get('deploy_to');
remote {
run "cd $deploy_to && git fetch origin && git checkout -q origin/master && git submodule update --init";
}
$host;
},
};