Lambda から RDS にアクセスする方法 (python)

## 一行で説明
Python で書かれた Lambda function から RDS にアクセスする方法を説明します。


## 参考ページ

AWS の公式ドキュメントにチュートリアルがありますので、これに準拠します。ただし、チュートリアルでは CLI ベースで操作しますので、それを適宜マネコンからの操作に置き換えて行きます。

- [チュートリアル: Amazon VPC の Amazon RDS にアクセスできるように Lambda 関数を設定する](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/vpc-rds.html)

## 手順

1. RDS を作成
1. Lambda のデプロイパッケージ（zipファイル）を作成
1. Lambda に付与する IAM ロールの作成
1. Lambda 関数を作成
1. テスト実行

順を追って詳しく見ていきます。

## 1. RDS を作成

AWSのマネコン上から RDS を作成してください。
作成には少し時間がかかります。
作成完了しましたらローカルからアクセスができることを確認してみてください。

```
$ mysql -u username -h lambda.xxxxxxxxxxxx.us-east-1.rds.amazonaws.com -p
```

### セキュリティグループの修正
RDS を作成するとセキュリティグループの設定として、デフォルトで送信元が制限されます。ですので、ローカル環境からアクセスできても、このあと Lambda からアクセス出来ないという問題が起こります。そこで、該当の RDS インスタンスのセキュリティグループを編集し、送信元を任意のIP(0.0.0.0/0)に変更してください。（要件に応じて適切なIPを設定してください。）

## 2. Lambda のデプロイパッケージ（zipファイル）を作成

現在、`/path/to/workdir/` で作業しているとします。
`/path/to/workdir/` は適宜読み替えてください。
以下のような Python スクリプトを作成します。ファイル名は `app.py` とします。

```python
import sys
import logging
import rds_config
import pymysql
#rds settings
rds_host  = "rds-instance-endpoint"
name = rds_config.db_username
password = rds_config.db_password
db_name = rds_config.db_name


logger = logging.getLogger()
logger.setLevel(logging.INFO)

try:
    conn = pymysql.connect(rds_host, user=name, passwd=password, db=db_name, connect_timeout=5)
except:
    logger.error("ERROR: Unexpected error: Could not connect to MySql instance.")
    sys.exit()

logger.info("SUCCESS: Connection to RDS mysql instance succeeded")
def handler(event, context):
    """
    This function fetches content from mysql RDS instance
    """

    item_count = 0

    with conn.cursor() as cur:
        cur.execute("create table Employee3 ( EmpID  int NOT NULL, Name varchar(255) NOT NULL, PRIMARY KEY (EmpID))")
        cur.execute('insert into Employee3 (EmpID, Name) values(1, "Joe")')
        cur.execute('insert into Employee3 (EmpID, Name) values(2, "Bob")')
        cur.execute('insert into Employee3 (EmpID, Name) values(3, "Mary")')
        conn.commit()
        cur.execute("select * from Employee3")
        for row in cur:
            item_count += 1
            logger.info(row)
            #print(row)


    return "Added %d items from RDS MySQL table" %(item_count)
```

`app.py` では `rds_config` と `pymysql` が import されていますので、これらを準備します。

まず、`rds_config.py` という名前で下記のような内容を保存します。

```python
#config file containing credentials for rds mysql instance
db_username = "username"
db_password = "password"
db_name = "databasename"
```

次に、pip を用いて `pymysql` を `/path/to/workdir/` に保存します。

```
$ pip install pymysql -t /path/to/workdir/
```

必要なファイルが準備できましたので、最後にこれらのファイルを Zip でアーカイブします。
ここで注意点として、ディレクトリごとアーカイブするのではなく、`/path/to/workdir/` 以下をアーカイブします。

```
$ zip -r app.zip /path/to/workdir/*
```

ここでは、`app.zip` という zip ファイルを作成しました。

## 3. Lambda に付与する IAM ロールの作成
AWS の IAM の画面で新規ロールを作成します。その際、AWS サービスロールとして `AWS Lambda` を選択します。
ここでは 'lambda-role' という名前をつけます。

## 4. Lambda 関数を作成
AWS マネコンから Lambda 関数を作成します。
今回は `Blank Function` を選択し、トリガーとしては API Gateway を選択しました。
このあたりは適宜必要なものを選択してください。
その他の設定項目は以下のようになります。

- Runtime: Python2.7
- Handler: app.handler
- Role: Choose an existing role
- Existing role: lambda-role
- Code entry type: Upload a .ZIP file
    - 先程作った `app.zip` をアップロードします

この設定で Lambda function を作成します。


## 5. テスト実行

最後に、手動実行します。
Lambda の画面で `Test` ボタンを押すと手動実行できます。
以下のような結果が帰ってくれば成功です。

```
"Added 3 items from RDS MySQL table"
```