28
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

RDS Proxy を使って、AWS Lambda から接続してみた

Last updated at Posted at 2022-02-26

はじめに

AWS Lambda が良く語られますが、予測不可能なリクエストが来た時に、多くのインスタンスを横に並べてリクエストを捌く構成があります。AWS Lambda の場合は、1リクエスト1インスタンスとなるので、需要が高まったときには必然的に多くのインスタンスが立ち上がる構成になります。この時、インスタンス が RDS のコネクションを取得している場合、多くのデータベースコネクションを取得することにより、データベース側の負荷が高まってしまう課題がありました。

こういった問題を解決するための選択肢の一つとして、RDS Proxy と呼ばれるデータベースのコネクションをプールしてくれる機能があります。Amazon RDS に備わっている機能となっており、複数のインスタンス間でデータベースコネクションをプールしてくれます。

RDS Proxy を利用するメリットは次の通りです。

  • アプリケーションのスケーラビリティ
  • データベースのフェールオーバーに伴う、アプリケーション側のフェールオーバーにかかわる時間の短縮
  • AWS IAM 認証により、クレデンシャル情報を Secret Manager に持ち、セキュリティの向上に寄与

今回は、RDS Proxy を構成してみて、AWS Lambda から接続する方法を確かめてみましょう。

Aurora MySQL

Aurora MySQL 2.08 クラスターを既に稼働している環境を利用していきます。Writer Instance が 1 台、Reader Instance が 1 台存在しています。

image-20220226172239143.png

Secret Manager で Secret の作成

RDS Proxy を作成する際に、Secret Manager でデータベースへクレデンシャル情報を定義する必要があります。Secret Manager のページを開いて、Store a new secret を押します

image-20220226181533963.png

User name や Password を指定します

image-20220226181637740.png

対象の Database を選択して Next を押します

image-20220226181715450.png

適当に名前を入れて Next を押します

image-20220226181802490.png

ローテーションは OFF にしておきます

image-20220226181824470.png

Next

image-20220226181834044.png

Store を押して作成します

image-20220226181849486.png

作成されました

image-20220226181914171.png

RDS Proxy の作成

RDS のページで、Proxies のメニューを選んだ後、Create proxy を押します。

image-20220226173211816.png

いくつかのパラメータを指定します

image-20220226173423905.png

いくつかのパラメータを指定します

  • RDS Proxy が連携するデータベースを指定
  • RDS Proxy がプーリングするコネクションの割合を指定
  • RDS Proxy としての Reader Endpoint を有効化

image-20220226173752810.png

RDS Proxy では、データベースへアクセスするユーザーアカウントを Secret Manager で用意する必要があります。先ほど作成した Secret を選択します。

image-20220226182243527.png

Security Group を指定したのちに、Create proxy を押します

image-20220226182307913.png

RDS Proxy が Creating となりました

image-20220226182336535.png

一定時間後、Available に変わりました

image-20220226182923199.png

RDS Proxy の Endpoint を確認

RDS Proxy の詳細画面を開くと、RDS Proxy としての Endpoint を確認できます。

image-20220226183318985.png

MySQL Client から RDS Proxy を経由して接続

RDS Proxy が作成できたので、接続確認のために、MySQL Client から接続をしてみます。

mysql -u admin -h rds-proxy-test01.proxy-chuxmuzmrpgx.ap-northeast-1.rds.amazonaws.com -p

SELECT は問題なくできます。

mysql> SELECT * FROM sugi01.sample;
+----+-------+
| id | value |
+----+-------+
|  1 |     1 |
|  2 |     2 |
|  3 |     3 |
|  4 |     4 |
|  5 |     5 |
|  6 |     6 |
|  7 |     7 |
|  8 |     8 |
|  9 |     9 |
| 10 |    10 |
+----+-------+
10 rows in set (0.01 sec)

INSERT も OK です。

mysql> INSERT INTO sugi01.sample VALUES(11, 11);
Query OK, 1 row affected (0.02 sec)

mysql> SELECT * FROM sugi01.sample;
+----+-------+
| id | value |
+----+-------+
|  1 |     1 |
|  2 |     2 |
|  3 |     3 |
|  4 |     4 |
|  5 |     5 |
|  6 |     6 |
|  7 |     7 |
|  8 |     8 |
|  9 |     9 |
| 10 |    10 |
| 11 |    11 |
+----+-------+
11 rows in set (0.01 sec)

mysql>

ReadOnly の Endpoint にアクセスしてみます

mysql -u admin -h rds-proxy-test01-read-only.endpoint.proxy-chuxmuzmrpgx.ap-northeast-1.rds.amazonaws.com -p

INSERT は想定通りエラーになりました

mysql> INSERT INTO sugi01.sample VALUES(11, 11);
ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement
mysql>

Lambda Function を作成

次は、Lambda Function から RDS Proxy に接続する方法を確認していきましょう。今回は、SAM を使って Lambda Function を Deploy していきます。

SAM Project 作成

SAM Project を作成していきます。今回の記事の本筋ではないため、SAM の説明は省略していきます。

SAM Project を作成して、Hello World としての動作確認を行い、問題ない場合は一旦 Deploy を行います。

sam init
cd hello-rdsproxy
sam build
sam local invoke
sam deploy --guided

MySQL を Docker で動かす

ローカルで MySQL を Docker を使って動かします。動作確認用です。

docker run \
--name mydb \
-itd \
--hostname my-mysql \
-e MYSQL_ROOT_PASSWORD=mypassword \
-e BIND-ADDRESS=0.0.0.0 \
-p 3306:3306 \
public.ecr.aws/docker/library/mysql:8.0

MySQL に接続して、サンプルデータを格納します。

mysql -u root -h 127.0.0.1 --port=3306 -pmypassword

CREATE DATABASE sugi01;
USE sugi01;

CREATE TABLE sample2(
  id INT(11) NOT NULL AUTO_INCREMENT,
  name VARCHAR(10) NOT NULL,
  PRIMARY KEY (id)
);

INSERT INTO sample2(name) VALUES ("MySQL Data");

Python の動作確認 in Local

Function の環境変数を定義していきます。samconfig.toml に、次の値を追記します。

  • default.deploy.parameters : RDS Proxy に接続するための Endpoint や Username などを入力
  • default.local_invoke.parameters : Docker でうごかしている MySQL に接続するための情報を入力。IP アドレスは、Linux マシンの IP アドレスを指定
[default.deploy.parameters]
<省略>
parameter_overrides = "MysqlHostnameKey=rds-proxy-test01.proxy-chuxmuzmrpgx.ap-northeast-1.rds.amazonaws.com MysqlPortKey=3306 MysqlUsernameKey=admin MysqlPasswordKey=secret"

[default.local_invoke.parameters]
parameter_overrides = "MysqlHostnameKey=10.0.0.163 MysqlPortKey=3306 MysqlUsernameKey=root MysqlPasswordKey=mypassword"

Lambda Function に環境編素を渡すための設定を、 template.yaml に追記します。

Parameters:
  MysqlHostnameKey:
    Type: String
    Default: default1
  MysqlPortKey:
    Type: String
    Default: default2
  MysqlUsernameKey:
    Type: String
    Default: default3
  MysqlPasswordKey:
    Type: String
    Default: default4

Globals:
  Function:
    Timeout: 10
    MemorySize: 1024
    Environment:
      Variables:
        MYSQL_HOSTNAME: !Ref MysqlHostnameKey
        MYSQL_PORT: !Ref MysqlPortKey
        MYSQL_USERNAME: !Ref MysqlUsernameKey
        MYSQL_PASSWORD: !Ref MysqlPasswordKey

MySQL 接続に必要なライブラリをインストールします

cd ~/samdir/hello-rdsproxy
pip install mysql-connector-python

requirement.txt に、次のライブラリを追記します。

mysql-connector-python

Python のソースコードはこんな感じです。

  • 環境変数から接続先の MySQL の情報を取得
  • sugi01.sample2 のデータを取得して、1行だけ出力
import json
import os
import mysql.connector as mydb


def lambda_handler(event, context):

    hostname = os.environ['MYSQL_HOSTNAME']
    port = os.environ['MYSQL_PORT']
    username = os.environ['MYSQL_USERNAME']
    password = os.environ['MYSQL_PASSWORD']

    connection = mydb.connect(
        host=hostname,
        user=username,
        passwd=password,
        db='sugi01')

    cursor = connection.cursor()

    cursor.execute("SELECT * FROM sample2")
    selected = cursor.fetchone()
    print(selected)

    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": selected,
            # "location": ip.text.replace("\n", "")
        }),
    }

Build を行います

sam build

ローカルで動作確認です。

sam local invoke

実行例です。正常にローカルの MySQL と接続できています。

> sam local invoke
Invoking app.lambda_handler (python3.9)
Skip pulling image and use local one: public.ecr.aws/sam/emulation-python3.9:rapid-1.40.0-x86_64.

Mounting /home/ec2-user/samdir/hello-rdsproxy/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated inside runtime container
START RequestId: 87a77126-7673-4228-bde8-073b187965db Version: $LATEST
(1, 'MySQL Data')
END RequestId: 87a77126-7673-4228-bde8-073b187965db
REPORT RequestId: 87a77126-7673-4228-bde8-073b187965db  Init Duration: 0.06 ms  Duration: 156.75 ms     Billed Duration: 157 ms Memory Size: 1024 MB    Max Memory Used: 1024 MB
{"statusCode": 200, "body": "{\"message\": [1, \"MySQL Data\"]}"}⏎

Deploy

Lambda Function をデプロイしましょう

まず、SAM の template.yaml を編集して、Lambda を VPC 内部にデプロイする必要があります。次のように、Security Group と Subnet を指定しましょう。

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.9
      VpcConfig:
        SecurityGroupIds:
          - sg-00515cac8ae3971b6
        SubnetIds:
          # Subnet IDを書く
          - subnet-0d9a1ae8571fa7c30
          - subnet-0355f72e6534092bf
          - subnet-0c4b7c352a610baf4

SAM deploy を行っていきます。

sam deploy

動作確認

無事に Deploy が完了しました!次のようにアクセスすると、正常にデータが返ってきています。

> curl https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message": [1, "MySQL Data"]}⏎      

負荷を掛けてみましょう

watch -n 0.1 curl https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/

RDS Proxy のメトリックを見てみると、データベースコネクションが増えている様子が見えます。

image-20220226213452182.png

参考URL

RDS Proxy の開始方法
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/rds-proxy-setup.html#rds-proxy-creating

28
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?