サーバレスでお問い合わせフォームを実装してみる (4)
こんにちは、システムエンジニアの今井です。
前回のブログ「サーバーレスでお問い合わせフォームを実装してみる(3)」の続きです。
(導入編)「サーバーレスとは本当にサーバーがないこと?」
(1)サーバーレスでお問い合わせフォームを実装してみる(フォームとAPIの作成)
(2)サーバーレスでお問い合わせフォームを実装してみる(フォームからAPIへ値の送信)
(3)サーバレスでお問い合わせフォームに記載された内容をDBに保存してみる1
→(4)サーバレスでお問い合わせフォームに記載された内容をDBに保存してみる2
今回はお問い合わせ内容をデータベースに保存する処理を完成させたいと思います。

1. DB接続できるLambda関数のスケルトン作成
(1)前回、構築用に作成したEC2サーバーにsshクライアントで接続します。

(2)ホームディレクトリにディレクトリを作成し、カレントディレクトリを変更します。
mkdir contactInsert cd contactInsert
(3)ステータスコードとメッセージのみを返す関数を作成します。
vi lambda_function.py
関数の内容
import json
def lambda_handler(event, context):
# TODO implement
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
(4)AmazonLinux(EC2)のデフォルトのPythonは古いため、Python3をインストールします。
python -V >> Python 2.7.18 sudo yum -y install python3 python3 -V >> Python 3.7.9
(5)MySQLに接続するためのPythonライブラリをダウンロードします。
pip3 install pymysql -t ./ >> Successfully installed pymysql-1.0.2
(6)作成したファイルをzipファイルにまとめてダウンロードします。
ls >> lambda_function.py pymysql PyMySQL-1.0.2.dist-info zip -r contactInsert.zip ./*
作成したzipファイルは、のちほどAWSコンソールからアップロードして利用します。
2. DB登録するためのLambdaを作成
(1)Lambdaのページを開きます。
https://ap-northeast-1.console.aws.amazon.com/lambda/home

(3)関数名は「contactInsert」と入力し、ランタイムは「Python 3.7」を選択します。

(4)「デフォルトの実行ロールの変更」をクリックして「既存のロールを使用する」を選択します。

(5)既存のロールから「contact-example-role」を選択します。

(6)「contact-example-roleロールを表示」をクリックします。

(7)ロールの詳細ページで「ポリシーをアタッチします」をクリックします。

(8)ポリシーのフィルタに「AWSLambdaVPCAccessExecutionRole」と入力します。

(9)一覧から絞り込まれた「AWSLambdaVPCAccessExecutionRole」にチェックを入れて、「ポリシーのアタッチ」をクリックします。

(10)詳細設定をクリックして VPC、サブネット、セキュリティグループ(default)を選択します。

Lambdaを作成することができました。

3. ZIPファイルをLambdaに反映
「1.」で作成したzipファイルをアップロードしてLambdaに反映させます。
(1)contactInsertの詳細ページで「アクション」をクリックし、「.zipファイルをアップロード」を選択します。

関数コードのファイル一覧にアップロードしたzipファイルの内容が反映されます。

4. lambdaロールにInvokeFunctionを追加
(1)IAMのページを開きます。
https://console.aws.amazon.com/iam/home

(3)「contact-example-role」をクリックします。

(4)「インラインポリシーの追加」をクリックします。

(6)JSONの内容を以下に差し替えます。
JSONの内容
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction"
],
"Resource": "*"
}
]
}
(8)名前に「LambdaInvokeFunction」と入力し、「ポリシーの作成」をクリックします。

「LambdaInvokeFunction」が追加できました。
5. LambaのARN名の確認
contactInsertの詳細ページの上部にARN(Amazonリソースネーム)が表示されています。
のちほど、必要になるためコピーしておきます。

6. ContactSendからContactInsertを実行するための設定
(1)Lambdaの関数一覧から「contactSend」をクリックします。

(2)main.pyの72行目に以下のコードを追加します。
print('invoke start')
clientLambda = boto3.client("lambda")
clientLambda.invoke(
FunctionName="ここにさきほどコピーしたARN名を入れます",
InvocationType="Event",
Payload=json.dumps(event)
)
print('invoke end')
ContactSendが呼び出された際にContactInsertも呼び出されるように設定することができました。
7. ContactSendからContactInsertを実行しログを確認
実際に呼び出しが行われているか確認してみます。
(1)お問い合わせフォームのindex.htmlファイルを開きます。

(3)「CloudWatch」を開きます。
https://ap-northeast-1.console.aws.amazon.com/cloudwatch/home
(5)「/aws/lambda/contactInsert」をクリックします。

Log streamにさきほどのお問い合わせ操作のログが確認できました。

8. ContactInsert内にDBの保存処理を追加
(1)RDSのページを開きます。
https://ap-northeast-1.console.aws.amazon.com/rds/home

(3)プロキシの一覧から「proxy-contact-test」をクリックします。

(5)Lambda関数の一覧ページから「ContactInsert」をクリックします。

(6)「lambda_function.py」を以下のコードに差し替えます。

import json
import boto3
from urllib.parse import parse_qs
import time
import base64
import pymysql
ENDPOINT="ここにRDSProxyのエンドポイント名を入力します"
PORT="3306"
USER="admin"
REGION="ap-northeast-1"
DBNAME="test"
PASSWORD="ここにadminのパスワードを入力します"
def respond(err, res=None):
return {
'statusCode': '400' if err else '200',
'body': err.message if err else json.dumps(res),
'headers': {
'Content-Type': 'application/json',
},
}
def sendmail(to, subject, body):
client = boto3.client('ses', region_name='ap-northeast-1')
response = client.send_email(
Source=MAILFROM,
ReplyToAddresses=[MAILFROM],
Destination= {
'ToAddresses': [
to
]
},
Message={
'Subject': {
'Data':subject,
'Charset':'UTF-8'
},
'Body':{
'Text':{
'Data':body,
'Charset':'UTF-8'
}
}
}
)
print('Loading function')
def lambda_handler(event, context):
print("Received event: " + json.dumps(event))
try:
param = base64.b64decode(event['body'])
param = param.decode("UTF-8")
param = parse_qs(param)
company = param['company'][0]
name = param['name'][0]
kana = param['kana'][0]
email = param['email'][0]
tel = param['tel'][0]
contact = param['contact'][0]
ipaddress = event['requestContext']['http']['sourceIp']
useragent = event['requestContext']['http']['userAgent']
now = time.time()
print('pymysql start')
conn = pymysql.connect(ENDPOINT, user=USER, password=PASSWORD, db=DBNAME, connect_timeout=5)
with conn.cursor() as cursor:
sql = "INSERT INTO users (name) VALUES (%s)"
r = cursor.execute(sql, (name))
print(r) # -> 1
conn.commit()
print('pymysql end')
body = {'result':1}
return respond(None, body)
except:
import traceback
traceback.print_exc()
body = {'result':0}
return respond(None, body)
ここまでですべての設定が完了しました。
9. 動作確認
(1)お問い合わせフォームのindex.htmlファイルを開きます。

データベースにお問い合わせ内容が保存されているか確認します。
(2)「RDS Proxy」に接続します。
mysql -uadmin -p -h【RDS Proxyのエンドポイント】
(3)SQLを実行して保存された内容を確認します。
use 'test'; select * from users;
データベースに問い合わせ内容が保存されています。
以上で問い合わせ内容のデータベース保存機能を実現することができました。
Lambdaを利用した問い合わせフォームは初期構築にひと手間掛かりますが、Webサイトの基本的な機能を低コストで運用できるため、ランニングコストをぐっと下げることができます。
また、各サービスごとに柔軟なアクセス制御ができるため、セキュアに動作を実現することが可能です。
今回作成したお問い合わせフォーム以外にも様々な機能を実現できるため、サイト制作の際にはサーバーレスの導入を検討してみてはいかがでしょうか。


















