前回の(1)はこちら から。
AWSを操作する──AWS::CLIWrapper
開発したサービスを運用するにあたっては、AWS(Amazon Web Services )を利用することも多いでしょう。Amazon EC2(Elastic Compute Cloud )やELB(Elastic Load Balancing )などAWSが提供するさまざまなサービスはAPIを利用して操作でき、このAPIを利用するための公式SDK(Software 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;
# AWS::CLIWrapperのオブジェクト生成
my $aws = AWS::CLIWrapper->new(
region => 'ap-northeast-1',
);
# 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'],
});
# 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'
);
# EC2インスタンスをELBに登録
$aws->elb('register-instances-with-load-balancer', {
'load-balancer-name' => 'myapp-elb',
'instances' => ['i-xxxxxxxx'],
});
# ヘルスチェックのステータス確認
# 3回繰り返す
my $retry = 3;
for my $i (1 .. $retry) {
# ヘルスチェックのステータスを取得
my $states = $aws->elb(
'describe-instance-health', {
'load-balancer-name' => 'myapp-elb',
});
# ステータスの確認
my $out_service = 0;
for my $instance (@{ $states->{InstanceStates} }) {
# ステータスの表示
printf("%s ... %s\n",
$instance->{InstanceId},
$instance->{State},
);
# OutServiceのカウント
if ($instance->{InstanceId} ne 'InService') {
$out_service++
}
}
# すべてのインスタンスがInServiceの場合、
# ループを抜ける(成功)
last if $out_service == 0;
# 失敗時の処理
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インスタンスを自動的に終了するなどの処理も必要になるでしょう。
Mackerelを操作する──WebService::Mackerel
サービスを運用するにあたり、サービスが動くサーバの管理と監視は必要不可欠です。サーバの管理や監視を行うツールにはさまざまなOSS(Open Source Software )やSaaS(Software as a Service )が提供されています。その中でも今回は、はてなが提供するSaaSであるMackerel と、そのAPIをPerlから操作するWebService::Mackerelの使い方の一例を紹介します。
ホストの取得
リスト3 は、WebService::Mackerelを利用して、Mackerelで管理しているすべてのサーバのホスト名を表示するコードです。
リスト3 ホストの取得スクリプトの例
use WebService::Mackerel;
use JSON;
# WebService::Mackerelのオブジェクト生成
my $mkr = WebService::Mackerel->new(
api_key => 'key',
service_name => 'service',
);
# ホスト一覧の取得
my $response = decode_json( $mkr->get_hosts );
my $hosts = $response->{hosts};
# ホスト名の表示
for my $host (@{ $hosts }) {
printf "%s\n", $host->{name};
}
リスト3 (1) では、WebService::Mackerelのオブジェクトを生成しています。このとき、MackerelのAPIキーをapi_key
というパラメータとして与える必要がありますので、あらかじめMackerelのオーガニゼーションの詳細画面からAPIキーを作成しておきましょう。また、APIキーに対応したオーガニゼーションに存在するサービスの名前をservice_name
というパラメータとして与える必要があります。
リスト3 (2) では、WebService::Mackerelのオブジェクトからget_hosts
メソッドを利用して、Mackerelで管理しているサーバの一覧を取得しています。WebService::Mackerelでは、APIにアクセスする各種メソッドはAPIのレスポンスであるJSONを文字列として返すので、JSONモジュールを利用してPerlのデータ構造に変換しています。
最後にリスト3 (3) では、APIを利用して取得したサーバ一覧から、ホスト名を表示しています。ここではホストの名前だけを利用していますが、Mackerelのサーバ一覧取得APIではこれ以外にもサーバのIPアドレスやMackerel上でのステータスなど、さまざまな情報を取得できます。詳しくは、MackerelのAPIドキュメントを参照してください。
ちなみに筆者は、Amazon VPC(Virtual Private Cloud )内に用意したSSH接続用の踏み台サーバに接続した際、VPC内で稼働しているサーバの情報を表示するスクリプトが実行されるようにしています。VPC内で稼働しているサーバはすべてMackerelで管理されているため、WebService::Mackerelを利用したスクリプトを用意すれば、その情報を取得できます。これによって、踏み台サーバに接続するだけで、VPC内で稼働しているサーバ(EC2インスタンス)のIPアドレスとインスタンスサイズ、そしてMackerel上のステータスを図1 のフォーマットで確認できるようになっています。
図1 Mackerelで管理しているホスト一覧の表示例
App
10.0.xxx.xxx (instance-size) ... working
10.0.xxx.xxx (instance-size) ... working
Worker
10.0.xxx.xxx (instance-size) ... working
10.0.xxx.xxx (instance-size) ... working
監視パラメータの取得と変更
Mackerelには監視パラメータの変更APIがあり、メトリック監視においてWarning、Criticalとなる閾値(いきち)を変更できます。監視パラメータの変更はMackerelが提供する公式のコマンドラインインタフェース(mkrコマンド)で実装できますが、WebService::Mackerelでも実現できます。
リスト4 は、WebService::MackerelでMackerelの監視パラメータを取得するコードです。監視パラメータはWebService::Mackerelのget_monitor
メソッドで取得できます。
リスト4 Mackerelの監視パラメータ取得スクリプトの例
use WebService::Mackerel;
use JSON;
use Data::Dumper;
my $mkr = WebService::Mackerel->new(
api_key => 'key',
service_name => 'service',
);
# 監視パラメータの取得
my $payload = decode_json( $mkr->get_monitor );
my $monitors = $payload->{monitors};
# 監視パラメータの表示
print Dumper $monitors;
このコードを実行すると、図2 の出力を得ることができます。この出力から、現在Mackerel上でconnectivity
(サーバの疎通確認)と、host
に対するcpu%
(CPU利用率)の2つの監視パラメータが設定されていることがわかります。そしてcpu%
については、warning
が50%で、critical
が80%でそれぞれアラートが通知されることなどがわかります。
図2 取得した監視パラメータの例
$VAR1 = [
{
'scopes' => [],
'excludeScopes' => [],
'id' => 'xxxxxxxxxxx',
'type' => 'connectivity'
},
{
'operator' => '>',
'name' => 'CPU %',
'metric' => 'cpu%',
'warning' => '50',
'type' => 'host',
'id' => 'yyyyyyyyyyy',
'duration' => 1,
'excludeScopes' => [],
'critical' => '80',
'scopes' => []
},
さらに、リスト5 に示すコードを利用して、監視パラメータの閾値を変更できます。監視パラメータの更新はリスト5 (1) のようにupdate_monitor
メソッドで行い、第1引数には監視パラメータのIDを、第2引数には監視パラメータの設定内容をそれぞれ指定します。このコードでは、cpu%
のアラート通知条件をwarning
は60%、critical
は90%にそれぞれ変更しています。
リスト5 Mackerelの監視パラメータ変更スクリプトの例
use WebService::Mackerel;
use JSON;
use Data::Dumper;
my $mkr = WebService::Mackerel->new(
api_key => 'key',
service_name => 'service',
);
# 監視パラメータの更新
$mkr->update_monitor('yyyyyyyyyyy', {
type => "host",
name => "CPU %",
metric => "cpu%",
duration => 1,
operator => ">",
warning => 60,
critical => 90,
scopes => [],
excludeScopes => [],
});
<続きの(3)はこちら 。>