天然パーマです。

ELB配下のEC2インスタンスにデプロイをする

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

参考リンク