RDSの動的IPアドレス変更に対応!Lambdaを使ってNLBに自動ターゲット登録

以下のページでRDSとNLBを組み合わせる構成をご紹介しました。
この構成を取ることで、別のAWSアカウントのシステムなどDNSによるエンドポイントの名前解決が行えないシステムでも、NLBの固定IPでDB接続が可能になります。

ただ、この構成でも面倒な点がのこっていました。
それが、RDSのIPアドレスが変わってしまったときにNLBのターゲットグループに再登録が必要になる点です。
RDSのIPアドレスが変わるタイミングは、マルチAZにおけるフェイルオーバーや、停止からの起動、バージョンアップ、ハードウェアメンテナンスなどがあります。

基本的には運用作業の中で起きるものなので、手動で追加でもよいかと思ったのですが、作業手順は少ないに越したことはありません。
Lambdaによる自動化を行ってみます。

使用例

このページのLambdaを使用することで以下のようなことが実現できます。
  • RDSのIPアドレス変更時に自動でNLBのターゲットに登録
このLambdaは数分おきに実行させ、変更があれば自動登録し、変更がなければスキップする処理とします。
定期実行にはAmazon EventBridgeの作成が必要となります。

※AWS EventBridgeの解説は、本ページでは省略いたします。
 作成方法は、こちらをご確認下さい。

構成図

以下で紹介したRDSとNLBの構成にLambdaによるターゲットの自動更新機能を追加します。

LambdaはNLBのターゲットグループに対して、ターゲットの登録と登録解除を制御します。

Lambdaソースコード

以下は、メンテナンスページ表示用のソースコードです。
メンテナンスページを実装したいリスナーARNと表示するメンテナンスページのHTMLを入力すれば使用可能です。
import boto3
import json
import os
import socket

rds_client = boto3.client('rds')
elbv2_client = boto3.client('elbv2')
ec2_client = boto3.client('ec2')

def lambda_handler(event, context):
    target_group_arn = os.environ['TARGETGROUP']
    rds_endpoint = os.environ['RDSENDPOINT']
    port =  os.environ['PORT']
    primary_ip = socket.getaddrinfo(rds_endpoint, port)[0][4][0]
    
    current_targets_response = elbv2_client.describe_target_health(
        TargetGroupArn=target_group_arn
    )

    targets_to_deregister = []
    for target in current_targets_response['TargetHealthDescriptions']:
        if target['Target']['Id'] != primary_ip:
            targets_to_deregister = [
                {
                    'Id': target['Target']['Id'],
                    'Port': target['Target']['Port']
                }
            ]
    
    if targets_to_deregister:
        elbv2_client.deregister_targets(
            TargetGroupArn=target_group_arn,
            Targets=targets_to_deregister
        )
        
    elbv2_client.register_targets(
        TargetGroupArn=target_group_arn,
        Targets=[
            {
                'Id': primary_ip,
                'Port': int(port)
            }
        ]
    )
    
    return 0
                    

権限(IAMロール設定)

Lambdaに付与するIAMロールに「ec2:DescribeNetworkInterfaces」、「elasticloadbalancing:RegisterTargets」、「elasticloadbalancing:DeregisterTargets」、「elasticloadbalancing:DescribeTargetHealth」、「rds:DescribeDBInstances」の権限を付与してください。

解説

紹介した閉局Lambdaのフローは以下の通りです。
  1. RDSのプライマリIPアドレスを取得
  2. 現在のターゲットグループと比較して、変更が必要かを判定
  3. 変更が必要な場合は、旧ターゲットを登録解除 & 新しいプライマリIPアドレスを登録

今回の処理では、RDSのエンドポイントがどのIPアドレスに向いているのかを確認することが必要となります。
Pythonには、socketライブラリがあるので、名前解決にてIPアドレスを取得しています。
フェイルオーバー等によりIPアドレスが変更になった場合も自動で変更後のIPアドレスを取得することが可能となります。

取得したIPアドレスはNLBのターゲットグループに登録します。
旧IPアドレスを登録解除し、新IPアドレスを登録する流れとなります。
IPアドレスに変更がない場合は処理がスキップされます。

使い方

今回紹介したソースコードのLambdaを作成し、AWS EventBridgeで定期実行するように設定してください。
また、Lambdaの環境変数にご自身の環境の情報を設定してください。

  • TARGETGROUP ・・・ NLBのターゲットグループARN
  • RDSENDPOINT ・・・ RDSのエンドポイント
  • PORT ・・・ DBの接続ポート