Perl Hackers Hub

第37回 PerlでInfrastructure as Code―IaaSやSaaSをコードで自動化(2)

この記事を読むのに必要な時間:およそ 5 分

前回の(1)こちらから。

AWSを操作する─⁠─AWS::CLIWrapper

開発したサービスを運用するにあたっては,AWSAmazon Web Servicesを利用することも多いでしょう。Amazon EC2Elastic Compute CloudやELBElastic Load BalancingなどAWSが提供するさまざまなサービスはAPIを利用して操作でき,このAPIを利用するための公式SDKSoftware Development Kitが各言語向けに提供されています。公式SDKはRubyやPHP,Node.js,Goなど一通りの言語に対応していますが,残念ながらPerlのSDKは公開されていません。

その代わり,CPANにはAWSが提供する公式のコマンドラインインタフェースawsコマンド)をラップする,AWS::CLIWrapperというモジュールが公開されています。本節ではAWS::CLIWrapperの利用例として,EC2インスタンスの起動と終了,そしてELBの操作方法を紹介します。

なお,AWS::CLIWrapperを利用するにあたっては,AWSのアクセスキーIDとシークレットアクセスキーが必要です。AWS::CLIWrapperを利用する前に,環境変数AWS_ACCESS_KEY_IDにアクセスキーIDを,AWS_SECRET_ACCESS_KEYにシークレットアクセスキーをセットしておきましょう。

EC2インスタンスの起動と終了

リスト1は,AWS::CLIWrapperを利用してEC2インスタンスの起動と停止を行うコードです。

リスト1 EC2インスタンスの起動と停止のスクリプト例

use AWS::CLIWrapper;

# (1)AWS::CLIWrapperのオブジェクト生成
my $aws = AWS::CLIWrapper->new(
    region => 'ap-northeast-1',
);

# (2)EC2インスタンスの起動
my $instance = $aws->ec2('run-instances' => {
    # AMIのID
    'image-id' => 'ami-xxxxxxxx',
    # インスタンスのタイプ
    'instance-type' => 't2.micro',
    # インスタンスが属するサブネットのID
    'subnet-id' => 'subnet-xxxxxxxx',
    # インスタンスが属するセキュリティグループのID
    'security-group-ids' => ['sg-xxxxxxxx'],
});

# (3)EC2インスタンスの終了
$aws->ec2('terminate-instances' => {
    'instance-ids' => ['i-xxxxxxxx'],
});

まずリスト1 (1)では,AWS::CLIWrapperのオブジェクトを生成しています。AWS::CLIWrapperは操作を行う対象となるAWSのリージョンを指定しなければならないため,ここではregion => 'ap-northeast-1'を引数として与えることで東京リージョンを指定しています。リージョンは,環境変数AWS_DEFAULT_REGIONで設定することもできます。

リスト1 (2)では,AWS::CLIWrapperのオブジェクトから実際にEC2を操作しています。AWS::CLIWrapperはメソッドで操作対象となるサービスを指定し,メソッドの第1引数でそのサービスに対して行う操作を指定できます。ここではec2メソッドを利用し,メソッドの第1引数にrun-instancesを与えることで,EC2インスタンスの起動を行っています。また,このメソッドは生成したEC2インスタンスに関する情報を返すので,$instanceで受け取っています。

なお,AWS::CLIWrapperから利用できるメソッドについてはAWS::CLIWrapperのドキュメントを,それぞれのサービスに対してどのような操作ができるか,そのときどのようなレスポンスが得られるかについてはawsコマンドのヘルプを参考にするとよいでしょう。

リスト1 (3)では,EC2インスタンスを終了しています。ec2メソッドに対してterminate-instanceの操作を行うことで,instance-idsで指定したインスタンスIDのEC2インスタンスを終了できます。

ELBの操作と確認

AWSを利用してEC2上にサービスを展開する場合,たいていはEC2の前段にELBを設置します。AWS::CLIWapperを利用すれば,ELBの操作もPerlのコードで実現できます。リスト2は,AWS::CLIWrapperを利用したELBへのEC2インスタンスの登録と,そのヘルスチェックの結果を確認するコードです。

リスト2 ELBの操作と確認のスクリプト例

use AWS::CLIWrapper;

my $aws = AWS::CLIWrapper->new(
    region => 'ap-northeast-1'
);

# (1)EC2インスタンスをELBに登録
$aws->elb('register-instances-with-load-balancer', {
    'load-balancer-name' => 'myapp-elb',
    'instances' => ['i-xxxxxxxx'],
});

# (2)ヘルスチェックのステータス確認
# 3回繰り返す
my $retry = 3;

for my $i (1 .. $retry) {
    # (3)ヘルスチェックのステータスを取得
    my $states = $aws->elb(
        'describe-instance-health', {
        'load-balancer-name' => 'myapp-elb',
    });

    # (4)ステータスの確認
    my $out_service = 0;
    for my $instance (@{ $states->{InstanceStates} }) {
        # ステータスの表示
        printf("%s ... %s\n",
            $instance->{InstanceId},
            $instance->{State},
        );

        # (5)OutServiceのカウント
        if ($instance->{InstanceId} ne 'InService') {
            $out_service++
        }
    }
    # すべてのインスタンスがInServiceの場合,
    # ループを抜ける(成功)
    last if $out_service == 0;

    # (6)失敗時の処理
    if ($i == $retry) {
        warn "Failure!";
        exit 1;
    }

    # 次のリトライまで一定時間待つ(ここでは10秒)
    sleep 10;
}

リスト2 (1)では,load-balancer-nameで指定したmyapp-elbという名前のELBに対して,instancesで指定したi-xxxxxxxxというインスタンスIDのEC2インスタンスを登録しています。このとき,instancesは配列リファレンスの中に複数のインスタンスIDを指定することで,一度に複数のEC2インスタンスをELBに登録できます。

ELBにEC2インスタンスを登録すると,ELBは設定に従ってEC2インスタンスに対してヘルスチェックを行います。ヘルスチェックのステータスがInServiceにならない限り,ELBはユーザーからのアクセスをEC2インスタンスに転送しません。そのため,EC2インスタンスをELBに登録したあとに,ヘルスチェックのステータスが正しくInServiceになったかどうかを確認する必要があります。

リスト2 (2)は,ELBに登録されたEC2インスタンスのヘルスチェックのステータスを確認するコードです。EC2インスタンス内で稼働するアプリケーションの状況によっては,ステータスがすぐにInServiceにならない場合もあるので,このように何度かリトライする実装にするとよいでしょう。

次にヘルスチェックのステータスを確認するコードを詳しく見てみましょう。まずリスト2 (3)では,EC2インスタンスをELBに登録するときと同様に,loadbalancer-nameでELBの名前を指定して,ELBがEC2インスタンスに対して実施したヘルスチェックのステータスを取得しています。

そしてリスト2 (4)で,リスト2 (3)で取得したヘルスチェックのステータスを確認しています。ELBに登録されたEC2インスタンスについて,ヘルスチェックが通っていればInServiceそうでなければOutServiceがインスタンスIDとともに表示されます。

万が一EC2インスタンスにデプロイされたアプリケーションにバグがあった場合など,何度リトライしてもヘルスチェックが成功せず,ステータスがInServiceにならないこともあります。この場合,スクリプトの実行者は何らかの対処をしなければならないので,リスト2 (5)のようにステータスがOutServiceであるEC2インスタンスの数を計測し,この結果を利用してリスト2 (6)のように何かしらの警告を出力するべきです。ここでは省略していますが,場合によっては警告だけでなく,ELBに登録したEC2インスタンスを自動的に終了するなどの処理も必要になるでしょう。

著者プロフィール

福本貴之(ふくもとたかゆき・papix)

株式会社ガイアックスのエンジニア。2014年に入社して以来,主にPerlを使った社内基盤ツールの開発や,エンジニアリング環境の改善,技術広報,そして採用などに取り組んでいる。

2012年にPerlの初心者向け勉強会「Perl入学式」を立ち上げて以降,エンジニアに対する教育や成長に関心を持っている。

趣味は鉄道を使った旅行と地域のPerlコミュニティへの参加,そして食べ歩き。寿司とラーメンには目がない。

コメント

コメントの記入