目次
はじめに
こんにちは、omkです。
今回はLambdaを触る機会をいただいたのでLambdaとrubyの勉強を致しました。
これまではLambdaの主要な言語に対応できずになんとなく敬遠していたのですが、良い機会だとRubyの勉強から始めて無事に動くものが出来たのでまとめます。
内容
ALBのヘルスチェックで正常に動いているEC2インスタンスがなくなった(HealthyHostCount < 1)ときに
Lambdaで、それらを停止させ、停止しているインスタンスの中から起動時刻が最も古いEC2インスタンスを立ち上げる
流れを実装しました。
(ターゲットグループは1つを想定)
実装
require 'json'
require 'aws-sdk'
def lambda_handler(event:, context:)
#イベントから問題が起こっているELBを特定
message = JSON.parse(event['Records'][0]['Sns']['Message'])
elb_ins = message['Trigger']['Dimensions'].select { |k| k['name'] == 'LoadBalancer' }[0]['value']
elb_arn = "arn:aws:elasticloadbalancing:"+ENV['region']+":"+ENV['AWS_AcountID']+":loadbalancer/"+elb_ins
#ELBのターゲットグループに所属しているEC2インスタンスの取得
alb_client = Aws::ElasticLoadBalancingV2::Client.new({region: ENV['region']})
ec2_insIds = []
##ターゲットグループ取得
alb_resp = alb_client.describe_target_groups(load_balancer_arn: elb_arn)
alb_targetgArn = alb_resp.target_groups[0].target_group_arn
##EC2インスタンスのID取得
alb_resp = alb_client.describe_target_health(target_group_arn: alb_targetgArn).target_health_descriptions
ec2_insIds += alb_resp.map(&:target).map(&:id)
ec2_Stoppeds = []
ec2_resource = Aws::EC2::Resource.new(region: ENV['region'])
#ヘルシーではないインスタンスを止める
for i in 0..(alb_resp.length - 1)
alb_target = alb_resp[i]
ec2_ins = ec2_resource.instance(alb_target['target']['id'])
##起動しているがヘルシーでないインスタンスの停止
if (alb_target['target_health']['state'] != 'healthy') && (ec2_ins.state.name=="running") then
ec2_StoppedHash = {'id' => ec2_ins.id ,'healthState' => alb_target['target_health']['state']}
ec2_resource.instance(alb_target['target']['id']).stop
ec2_Stoppeds.push(ec2_StoppedHash)
end
end
#止まっているEC2インスタンスのIDと起動時刻だけ取得
ec2_insIdTime = []
for i in 0..(ec2_insIds.length-1)
ec2_ins = ec2_resource.instance(ec2_insIds[i])
if (ec2_Stoppeds.include?(ec2_ins.id) == false) && (ec2_ins.state.name == 'stopped') then
##各EC2インスタンスのidと起動時刻をHash化してまとめる
##起動時刻は数字だけに
launchTime = ec2_ins.launch_time.to_s
launchTime = launchTime.tr('^0-9','')
ec2_insIdTimeHash = {'id' => ec2_ins.id , 'time' => launchTime}
ec2_insIdTime.push(ec2_insIdTimeHash)
end
end
#起動時刻でsortして一番古いインスタンスを起動
ec2_insIdTime = ec2_insIdTime.sort_by! { |a| a['time'] }
##最後に起動してから最も時間の経っているインスタンスを起動
ec2_insId = ec2_insIdTime[0]['id']
ec2_ins = ec2_resource.instance(ec2_insId)
ec2_ins.start()
#ログ作成
pp "停止したインスタンス"
pp ec2_Stoppeds
pp "起動したインスタンス"
pp ec2_ins.id
end
まとめ
AWS SDKを使うことで簡単にAWS上のパラメータを取得できるようになります。
今回はSNSを通して渡されたCloudWatchのアラームから、ELBを特定し、そのターゲットグループに含まれるEC2のインスタンスを操作しました。
Lambdaは様々なものをトリガーとして起こせるのでその便利さを最大限に発揮していきたいです。
Rubyに関しては特にAWS SDKを扱う部分が多かったので、純粋なRubyの機能自体にはそこまで触れることもなく(とはいえSDKも言語によって書き方が色々変わってくるようですが)、導入として良い経験になったと感じます。
参考
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws.html
https://tekunote.com/aws/lambda-ruby-event-param
http://l-chika.hatenablog.com/entry/2016/12/15/102148
アーキテクト課のomkです。
AWSについて雑多に取り組んだ内容を発信しています!!