LambdaからRDSへ接続してみる

#ご挨拶
タイトルの通りLambdaからRDSへ接続してみたので記事を書いていきます。
最近業務でLambdaを使用することが増えてきたので勉強になればと思いやってみました。
#やること
LambdaでプライベートサブネットにあるRDS MySQLに向けてSQLを実行して実行結果を確認します。
今回RDSの作成はCloudFormationを使用しています。
事前にプライベートサブネットを二つ作成しています。
以下の手順で進んでいきます。

1. Lambda関数の作成
2. IAMロールの編集
3. RDSの作成
4. LambdaをRDSに接続できるように設定
5. テスト実行

###構成図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/080a41ab-852d-2f12-2066-cf1b11abea77.png)

#参考にしたサイト
[チュートリアル: Amazon VPC の Amazon RDS にアクセスする Lambda 関数の設定](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/services-rds-tutorial.html)
[pymysqlのドキュメント](https://pymysql.readthedocs.io/en/latest/)

#やってみる
##1. Lambda関数の作成
マネジメントコンソールからLambdaへ移動
![スクリーンショット 2021-10-30 182647.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/521976db-b9f1-2273-22f8-8d35aa364d3d.png)
移動後、関数→関数の作成をクリック
![スクリーンショット 2021-10-30 183025.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/7ca1f916-5c6b-d9b5-7044-df1b13e23f21.png)
クリック後上から順に以下の画像のように選択と入力を行います
関数名はお好みで大丈夫です。
今回はPythonを使用して関数を作成するのでランタイムはPython3.9を選択しました。
IAMロールは新しく作成してくれるものを選択することでCloudWatch logsへのアクセス権をいい感じに絞ったものが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/2d151aa0-601a-decc-d946-a0810374a179.png)
作成が完了したら一旦マネジメントコンソールでの作業は終わりでコードを作成します。
###コード作成
pythonでMySQLの操作をするのにpymysqlというモジュールを使用します。
pymysqlはLambdaのデフォルトでは使用できないのでモジュールをzipにしてアップロードします。

```text:lambda_function.py
import os
import pymysql

host = os.environ['RDS_HOST_NAME']
user = os.environ['USER']
password = os.environ['PASS']
db = os.environ['DB']

connection = pymysql.connect(host=host, user=user, password=password, database=db)

def lambda_handler(event, context):
    with connection.cursor() as cursors:
        cursors.execute('show databases')
        print(cursors.fetchall())
```
作成されているスキーマを取得するものを作成しました。
execute()でSQLを実行して結果をfetchall()で取ってきています。
ここまで出来たらファイルを保存します。
保存したディレクトリ(フォルダ)と同じ階層にpymysqlを入れます。
以下のコマンドを実行します。

```text:powershell
pip install PyMySQL -t /ファイルがあるディレクトリ

もしくはファイルがあるディレクトリに移動して以下のコマンド実行

pip install PyMySQL -t ./
```
インストールができたらファイルとモジュールを一つのzipにします。
zipができたらマネジメントコンソールに戻ってアップロードします。
以下の画面からアップロード元→.zipファイル→アップロードの順でクリックして上記手順で作成したzipファイルをアップロードします。
![スクリーンショット 2021-10-30 233442.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/6881c526-8a8a-e31c-33e9-f9461ca2b6d9.png)
##2. IAMロールの編集
上記1まで出来たらIAMロールを編集します。
RDSにアクセスできるようにするにはENIが必要なためIAMでアクセス権を与えます。
以下の画面の設定→アクセス権限→実行ロールのところでLambdaにアタッチされているIAMロールが確認できます。
そこからIAMロールをクリックすると編集ができます。
![スクリーンショット 2021-10-30 234510.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/59c44c5f-0881-28b5-0e11-3cd80898637a.png)
クリックするとIAMの画面に移動します。
移動したら「ポリシーをアタッチします」をクリックしてIAMポリシーを選択します。
選択するポリシーはAWSLambdaVPCAccessExecutionRoleです。
アタッチできたらIAMの設定は終了です。
##3. RDSの作成
RDSの作成は以下のyamlで作成しました。
CloudFormationの使用方法は以下の記事の「CloudFormationでスタック作成」をご覧ください。
[【AWS】 CloudFormationで基本的な構成のEC2とRDSを作る](https://qiita.com/Mattun_0226/items/d0f49dbe84937de73a4d#cloudformation%E3%81%A7%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E4%BD%9C%E6%88%90)

```text:create_rds.yml
AWSTemplateFormatVersion: "2010-09-09"

Description: create rds

#パラメータ
Parameters:
  vpcid:
    Type: AWS::EC2::VPC::Id
    Description: Enter vpcid

  subnetid1: 
    Type: AWS::EC2::Subnet::Id
    Description: Enter RDS subnetid
  
  subnetid2: 
    Type: AWS::EC2::Subnet::Id
    Description: Enter RDS subnetid
  
  rdssubnetgroupname:
    Type: String
    Description: Enter RDS subnet groupname

  rdsdbname:
    Type: String
    Description: Enter RDS DBname

  rdsusername:
    Type: String
    Description: Enter RDS username
    AllowedPattern: '[a-zA-Z0-9]*'

  rdspassword: 
    Type: String
    Description: Enter RDS password
    MinLength: '8'
    MaxLength: '41'
    AllowedPattern: '[a-zA-Z0-9]*'

#リソース
Resources:
  lambdasecuritygroup:
    Type: AWS::EC2::SecurityGroup
    Properties: 
      GroupDescription: lambda-securitygroup
      SecurityGroupEgress: 
        - IpProtocol: -1
          FromPort: -1
          ToPort: -1
          CidrIp: 0.0.0.0/0
      VpcId: !Ref vpcid

  rdssecuritygroup:
    Type: AWS::EC2::SecurityGroup
    Properties: 
      GroupDescription: rds-securitygroup
      SecurityGroupEgress: 
        - IpProtocol: -1
          FromPort: -1
          ToPort: -1
          CidrIp: 0.0.0.0/0
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          SourceSecurityGroupId: !Ref lambdasecuritygroup
      VpcId: !Ref vpcid

  rdssubnetgroup: 
    Type: AWS::RDS::DBSubnetGroup
    Properties: 
      DBSubnetGroupDescription: rdssubnetgroup
      SubnetIds:  
        - !Ref subnetid1
        - !Ref subnetid2
      DBSubnetGroupName: !Ref rdssubnetgroupname
      Tags: 
        - Key: Name
          Value: rdssubnetgroup

  rdsinstance:  
    Type: AWS::RDS::DBInstance
    Properties: 
      AllocatedStorage: 20
      DBInstanceClass: db.t2.micro
      DBSubnetGroupName: 
        !Ref rdssubnetgroup
      DBName: !Ref rdsdbname
      Engine: mysql
      EngineVersion: "5.7.34"
      MasterUsername: !Ref rdsusername
      MasterUserPassword: !Ref rdspassword
      StorageType: gp2
      Tags:
        - Key: Name
          Value: rdsinstance
      VPCSecurityGroups: 
        - !Ref rdssecuritygroup
```
上記のテンプレートを使用してプライベートサブネットにRDSを作成します。
##4. LambdaをRDSに接続できるように設定
RDSの作成ができたら環境変数を登録していきます。
Lambda関数の設定画面から環境変数→編集をクリック
![スクリーンショット 2021-10-31 000648.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/196aa5e9-3e5f-227b-aec3-c59d42a0e05b.png)
キーと値には以下の4つを設定します。

| キー | 値 |
|:-:|:-:|
| RDS_HOST_NAME | RDSのエンドポイント |
| USER | MySQLのユーザ (CloudFormationで作成時に入力したユーザ) |
| PASS | MySQLのパスワード (CloudFormationで作成時に入力したパスワード) |
| DB | DB名 (CloudFormationで作成時に入力したDB名)  |
次にVPCの設定を行います。
Lambdaの設定→VPC→編集をクリック
![スクリーンショット 2021-10-31 003018.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/91eee5e8-0737-55b2-b1cc-3e9bb12f639e.png)
クリックしたら上からVPC、サブネット、セキュリティグループを選択します。
VPCはRDSと同じVPCを選択します。
サブネットはプライベートサブネットを選択します。
セキュリティグループはCloudFormationで作成したlambda-securitygroupを選択します。
##5. テスト実行
上記まで完了したらテスト実行してみます。
コード→Testをクリックします。
![スクリーンショット 2021-10-31 004712.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612471/f27d278a-149e-34c2-38ce-3790615e8fbd.png)
テストを実行してFunction Logsに以下のデータベースが出力されれば成功です。

```text:データベース
(('information_schema',), ('innodb',), ('lambda_to_rds',), ('mysql',), ('performance_schema',), ('sys',))
```
#感想
information_schemaが見れるので各テーブルのレコード数やAutoIncrementの数値を取ってきてCloudWatchメトリクスに登録するなどの活用ができそうだと思いました。(小並感)
使用方法によってはRDS Proxyというものを使用してLambdaからの大量の接続を維持することも検討する必要があるようです。
[AWS LambdaでAmazon RDS Proxyを使用する](https://aws.amazon.com/jp/blogs/news/using-amazon-rds-proxy-with-aws-lambda/)