先日のエントリに書いたとおり、先月から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されませんでした。たまたまなのか、仕様が変わったのかは不明です。


コメント