概要
RDS Proxyをセットアップする手順を記載する
なぜRDS Proxyを使わないといけないか
LambdaからRDSへのアクセスはアンチパターンと言われています。(調べるまで知りませんでした)
その理由は、Lambdaはリクエストごとに起動し、その都度RDSに対してコネクションを張ろうとするため、
コネクション上限を超えたLambdaからのアクセスはエラーとなってしまうためです。
Lambda起動の頻度が高いほどコネクションが多くなってしまうのですね。。。
lambdaが終了しても、コネクションが残ってしまい、接続数の上限に達してしまう
参考
AWS
- RDS Proxyについて https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html
- PostgreSQL関数lastvalを使用してはいけないw(Proxyを利用してるからしょうがない)
- PostgreSQLの一部バージョンに対応していない
- 10.10 and higher minor versions, and version 11.5 and higher minor versions
- 12, 13系に未対応なので、気をつける(2021年10月27日)
- https://stackoverflow.com/questions/67967745/rds-proxy-gives-empty-dropdown-for-database-when-using-rds-postgresql-13-2
- 使い方 https://aws.amazon.com/jp/blogs/news/using-amazon-rds-proxy-with-aws-lambda/
RDS Proxyについての記事
- https://ichi-station.com/aws-rds-proxy-lambda-aurora/
- https://sebenkyo.com/2020/11/04/post-1590/
- https://qiita.com/curanosuke/items/9f17857efa24c138997f
lambdaのコードをzipで圧縮してアップロード
前提
RDSにインスタンスとテーブルは作成されていること
[検証用] RDSにインスタンスを作成し、テーブルの作成手順
※ 起動の手順は省略
MySQL
CREATE DATABASE stream_test;
USE stream_test;
CREATE TABLE `fruits` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `fruits` (name) VALUES ('orange'), ('apple');
PostgreSQL
CREATE DATABASE stream_test;
\c stream_test;
CREATE TABLE "fruits" (
"id" SERIAL,
"name" varchar(255) NOT NULL DEFAULT ''
);
INSERT INTO "fruits" (name) VALUES ('strawberry'), ('banana');
手順
- シークレットマネージャーを登録する
- RDS Proxyを登録する
- Policyを作成する
- lambdaを登録する
- テストを実行する
シークレットマネージャーを登録する
RDS Proxyで利用されるuserとpasswordをシークレットマネージャーに登録
- ユーザー名
- パスワード
- データベース
RDS Proxyを登録する
- プロキシ識別子: 任意
- エンジンの互換性: 任意
- Transport Layer Security が必要: PostgreSQLの場合は必須
- データベース: 任意(PostgreSQLは、version 10 もしくは 11のみ対応)
- Secrets Manager シークレット: 前述のシークレット
- IAM ロール: IAMロールを作成
- IAM 認証: 無効(SSMを利用するので、無効)
- サブネット : (変更しない)
Policyを作成する
LambdaからRDS Proxyを参照できるPolicyを作成する
- タグ(任意)
- キー: Name
- 値 - オプション: 任意
- 名前: 任意(前述のタグと同じもの推奨)
- 説明: 任意( ex:
Secret manager available in lambda
)
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"secretsmanager:GetResourcePolicy",
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:ListSecretVersionIds"
],
"Resource": [
"{secretのARN}"
]
}
]
}
lambdaを登録する
"一から作成" を選択
- 関数名: 任意
- ランタイム: Python3.8 (他の言語、バージョンでも良いが、今回利用するレイヤーが、3.8向けのものです)
レイヤーの追加
Python3.8に対応したレイヤーを探して使う(2021年12月3日時点で、3.9向けのものは、このリポジトリでは準備されていない)
PostgreSQLを利用したので、 psycopg2
を利用
今回は、こちらを参照
arn:aws:lambda:ap-northeast-1:770693421928:layer:Klayers-python38-aws-psycopg2:1
以下は他のサイトで見つけた psycopg2
arn:aws:lambda:ap-northeast-1:898466741470:layer:psycopg2-py38:1
設定
-
一般設定
- タイムアウト: 30秒(任意です)
-
IAMロール
- ポリシーの追加
- 前述で作成したPolcy
- AWSLambdaVPCAccessExecutionRole
※ kinesisを利用する場合は、AmazonKinesisFullAccessを追加
-
VPC
- VPC: RDSのあるVPC
- サブネット: 全て選択
- セキュリティグループ: RDS Proxyと同じもの
-
データベースプロキシ
- 既存のデータベースプロキシの選択: 前述のRDS Proxy
-
データベースプロキシ追加後、IAMロール
- RDS ProxyのPolicyがあるか確認
- ex) AWSLambdaRDSProxyExecutionRole-12345678-1234-1234-1234-123456789012
lambda登録
import json
import os
import sys
import boto3
import psycopg2
import base64
# PostgreSQL Connection
def connect():
ENDPOINT="{前述のRDS Proxyのエンドポイント}"
PORT="5432"
USR="{前述のRDS Proxyに登録したユーザ}"
REGION="ap-northeast-1"
DATABASE="{任意のデータベース名}"
client = boto3.client('rds')
token = client.generate_db_auth_token(DBHostname=ENDPOINT, Port=PORT, DBUsername=USR, Region=REGION)
con = psycopg2.connect(host=ENDPOINT, database=DATABASE, user=USR, password=token)
return con
# EXECUTE SELECT
def select_execute(con, sql, values):
print(sql)
with con.cursor() as cur:
cur.execute(sql, values)
records = cur.fetchall()
return records
def lambda_handler(event, context):
con = connect()
sql = 'SELECT COUNT(1) AS count FROM fruits'
records = select_execute(con, sql, [])
return {
'statusCode': 200,
'body': f"calllog_id: {records[0][0]}"
}
テストを実行する
fruitsの個数が表示されれば、正常に完了です。
Test Event Name
test1
Response
{
"statusCode": 200,
"body": "fruits count: 2"
}
Function Logs
START RequestId: 6f6d853f-e213-41e4-a75c-fc6f1a927238 Version: $LATEST
SELECT COUNT(1) AS count FROM fruits
END RequestId: 6f6d853f-e213-41e4-a75c-fc6f1a927238
REPORT RequestId: 6f6d853f-e213-41e4-a75c-fc6f1a927238 Duration: 1437.65 ms Billed Duration: 1438 ms Memory Size: 128 MB Max Memory Used: 74 MB Init Duration: 330.97 ms
Request ID
6f6d853f-e213-41e4-a75c-fc6f1a927238