はじめに
AWSのサーバーレスアーキテクチャを設計する際、AWS LambdaからAmazon RDSへの接続は頻出のパターンです。しかし、Lambdaの急激なスケールアウトに伴うコネクションの枯渇や、VPC内への配置による起動オーバーヘッドなど、実務では多くの課題に直面します。
本記事では、これらの課題を解決し、セキュアかつ高パフォーマンスな接続を実現する「Amazon RDS Proxy」を経由した安全な接続手順を、初心者から中級者向けにステップバイステップで解説します。
前提知識とRDS Proxyが必要な理由
なぜ直接接続ではダメなのか?
Lambda関数はリクエスト数に応じて自動的にスケール(並行実行)します。各LambdaインスタンスがRDSに対して個々にデータベース接続を確立すると、RDSの最大接続数(Max Connections)制限に一瞬で達してしまい、接続エラー(Too many connections)が発生する原因になります。
RDS Proxyがもたらすメリット
RDS Proxyを導入することで、以下のメリットを享受できます。
- コネクションプーリング:Proxyが接続をプールして効率的に再利用するため、RDSの負荷を大幅に軽減します。
- セキュリティの向上:データベースの認証情報をLambdaの環境変数に保持せず、AWS Secrets ManagerとIAMポリシーを連携させて安全に管理できます。
- 高速なフェイルオーバー:マルチAZ構成のRDSがフェイルオーバーした際、接続の切り替えを数秒高速化できます。
具体的な設定手順・設計方法
ここからは、LambdaからRDS Proxyを経由してRDS PostgreSQLまたはMySQLに接続する具体的な手順を解説します。本手順では、VPCの作成やRDSインスタンスの起動は完了しているものとします。
1. Secrets Managerでの認証情報の作成
RDS Proxyは、データベースのユーザー名とパスワードをSecrets Managerから取得します。
- AWS Secrets Managerコンソールを開き、「新しいシークレットを保存する」をクリックします。
- シークレットのタイプで「Amazon RDS データベースの資格情報」を選択し、ユーザー名とパスワードを入力します。
- 対象のRDSデータベースを選択し、任意のシークレット名(例:
rds/db-credentials)を付けて保存します。
2. RDS Proxy用のIAMロールとProxyの作成
RDS ProxyがSecrets Managerからシークレットを読み取るためのIAMロールを作成し、Proxyを構築します。
- RDSコンソールの「プロキシ」メニューから「プロキシの作成」を選択します。
- プロキシ名を入力し、対象のRDSデータベースを選択します。
- 「接続」セクションで、先ほど作成したSecrets Managerのシークレットを選択します。IAMロールは「IAMロールの作成」を選択すると、必要な権限を持つロールが自動作成されます。
- プロキシ用のセキュリティグループとして、Lambdaからのインバウンド通信(ポート3306または5432)を許可するルールを設定します。
3. Lambda関数の作成とVPC設定
Lambda関数を作成し、RDS Proxyと同じVPCおよびサブネットに配置します。
- Lambdaコンソールで新しい関数を作成します。
- 「詳細設定」を展開し、「VPCを有効化」にチェックを入れます。
- RDS Proxyが配置されているVPC、プライベートサブネット、およびセキュリティグループを選択します。
4. 接続テスト用のPythonコードと外部ライブラリの導入
LambdaからRDS Proxy経由で接続するためのPython(PyMySQLを使用した例)プログラムを作成します。標準外のライブラリである pymysql を使用するため、事前にLambdaレイヤー等で導入する必要があります。
【補足】PyMySQLライブラリの導入手順:
ローカル環境で以下のコマンドを実行してパッケージを特定のディレクトリ構成でインストールし、ZIP圧縮してLambdaレイヤーにアップロードしてください。
mkdir -p python/lib/python3.9/site-packages
pip install pymysql -t python/lib/python3.9/site-packages/
zip -r pymysql-layer.zip python/
アップロードしたレイヤーをLambda関数に紐づけた後、以下のコードを記述します。
import sys
import pymysql
import os
# 環境変数からRDS Proxyの接続情報を取得
DB_ENDPOINT = os.environ['DB_ENDPOINT'] # RDS Proxyのホスト名
DB_USER = os.environ['DB_USER']
DB_PASSWORD = os.environ['DB_PASSWORD']
DB_NAME = os.environ['DB_NAME']
def lambda_handler(event, context):
try:
# RDS Proxyへの接続を確立
conn = pymysql.connect(
host=DB_ENDPOINT,
user=DB_USER,
password=DB_PASSWORD,
db=DB_NAME,
connect_timeout=5
)
with conn.cursor() as cursor:
cursor.execute("SELECT version();")
result = cursor.fetchone()
return {
'statusCode': 200,
'body': f"Database version: {result[0]}"
}
except Exception as e:
print(f"ERROR: Connection failed. {e}")
return {
'statusCode': 500,
'body': "Connection failed"
}
実務での注意点
セキュリティグループの最小特権原則
実務でのトラブルの多くは「接続タイムアウト」です。これはセキュリティグループの設定ミスに起因します。「Lambdaのセキュリティグループ」から「RDS Proxyのセキュリティグループ」への特定ポート(例: 3306)のインバウンド通信のみを許可するよう、送信元にLambdaのセキュリティグループIDを明示的に指定して、不要なアクセス経路を遮断してください。
コールドスタートとVPC IPの枯渇対策
VPC内のLambdaは、起動時に「Hyperplane ENI(エラスティックネットワークインターフェイス)」を共有して通信します。昔のように起動ごとにENIを新規作成することはなくなりましたが、サブネット内のプライベートIPアドレスの空き容量には依然として注意が必要です。十分なアドレス数を持つ/24以上のサブネットを、高可用性のためにマルチAZ(最低2つ以上)構成でLambdaに割り当ててください。
まとめ
本記事では、AWS LambdaからRDSへのセキュアかつ高スケーラブルな接続を実現するために必須となる「RDS Proxy」の構築手順と実務での注意点を解説しました。サーバーレス構成において、データベースのコネクション管理はシステムの安定性を左右する極めて重要な要素です。本設計を実務に取り入れ、信頼性の高いシステム構築を目指しましょう。