lambdaでalbのターゲットグループ変更の仕方

0

ec2が2台あります。1台が本稼働しており、もう1台をスタンバイとして用意しています。稼働中のec2はステータスチェックを行なっており、cloudwatchのアラームでstatuscheckfailed_instanceを監視しています。ステータスチェックで状態を異常と検知した場合SNSで対象のメールアドレスにメッセージを送るようになっています。このSNS通知をトリガーとしてlambdaを起動しようとしています。lambdaで実行したい内容はalbに稼働中のec2をターゲットグループとして紐づけています。スタンバイインスタンスは負荷分散しているわけではないため、albには紐づいていない状態です。ec2紐づいているリスナールールのターゲットグループをSNSのトリガーが発生した時にターゲットグループをスタンバイインスタンスに変更する処理をpythonで関数を作成したいとおもっています。 この処理を実現することは可能でしょうか。 また、可能な場合は処理内容のコードを教えていただかますでしょうか。

2回答
0

はい、可能です。
コードは以下のようになります。(例外処理などは入れていません)
以下のコードではアラームになったらEC2をターゲットグループから外して、停止していた2台目のEC2を起動後にターゲットグループへアタッチするコードになっています。
最後にターゲットグループから外したEC2を停止するようにしています。
また、EC2をターゲットグループにアタッチするためにEC2のステータスが「running」になるまで無限ループさせています。
なので、Lambdaの実行時間を1分程度に変更するようにしてください。
LambdaのIAMロールにはとりあえず「AmazonEC2FullAccess」をアタッチしておけば動作させることが可能です。

import boto3
import json
import time

elbv2_client = boto3.client('elbv2')
ec2_client = boto3.client('ec2')
instance_id1 = '1台目のインスタンスID'
instance_id2 = '2台目のインスタンスID' 
target_group_arn = 'ターゲットグループのARN'

def lambda_handler(event, context):
    Message = json.loads(event['Records'][0]['Sns']['Message'])
    deregister_instance_id = Message['Trigger']['Dimensions'][0]['value']

    # アラートになったのが1台目のEC2の場合の処理
    if deregister_instance_id == instance_id1:
        elbv2_client.deregister_targets(
            TargetGroupArn=target_group_arn,
            Targets=[
                {
                    'Id': deregister_instance_id,
                },
            ]
        )

        # 2台目のインスタンスを起動
        ec2_client.start_instances(
            InstanceIds=[instance_id2]
        )

        # 2台目のインスタンスが起動するまで無限ループさせる
        while True:
            time.sleep(3)
            response = ec2_client.describe_instance_status(
                InstanceIds=[instance_id2]
            )
            if len(response['InstanceStatuses']) > 0:
                instance_status = response['InstanceStatuses'][0]['InstanceState']['Name']
                if instance_status == 'running':
                    break

        # ターゲットグループへアタッチ
        elbv2_client.register_targets(
            TargetGroupArn=target_group_arn,
            Targets=[
                {
                    'Id': instance_id2,
                },
            ]
        )

        # 1台目のインスタンスを停止
        ec2_client.stop_instances(
            InstanceIds=[deregister_instance_id]
        )

    # アラートになったのが2台目のEC2の場合の処理
    else:
        elbv2_client.deregister_targets(
            TargetGroupArn=target_group_arn,
            Targets=[
                {
                    'Id': deregister_instance_id,
                },
            ]
        )

        # 1台目のインスタンスを起動
        ec2_client.start_instances(
            InstanceIds=[instance_id1]
        )

        # 2台目のインスタンスが起動するまで無限ループさせる
        while True:
            time.sleep(3)
            response = ec2_client.describe_instance_status(
                InstanceIds=[instance_id1]
            )
            if len(response['InstanceStatuses']) > 0:
                instance_status = response['InstanceStatuses'][0]['InstanceState']['Name']
                if instance_status == 'running':
                    break

         # ターゲットグループへアタッチ
        elbv2_client.register_targets(
            TargetGroupArn=target_group_arn,
            Targets=[
                {
                    'Id': instance_id1,
                },
            ]
        )

        # 2台目のインスタンスを停止
        ec2_client.stop_instances(
            InstanceIds=[deregister_instance_id]
        )
profile picture
エキスパート
回答済み 6ヶ月前
  • ご回答ありがとうございます。 自分の説明不足な部分がありました。 こちらのコードでは1つのターゲットグループのec2に対して変更を行う設定となっていると思いますが、 要件といたしましては前提としてターゲットグループはすでにスタンバイ側も作成しており、ターゲットグループが2つ存在している状態です。 albのリスナールールでデフォルトのルールでターゲットを稼働中のec2が紐づけられているターゲットグループ1を指定しています。 このターゲットグループを予め作成してあるスタンバイ側が紐づいているターゲットグループ2に変更したいという要件になります。 GUIで操作するとロードバランサーのルール編集からターゲットグループを変更する設定です。

0

ご返信ありがとうございます。(文字数制限で貼り付けられなかったのでスレッドを変更しました)
コードを修正しました。
以下のコードを使用すると、1台目のEC2が紐づいているターゲットグループから2台目のEC2が紐づいているターゲットグループに切り替わります。
また、使用していないスタンバイのEC2については停止した状態で使用してください。(途中で起動するコードを入れているので起動したままだとエラーになります)

import boto3
import json
import time

elbv2_client = boto3.client('elbv2')
ec2_client = boto3.client('ec2')
instance_id1 = '1台目のインスタンスID'
instance_id2 = '2台目のインスタンスID' 
target_group_arn1 = '1台目のインスタンスが紐づいたターゲットグループのARN'
target_group_arn2 = '2台目のインスタンスが紐づいたターゲットグループのARN'
listener_arn = '変更するリスナーのARN'

def lambda_handler(event, context):
    Message = json.loads(event['Records'][0]['Sns']['Message'])
    deregister_instance_id = Message['Trigger']['Dimensions'][0]['value']

    # アラートになったのが1台目のEC2の場合の処理
    if deregister_instance_id == instance_id1:
        elbv2_client.modify_listener(
            ListenerArn=listener_arn,
            DefaultActions=[
                {
                    'Type': 'forward',
                    'TargetGroupArn': target_group_arn2,
                },
            ]
        )

        # 2台目のインスタンスを起動
        ec2_client.start_instances(
            InstanceIds=[instance_id2]
        )

        # 1台目のインスタンスを停止
        ec2_client.stop_instances(
            InstanceIds=[deregister_instance_id]
        )

    # アラートになったのが2台目のEC2の場合の処理
    else:
        elbv2_client.modify_listener(
            ListenerArn=listener_arn,
            DefaultActions=[
                {
                    'Type': 'forward',
                    'TargetGroupArn': target_group_arn1,
                },
            ]
        )

        # 1台目のインスタンスを起動
        ec2_client.start_instances(
            InstanceIds=[instance_id1]
        )

        # 2台目のインスタンスを停止
        ec2_client.stop_instances(
            InstanceIds=[deregister_instance_id]
        )
profile picture
エキスパート
回答済み 6ヶ月前
  • 追記ありがとうございます。上記を参考に想定していた挙動を行うことができました。 ご回答ありがとうございました。

ログインしていません。 ログイン 回答を投稿する。

優れた回答とは、質問に明確に答え、建設的なフィードバックを提供し、質問者の専門分野におけるスキルの向上を促すものです。

質問に答えるためのガイドライン