先日のエントリに書いたとおり、先月からAWSで色々やっているのですが、2台あるEC2インスタンスのウチ1台を毎日一定時間だけ停止してコストを抑えたいなぁという事で、自動で停止/起動するスクリプトを書いてみました。
何故、自分で書いたのかというとAWS SDKを使った情報ってRubyのものが多くて、PHPな人である自分にとってはメンテが難しいのと、コレだけのためにRubyを導入するのもスマートじゃ無いという事で、少ない情報を駆使しながら自分で作ってみました。まぁ、Rubyのコードを参考にはしたのですが。
まずはAWS SDK for PHPを導入します。さっくりとyumでインストールできるので楽です。
sudo yum install php-amazon-sdk2
インストールしたら、今回のスクリプトのための設定ファイルを用意します。
<?php $config = array( 'key' => 'アクセスキー', 'secret' => 'シークレットアクセスキー', 'region' => 'ap-northeast-1(これは東京)', ); ?>
これを /etc/aws_ec2.config.inc.php というファイル名で配置しました。
起動用スクリプトはこんな感じ。
<?php require 'AWSSDKforPHP/aws.phar'; require_once '/etc/aws_ec2.config.inc.php'; use Aws\Ec2\Ec2Client; $instancelist = array( 'Instance ID', ); $instanceipaddress_map = array( 'Instance ID' => 'ElasticIP', ); $ec2 = Ec2Client::factory($config); // インスタンス起動処理 foreach ($instancelist as $ins) { // インスタンスのステータスチェック $response = $ec2->describeInstances( array( 'InstanceIds' => array($ins,), ) ); foreach ($response['Reservations'] as $instances_no => $reservations) { foreach ($reservations as $key => $value) { if ($key == "Instances") { foreach ($value as $k => $v) { if ($v['InstanceId'] == $ins) { $ins_status_name = $v['State']['Name']; if ($ins_status_name == "stopped") { // インスタンスの起動 $res = $ec2->startInstances( array( 'InstanceIds' => array($ins,), ) ); } } } } } } } // ElasticIP割当処理 foreach ($instanceipaddress_map as $ins => $ip) { for ($i = 1; $i <= 10; $i++) { $associated = false; // インスタンスのステータスチェック $response = $ec2->describeInstances( array( 'InstanceIds' => array($ins,), ) ); foreach ($response['Reservations'] as $instances_no => $reservations) { foreach ($reservations as $key => $value) { if ($key == "Instances") { foreach ($value as $k => $v) { if ($v['InstanceId'] == $ins) { $ins_status_name = $v['State']['Name']; if ($ins_status_name == "running") { // ElasticIPのステータスチェック $res = $ec2->describeAddresses( array( 'PublicIps' => array($ip,), ) ); foreach ($res['Addresses'] as $addr_no => $addr) { if ($addr['PublicIp'] == $ip) { $exist = $addr['Domain']; $associationid = $addr['AssociationId']; } } if (!$associationid && ($exist == 'vpc')) { // ElasticIPの割当 $r = $ec2->associateAddress( array( 'InstanceId' => $ins, 'PublicIp' => $ip, ) ); if ($r['AssociationId']) { $associated = true; } else { $associated = false; } } elseif ($associationid && ($exist == 'vpc')) { $associated = true; } } } } } } } if ($associated) { break; } else { sleep(15); } } } ?>
これを /root/startup-ec2.php に配置。
次に停止用スクリプトをこんな感じで。
<?php require 'AWSSDKforPHP/aws.phar'; require_once '/etc/aws_ec2.config.inc.php'; use Aws\Ec2\Ec2Client; $instancelist = array( 'Instance ID', ); $ec2 = Ec2Client::factory($config); // インスタンス停止処理 foreach ($instancelist as $ins) { // インスタンスのステータスチェック $response = $ec2->describeInstances( array( 'InstanceIds' => array($ins,), ) ); foreach ($response['Reservations'] as $instances_no => $reservations) { foreach ($reservations as $key => $value) { if ($key == "Instances") { foreach ($value as $k => $v) { if ($v['InstanceId'] == $ins) { $ins_status_name = $v['State']['Name']; if ($ins_status_name == "running") { // インスタンスの停止 $res = $ec2->stopInstances( array( 'InstanceIds' => array($ins,), ) ); } } } } } } } ?>
これを /root/shutdown-ec2.php に配置。
そして、cronで自動起動するように設定すればOKです。
0 5 * * * /usr/bin/php /root/shutdown-ec2.php 0 11 * * * /usr/bin/php /root/startup-ec2.php
ウチの場合、早朝にTripwireを走らせているので、それが終わった時間に停止し、6時間後に起動するようにしました。業務開始が10時だというのもあります。時間はそれぞれの事情に合わせて調整すれば良いかと思います。
あと、今回のスクリプトを作るために情報を集めている段階で「インスタンスを停止するとElasticIPがDisassociateされる」という記述を見かけたのですが、止めても直ぐにはDisassociateされないようです。少なくとも1時間以上停止してみましたがDisassociateされませんでした。たまたまなのか、仕様が変わったのかは不明です。
コメント