Posted at

aws cli + resque + daemon-spawn で EC2 インスタンスを起動・停止

More than 3 years have passed since last update.


概要


  • resque に「起動してね」「停止してね」というキューを積むと EC2 インスタンスを起動・停止する

  • ↑ 用のプロセスは daemon-spawn で常駐化

  • EC2 インスタンスの起動・停止は AWS CLI を利用して実現する


AWS CLI のインストール

$ sudo easy_install pip 

$ sudo pip install awscli
$ aws configure --profile my_profile
AWS Access Key ID [None]: AKIAYB7....
AWS Secret Access Key []: q-SLuyqi+oV....
Default region name []: ap-northeast-1
Default output format []: ※何も入力せず Enter

※事前に EC2 操作用の IAM を作成して、Access Key/Secret Access Key を払い出しておくこと。

参考:第1回 AWS CLIをインストール:インフラ屋のAWSはじめた日記─GUIを捨てよ


実装


app/workers/instaces_manager.rb

EC2_REGION = Settings.aws_ec2.region

CLI_PROFILE = Settings.aws_ec2.profile

class InstancesManager
# 処理種別
RUN_INSTANCES = 1 # 起動
TERMINATE_INSTANCE = 100 # 停止

@queue = Settings.resque.manager.queue

def self.perform(processing_type, options = {})
begin
logger = Logger.new(File.join(Rails.root, Settings.resque.manager.log_file))

# 処理開始
start_time = Time.now
logger.info("[PID:#{$$}]: instances_manager start at: #{start_time}")

# インスタンス起動・停止
begin
case processing_type
when RUN_INSTANCES then run_instances(options['count'])
when TERMINATE_INSTANCE then terminate_instance(options['instance_id'])
end
logger.info("[PID:#{$$}]: success: processing_type=#{processing_type}, options=#{options}")
rescue =>e
logger.error("[PID:#{$$}]: failure: processing_type=#{processing_type}, options=#{options}")
logger.error(e)
end

# 処理終了
finished_time = Time.now
logger.info("[PID:#{$$}]: instances_manager finished: #{start_time}(from) - #{finished_time}(to): #{finished_time - start_time}(processing time)")
rescue =>e
logger.error(e)
end
end

def self.run_instances(count)
image_id = Settings.aws_ec2.xxx.image_id
instance_type = Settings.aws_ec2.xxx.instance_type
key_name = Settings.aws_ec2.xxx.key_name
security_group_name = Settings.aws_ec2.xxx.security_group_name

command = [
'aws ec2 run-instances',
'--image-id', image_id,
'--count', count,
'--instance-type', instance_type,
'--key-name', key_name,
'--security-groups', security_group_name,
'--region', EC2_REGION,
'--profile', CLI_PROFILE
].join(' ')
IO.popen(command){}
end

def self.terminate_instance(instance_id)
command = [
'aws ec2 terminate-instances',
'--instance-ids', instance_id,
'--region', EC2_REGION,
'--profile', CLI_PROFILE
].join(' ')
IO.popen(command){}
end
end



bin/instances_manage_worker.rb

#!/usr/bin/env ruby

require File.expand_path('../../config/application', __FILE__)
Rails.application.require_environment!

class InstancesManageDaemon < DaemonSpawn::Base
def start(args)
@worker = Resque::Worker.new(Settings.resque.manager.queue)
@worker.work
end

def stop
# 処理中のjobを完了後、shutdownする
@worker.try(:shutdown)
end
end

InstancesManageDaemon.spawn!({
:working_dir => Rails.root,
:pid_file => File.join(Rails.root, Settings.resque.manager.pid_file),
:log_file => File.join(Rails.root, Settings.resque.manager.log_file),
:sync_log => true,
:singleton => true
})



インスタンスを起動する

Resque.enqueue(InstancesManager, InstancesManager::RUN_INSTANCES, count: 5)


インスタンスを停止する

Resque.enqueue(InstancesManager, InstancesManager::TERMINATE_INSTANCE, instance_id: my_instance_id)

def my_instance_id
command = '/usr/bin/curl "http://169.254.169.254/latest/meta-data/instance-id"'
IO.popen(command){|io| io.gets}
end