aws-sdkでEC2のインスタンス起動する
awscliはちょっと作業するのには簡単でよいのだけど、自動化したり何かに組み込んだりするにはjqとbashでがんばるのは辛みあるのでaws-sdkからAPI叩いてみるの試した。APIはRuby用ので、バージョンはaws-sdk 2.0.28です。
$ gem install aws-sdk
ec2-run-instances.rbとか適当な名前のスクリプトを書く。
はじめにアクセスキーとか環境設定して初期化する。
require 'aws-sdk' # set environments ec2 = Aws::EC2::Client.new( access_key_id: ENV['AWS_ACCESS_KEY_ID'], secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'], region: ENV['AWS_DEFAULT_REGION'] )
aws configureの設定を自動で取ってくれるようなので、そっちで予め設定しといてもよいけど、後で他のステップと部品を組み合わせる都合上、もろもろ環境変数経由でセットしてる。
次にEC2のインスタンスオプションのハッシュ作る。
# aws ec2 run-instances options # Note: security_group_ids can not use network_interfaces simultaneously. # So use network_interfaces:groups ec2_options = { dry_run: false, image_id: "ami-18869819", min_count: 1, max_count: 1, key_name: "aws-wercker", # security_group_ids: ["sg-48b7002d"], instance_type: "t2.micro", placement: { availability_zone: "ap-northeast-1a" }, block_device_mappings: [ { device_name: "/dev/xvda", ebs: { volume_size: 8, delete_on_termination: true, volume_type: "gp2" } }, ], monitoring: { enabled: false, }, disable_api_termination: false, network_interfaces: [ { device_index: 0, subnet_id: "subnet-6b55851c", groups: ["sg-48b7002d"], delete_on_termination: true, associate_public_ip_address: true }, ], ebs_optimized: false }
基本的にawscliでセットできるのと同じパラメータなので各自好きなように指定すればよいけど、1点ハマりどころが、aws ec2 run-instances --cli-input-jsonとパラメータのチェック条件が違うのか、security_group_idsがnetwork_interfaces両方同時にセットするとエラーになるので、associate_public_ip_address使うためにnetwork_interfaces指定したい場合は、セキュリティグループはsecurity_group_idsではなくて、network_interfacesのgroupsで指定すればよいです。
次にrun_instaces呼び出すとレスポンスが返ってくるので、インスタンスIDを抽出する。
# run instance run_response = ec2.run_instances(ec2_options) # get instance_id from API response instance_id = run_response.data.instances[0].instance_id
どんな構造のレスポンスが返ってくるかはSDKのドキュメント見ればわかるけど、pryとかでデバッグしながら試してみるとわかりやすい。
次にrun_instances起動してもすぐにステートがrunningになる前にリターンしてくるので、wait_untilヘルパーで待つ。
# wait until instance boot ec2.wait_until(:instance_running, instance_ids:[instance_id])
-
-
-
-
- -
-
-
-
(2015/3/5追記)
EC2インスタンス起動の直後にsshする場合は:instance_runningでは不十分で、ネットワーク到達性が確認できる:instance_status_okまで待たないとsshがConnection refusedで弾かれます。環境によると思いますが、Amazon Linuxのt2.microインスタンスだと、:instance_runningになるまで40秒ぐらいで、sshdが起動するのは1分30秒ぐらいで、:instance_status_okになるまでは3〜4分かかりました。
-
-
-
-
- -
-
-
-
その他PublicIpAddressとかインスタンスのパラメータ取得したい場合は、awscli同様にdescribe_instancesというのがあるので、それでレスポンス解析すれば取れる。
# get public ip address describe_response = ec2.describe_instances(instance_ids: [instance_id]) target_ip = describe_response.data.reservations[0].instances[0].public_ip_address
この辺インスタンスの設定値とか簡単なsetter/getterみたいな高レベルなAPI提供して欲しいんだけど、低レベルなAPIしかないのもうちょっと頑張って欲しいかんじする。。。と思ったら、どうやらaws-sdk-resourcesというgemがどうやらそれっぽい。もうちょっと高度なことをやりたくなったら調べる。
ちなみにrubyのプロセス内から環境変数読むこと出来るけど、色々試したが書き込みはできないっぽいので、標準出力に流して適当なファイルにリダイレクトしてsourceして親シェルで環境変数にセットするという力技しか思いつかなかったのなんかもっとよい方法ないものか。
# output result to stdout puts "export TARGET_IP=#{target_ip}" puts "export INSTANCE_ID=#{instance_id}"
$ ruby ec2-run-instances.rb > ec2.env $ source ec2.env
あと、インスタンス廃棄したければ、ec2-terminate-instances.rbとか作ってこんなかんじです。
require 'aws-sdk' # set environments ec2 = Aws::EC2::Client.new( access_key_id: ENV['AWS_ACCESS_KEY_ID'], secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'], region: ENV['AWS_DEFAULT_REGION'] ) instance_id = ENV["INSTANCE_ID"] terminate_response = ec2.terminate_instances(instance_ids: [instance_id])
awscli使えればだいたい対応するメソッドあるので読み替えは簡単。
参考