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

0

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

2 Antworten
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
EXPERTE
beantwortet vor 9 Monaten
  • ご回答ありがとうございます。 自分の説明不足な部分がありました。 こちらのコードでは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
EXPERTE
beantwortet vor 9 Monaten
  • 追記ありがとうございます。上記を参考に想定していた挙動を行うことができました。 ご回答ありがとうございました。

Du bist nicht angemeldet. Anmelden um eine Antwort zu veröffentlichen.

Eine gute Antwort beantwortet die Frage klar, gibt konstruktives Feedback und fördert die berufliche Weiterentwicklung des Fragenstellers.

Richtlinien für die Beantwortung von Fragen