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

以下のページでRDSとNLBを組み合わせる構成をご紹介しました。
この構成を取ることで、別のAWSアカウントのシステムなどDNSによるエンドポイントの名前解決が行えないシステムでも、NLBの固定IPでDB接続が可能になります。
ただ、この構成でも面倒な点がのこっていました。
それが、RDSのIPアドレスが変わってしまったときにNLBのターゲットグループに再登録が必要になる点です。
RDSのIPアドレスが変わるタイミングは、マルチAZにおけるフェイルオーバーや、停止からの起動、バージョンアップ、ハードウェアメンテナンスなどがあります。
基本的には運用作業の中で起きるものなので、手動で追加でもよいかと思ったのですが、作業手順は少ないに越したことはありません。
Lambdaによる自動化を行ってみます。
この構成を取ることで、別のAWSアカウントのシステムなどDNSによるエンドポイントの名前解決が行えないシステムでも、NLBの固定IPでDB接続が可能になります。
ただ、この構成でも面倒な点がのこっていました。
それが、RDSのIPアドレスが変わってしまったときにNLBのターゲットグループに再登録が必要になる点です。
RDSのIPアドレスが変わるタイミングは、マルチAZにおけるフェイルオーバーや、停止からの起動、バージョンアップ、ハードウェアメンテナンスなどがあります。
基本的には運用作業の中で起きるものなので、手動で追加でもよいかと思ったのですが、作業手順は少ないに越したことはありません。
Lambdaによる自動化を行ってみます。
使用例
このページのLambdaを使用することで以下のようなことが実現できます。
定期実行にはAmazon EventBridgeの作成が必要となります。
※AWS EventBridgeの解説は、本ページでは省略いたします。
作成方法は、こちらをご確認下さい。
- RDSのIPアドレス変更時に自動でNLBのターゲットに登録
定期実行にはAmazon EventBridgeの作成が必要となります。
※AWS EventBridgeの解説は、本ページでは省略いたします。
作成方法は、こちらをご確認下さい。
構成図
以下で紹介したRDSとNLBの構成にLambdaによるターゲットの自動更新機能を追加します。
LambdaはNLBのターゲットグループに対して、ターゲットの登録と登録解除を制御します。
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のフローは以下の通りです。
今回の処理では、RDSのエンドポイントがどのIPアドレスに向いているのかを確認することが必要となります。
Pythonには、socketライブラリがあるので、名前解決にてIPアドレスを取得しています。
フェイルオーバー等によりIPアドレスが変更になった場合も自動で変更後のIPアドレスを取得することが可能となります。
取得したIPアドレスはNLBのターゲットグループに登録します。
旧IPアドレスを登録解除し、新IPアドレスを登録する流れとなります。
IPアドレスに変更がない場合は処理がスキップされます。
- RDSのプライマリIPアドレスを取得
- 現在のターゲットグループと比較して、変更が必要かを判定
- 変更が必要な場合は、旧ターゲットを登録解除 & 新しいプライマリIPアドレスを登録
今回の処理では、RDSのエンドポイントがどのIPアドレスに向いているのかを確認することが必要となります。
Pythonには、socketライブラリがあるので、名前解決にてIPアドレスを取得しています。
フェイルオーバー等によりIPアドレスが変更になった場合も自動で変更後のIPアドレスを取得することが可能となります。
取得したIPアドレスはNLBのターゲットグループに登録します。
旧IPアドレスを登録解除し、新IPアドレスを登録する流れとなります。
IPアドレスに変更がない場合は処理がスキップされます。