AWS Lambda

AWS SDK for Ruby で書くLambda関数

はじめに

こんにちは、omkです。
今回はLambdaを触る機会をいただいたのでLambdaとrubyの勉強を致しました。
これまではLambdaの主要な言語に対応できずになんとなく敬遠していたのですが、良い機会だとRubyの勉強から始めて無事に動くものが出来たのでまとめます。

内容

ALBのヘルスチェックで正常に動いているEC2インスタンスがなくなった(HealthyHostCount < 1)ときに
Lambdaで、それらを停止させ、停止しているインスタンスの中から起動時刻が最も古いEC2インスタンスを立ち上げる
流れを実装しました。
(ターゲットグループは1つを想定)

Lambdaフローチャート

実装

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

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA