AWS SDK for Rubyを使ってEC2インスタンスのステータスを確認する
アプリケーション側で、任意のAWSのEC2インスタンスについて、現在の稼働状況をリアルタイムに確認したい時がある。例えば外部アプリケーションからEC2インスタンスを起動させたり、停止させたりする場合などに、インスタンスの稼動状況を確認してステータスが変わったら次のプロセスを実行したいとかいうケースが、それに当てはまる。
SDK for Rubyでは、AWS::EC2
クラスのclient.describe_instance_status
メソッドで特定のECインスタンスのステータスを取得することができる。インスタンスのステータスにはsystem_status
とinstance_status
の2種類があって、正確な稼動状態を確認したい場合はこの2つのステータスを取得する必要がある。 そして、注意しないといけないのが、インスタンスが停止している時はステータスが存在していないということだ。つまり、停止しているインスタンスに対してclient.describe_instance_status
メソッドを実行した場合、ステータス情報が格納されているinstance_status_set
オブジェクトの中身が取得できないので、それを踏まえてコーディングしないと、ステータス取得エラーとなってしまう。 例えば、停止状態のインスタンスを起動した場合のステータスを監視する時など、最初はインスタンスが停止しているので、instance_status_set
オブジェクト内にステータスがないということをあらかじめ想定して処理を作る必要がある。 また、ターミネートされたインスタンスはclient.describe_instance_status
メソッドを実行する対象自体がないことので、こちらも注意する必要がある。
さて、上記もろもろを踏まえてEC2インスタンスのステータス確認するRubyプログラムを作ってみた。
chkins.rb
# encoding: utf-8
require "aws-sdk"
def check_instance_status
ec2 = AWS::EC2.new(
:access_key_id => Params[:access_key_id],
:secret_access_key => Params[:secret_access_key],
:region => Params[:region]
)
AWS.memoize do
status = []
if ec2.instances[Params[:instance_id]].exists?
ec2info = ec2.client.describe_instance_status({ 'instance_ids' => [Params[:instance_id]] })
if ec2info.instance_status_set.empty?
# instance has stopped
status << 'stopped'
message = '%s has stopped'
else
ec2info.instance_status_set.map { |i|
sys_status = i.respond_to?(:system_status) ? i.system_status.details[0].status : nil
ins_status = i.respond_to?(:instance_status) ? i.instance_status.details[0].status : nil
status << sys_status << ins_status
}
if status.include?('passed')
# instance is running
message = '%s is running'
elsif status.include?('initializing')
# instance is initializing
message = '%s is starting'
else
# otherwise
message = '%s is unknown status'
end
end
else
# instance has terminated
status << 'terminated'
message = '%s has already terminated'
end
puts sprintf("#{message}. status: %s", "Instance: #{Params[:instance_id]}", status)
end
end
begin
# init
Params = {
:access_key_id => ARGV[0],
:secret_access_key => ARGV[1],
:region => ARGV[2],
:instance_id => ARGV[3],
:timeout => ARGV[4].nil? ? 1 : ARGV[4].to_i
}
raise 'Parameter is missing.' if Params.values.include?(nil)
for i in 1..Params[:timeout] do
sleep 1 if i > 1
check_instance_status
end
rescue => e
puts e
end
プログラム実行時の引数として、
- AWSアクセスキー(必須)
- AWSシークレットアクセスキー(必須)
- リージョン(必須)
- インスタンスID(ステータスを確認したいインスタンスID)
- タイムアウト回数(1秒単位で何回確認するか。省略可。省略時は1回のみ)
を渡してあげると、ほぼタイムアウト回数≒秒数の間ずっと指定インスタンスのステータスを標準出力でモニタリングしてくれます。
実行例:
$ ruby -Ku chkins.rb <AWSアクセスキー> <AWSシークレットキー> ap-southeast-1 <インスタンスID> 10
Instance: i-******** is running. status: ["passed", "passed"]
Instance: i-******** is running. status: ["passed", "passed"]
Instance: i-******** is running. status: ["passed", "passed"]
Instance: i-******** is running. status: ["passed", "passed"]
Instance: i-******** is running. status: ["passed", "passed"]
Instance: i-******** is running. status: ["passed", "passed"]
Instance: i-******** is running. status: ["passed", "passed"]
Instance: i-******** is running. status: ["passed", "passed"]
Instance: i-******** is running. status: ["passed", "passed"]
Instance: i-******** is running. status: ["passed", "passed"]
指定したインスタンスIDが稼働中であれば、上記のような結果が約10秒間モニタリングされます。
※ 実行前には、あらかじめAWS SDK for Ruby
(バージョンは1系)をインストールしておく必要があります。
特定ステータスを検知した時にメールを発報するなどの処理を付け足して、スクリプトの起動をcron
に登録し、定期的に実行するようにすれば、AWSのCloudWatchに依存せずにインスタンスの稼動状況を監視させたりとかできて良いかも。