この記事では、
AWSのAPIを使って、EC2インスタンスを自動起動・停止させる方法を説明します。

Amazon Elastic Compute Cloud(Amazon EC2)の料金は、利用した時間単位での従量課金となります。
このため、
24時間稼働させる必要が無いサーバの場合は、
cron等の定時処理で自動的に起動・停止をさせる事でコストを削減できます。

コスト削減の例

例えば、平日・日中時間帯のみ稼働させる場合で計算すると、次のようになります。
# 常時稼働の場合、通常はリザーブドインスタンスを利用するので
# この計算結果はオーバーなのですが、
# リザーブドインスタンスでも時間あたりで料金がかかるので
# 同じ手法でコストを削減することができます。

条件とコスト削減額

インスタンス:スモール・Linux
稼働時間:月〜金の8:00〜18:00に稼働、土日終日停止
台数:1台
インスタンスのIPアドレスが変わらないようにElasticIPアドレスを割り付ける
 →コスト削減額:$15.456 → $5.19

常時稼働させた場合の一週間のコスト:$15.456

EC2のインスタンスのコスト:$15.456
 → $0.092 * 24時間 * 7日間

自動起動・停止させた場合のコスト:$5.19

EC2のインスタンスのコスト:$4.6
→ $0.092 * 10時間 * 5日間
# 24時間 → 10時間 (8:00〜18:00のみ稼働のため)
# 7日 → 5日 (土日終日停止のため)

ElasticIPアドレスのコスト:$0.59
 → $0.005 * (14時間 * 5日間 + 24時間 * 2日間)
# 再起動時にIPアドレスが変わらないよう固定IPアドレスを割り付ける想定
# サーバ停止(固定IPがインスタンスと紐付いていない状態)時間に料金がかかる
# 14時間 * 5日(18:00〜8:00の平日5日間の停止時間分)
# 24時間 * 2日(土日終日停止分)

※2012/12/14時点の東京リージョンで計算しています。
※ $0.092/1時間毎 スモールインスタンス
※ $0.005/1時間毎 ElasticIPアドレス

最新・東京リージョン以外の料金は以下で確認して下さい。
Amazon EC2 料金表
 http://aws.amazon.com/jp/ec2/pricing/

自動起動・停止での処理内容

まず、EC2を制御するマシンを用意します。
このマシンは24時間稼働している必要があります。物理サーバでもEC2のインスタンスでも構いません。

ここではAWS SDK for Rubyを利用してインスタンスを制御します。

AWS SDK for Ruby
 http://aws.amazon.com/jp/sdkforruby/

インスタンス起動時では
・インスタンスの起動
・ElasticIPアドレスの割り付け
を行い、これを月〜金の8:00に実行、

インスタンス停止時では
・インスタンスの停止
を行い、これを月〜金の18:00に実行することにします。

自動起動・停止処理の作成

それでは、実際にEC2を制御するスクリプトを作成します。

EC2を制御するマシンにRuby1.9がインストールされているとして、
以下のコマンドを入力し、aws-sdkをインストールします。

$ gem install aws-sdk

AWSにアクセスするための認証情報を記載します。
access_key_id,secret_access_keyは自分の環境のものを記載してください。
以下の例では、endpointをtokyo regionで指定しています。

/etc/aws.yml

access_key_id: <access_key_idをここに>
secret_access_key: <secret_access_keyをここに>
ec2_endpoint: ec2.ap-northeast-1.amazonaws.com

インスタンス起動用のスクリプトを作成します。
インスタンスIDは、EC2 Management ConsoleのInstancesから確認できるi-で始まるID(i-XXXXXXXX形式)です。
紐づけるelastic ipアドレスには、ElasticIPsから取得したIPAddressを確認し設定します。

/usr/local/sbin/startup-ec2.rb

#!/usr/bin/ruby
# encoding: utf-8
require 'aws-sdk'

instancelist = ["<ec2のインスタンスidをここに>"]
instanceipaddress_map = {"<ec2のインスタンスidをここに>" => "<紐づけるelastic ipアドレスをここに>"}

AWS.config(YAML.load(File.read("/etc/aws.yml")))

# インスタンス起動
instancelist.each do |ins|
instance = AWS::EC2.new.instances[ins]
instance.start if instance.status == :stopped
end

# ElasticIPの割り当て
(0..12).each do |idx|
associated = true
instanceips_map.each do |ins, ip|
instance = AWS::EC2.new.instances[ins]
elasticip = AWS::EC2.new.elastic_ips[ip]
if instance.status == :running
instance.associate_elastic_ip(elasticip) if elasticip.exists? && !elasticip.associated?
next
end
associated = false
end
break if associated
sleep(15)
end

以下のコマンドを入力し、インスタンスの起動とElasticIPの割り当てがされる事を確認します。
Elastic IPの割り当てはインスタンス起動後に行うので、コマンドの実行には少し時間がかかります。
起動状態とElasticIPの割り当て状態は、EC2 Management Consoleから確認できます。

$ chmod 744 /usr/local/sbin/startup-ec2.rb
$ /usr/local/sbin/startup-ec2.rb

次にインスタンス停止用のスクリプトを作成します。

/usr/local/sbin/shutdown-ec2.rb

#!/usr/bin/ruby
# encoding: utf-8
require 'aws-sdk'

instancelist = ["<ec2のインスタンスidをここに>"]

AWS.config(YAML.load(File.read("/etc/aws.yml")))

# インスタンス停止
instancelist.each do |ins|
instance = AWS::EC2.new.instances[ins]
instance.stop if instance.status == :running
end

以下のコマンドを入力し、インスタンスが停止される事を確認します。
停止状態は、EC2 Management Consoleから確認できます。
# ElasticIPは、インスタンスを停止すると勝手に割り当てが外れます。

$ chmod 744 /usr/local/sbin/shutdown-ec2.rb
$ /usr/local/sbin/shutdown-ec2.rb

以上で、インスタンス起動用・停止用スクリプトの動作を確認したら。
両方のスクリプトを、次のようにcronに設定します。

0 8 * * 1-5 /usr/local/sbin/startup-ec2.rb
0 18 * * 1-5 /usr/local/sbin/shutdown-ec2.rb

起動スクリプトは月〜金の8:00に実行、停止スクリプトは月〜金の18:00に実行としています。

平日の昼間しか稼働していないサービスの場合など、
このようなスクリプトをcronに仕込むだけで、
サービスレベルを下げずにコスト削減が出来るので、
24時間稼働が必要で無いサービスを運用している方は試してみてはいかがでしょうか?