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; }, };