概要
- 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