見出し画像

それサーバレスでできません? 〜④LambdaからのRDSの利用

本作業の目的

LambdaからRDSを利用する場合はRDSのアクセス接続数が上限に達してしまいます。そのため、データベースへの接続プールを維持するRDS Proxyといった機能を追加する必要があります。
※RDS Proxyリリース以前はLambdaからRDSの直接利用はアンチパターンとされてきました。リリース発表時のインパクトは物凄い大きかったです、、

画像1

補足:RDSとDynamoDBの違い
「DynamoDB使えば問題ないのでは?」と考える方もいると思いますが、RDSとDynamoDBはそもそもの仕組み・用途が違うため、代替手段とすることはできません。細かい違いは多々ありますが、端的にシステムとしての違いを説明するとRDSはSQLであり、DynamoDBはNoSQLとなります。更に使い分けの説明をすると、「テーブル結合などの複雑のクエリを使用する場合はRDS(SQL)」、「複雑なクエリが必要ないが、パフォーマンスを上げたい場合はDynamoDB(NoSQL)」といった切り分けになります。
そのため、サーバレスにしたいからDynamoDBという判断ではなく、使用想定を基にした選定が必要になります。
※本章では、移行前のシステムがSQLの要件であったものとして進めています。

構築手順

作成済のデータベースへLambdaから接続するための設定手順について説明します。

画像2

1. DBへの接続情報の登録(Secrets Manager)
RDS Proxyから参照できるよう、データベースの接続情報(=ユーザー名、パスワード)をSecrets Managerに登録します。

1-1. Secrets Manager管理画面上で、「新しいシークレットを保存する」から新規作成を行います。 

画像3

1-2. シークレットの種類として「RDSデータベースの認証情報」を選択し、作成済のデータベースの認証情報を入力します。

4章_説明4_SSM作成2

1-3. 接続情報管理用の名前を入力します。識別しやすい名前としてください。

4章_説明5_SSM作成3

1-4. 暗号鍵のローテションはデフォルトの設定のままとし、作成を完了します。(※セキュリティポリシーに合致しない場合などは、適宜変更ください。)

2. RDS ProxyからDB接続情報へのアクセス権限設定(=IAMロールの作成)
手順1で作成した認証情報へ、RDS Proxyからアクセスできるよう権限設定を行います。

※手順3の途中で自動生成されるため、説明を割愛します。

3. RDS Proxyの作成
3-1. RDSダッシュボードからプロキシ一覧へ進み、「プロキシを作成」からRDS Proxyの新規作成を行います。

4章_説明6_Proxy作成1

4章_説明7_Proxy作成2

3-2. Proxyの設定を行い、「プロキシを作成」から作成を実行します。
※設定抜粋(下記以外の項目はデフォルトで入力されている設定を利用)
 ・プロキシ識別子:(任意の名称)
 ・エンジンの互換性:MySQL
 ・Secrets Managerシークレット:(手順1で作成したシークレットを指定)
 ・サブネット:(RDSを配置するサブネットを指定)

4章_説明8_Prosy作成3

4. 処理コードの変更
Lambdaのコード内の接続先情報をRDSからRDS Proxyへ変更します。
RDSのエンドポイントをRDSのエンドポイントに変更します。

import json
import mysql.connector
import os

DB_USER = os.environ["DB_USER"]
DB_PASSWORD = os.environ["DB_PASSWORD"]
DB_HOST = os.environ["DB_HOST"]
DB_NAME = os.environ["DB_NAME"]

def execute_query(event):
   config = {
       'user': DB_USER,
       'password': DB_PASSWORD,
       'host': DB_HOST, #<-RDS Proxyのエンドポイント(URL)に変更する
       'database' : DB_NAME,
   }

   cnx = mysql.connector.connect(**config)
   cursor = cnx.cursor()
   query = ("SELECT SLEEP(10)")
   cursor.execute(query)

def lambda_handler(event, context):
   execute_query(event)

※RDS Proxyを使用したLambda関数一式は下記サンプルコードを参照ください。

参考:RDSを使用するLambda関数を作成するテンプレート(CloudFormationで作成)

リポジトリのディレクトリ構造

- source
    - lambda_function.py
    - requirment.txt
- .DS_Store
- buildspec.yml
- template.yml
- README.md

template.yml (CloudFormationテンプレート)

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

#構築時に、自分の環境の情報を入力する
Parameters:
 SecurityGroupId01:
   Type: String
 Subnet01:
   Type: String
 Subnet02:
   Type: String
 Subnet03:
   Type: String
 DBUser:
   Type: String
 DBPassword:
   Type: String
 DBHost:
   Type: String
 DBName:
   Type: String
 
Resources:
 SampleFunction:
   Type: AWS::Serverless::Function
   Properties:
     Handler: lambda_function.lambda_handler
     Runtime: python3.8
     FunctionName: sample-function-userds
     CodeUri: ./source
     VpcConfig: 
       SecurityGroupIds:
         - !Ref SecurityGroupId01
       SubnetIds:
         - !Ref Subnet01
         - !Ref Subnet02
         - !Ref Subnet03

     Environment:
       Variables:
         DB_USER: !Ref DBUser
         DB_PASSWORD: !Ref DBPassword
         DB_HOST: !Ref DBHost
         DB_NAME: !Ref DBName

buildspec.yml (Code Buildのビルド設定)

version: 0.2                                                                                                                                                                                                

phases:
 install:    
   runtime-versions:
     python: 3.8
   commands:
     - sam build
     #出力先バケット名はあらかじめ作成しておく(下記"OUTPUT_S3_BUCKET"の部分)
     - sam package --s3-bucket OUTPUT_S3_BUCKET --output-template-file outputtemplate.yml
artifacts:
 type: zip
 files:
   - template.yml
   - outputtemplate.yml

requirement.txt (Pythonコードで使用するライブラリの指定)

mysql-connector-python==8.0.16


おすすめの一冊

サーバレスよりもDevOpsの話ですが、業務利用に向けて勉強になる書籍があったため、紹介します。
個人、チーム、プロジェクト全体の各レベルでの活用方法が記載されているため、新人からPMの方まで幅広く読める内容だと思います。
(アフィリエイトなので、以下リンクより購入いただけたら嬉しいです、、)


この記事が気に入ったらサポートをしてみませんか?