2023.10.10
AWS LambdaでPHPからMySQLへの接続の検証
結論
- AWSのサーバーレスLAMPスタックが社内のスタッフ向けのツールに利用できそう
- Webサービスのバックエンド処理にPHPを利用する場合はLambdaのメンテナンスコストが高くなりそう
はじめに
こんにちは。次世代システム研究室のT.Tです。
前回の記事では現在開発運用に携わっているサービスのcronで稼働しているバッチジョブのAWS移行の検証のために、PHPのYii2フレームワークのconsoleアプリケーションをLambda上で稼働させる内容についてご紹介しました。AWS移行にあたってバッチジョブ以外にも社内のスタッフ向けのツールもサーバーレスへの置き換えを検討しています。
社内のスタッフ向けのツールではユーザーのリクエストを受け付けてDBと連携してレスポンスを返す仕組みが必要になります。本記事ではAWS上でそのような仕組みを扱う新しいサーバーレスLAMPスタック – Part 1: 概要紹介を参考にして、Lambda上でPHPアプリケーションからRDBに接続するために調査した内容についてご紹介します。
1.サーバーレスLAMPスタックについて
サーバーレスLAMPスタックは以下の図のようなアーキテクチャです。このアーキテクチャによりサーバーレスでWebサービスへのユーザーリクエストを受け付けて、PHPとMySQLで連携して処理をしてレスポンスを返すことができます。
https://d2908q01vomqb2.cloudfront.net/b3f0c7f6bb763af1be91d9e74eabfeb199dc1f1f/2020/08/12/lamp_arch1.png
2.サーバーレスとコンテナの比較
サーバーレスLAMPスタックで実現したいことはECSとFargateでも実現できます。その点について比較してみます。
コンテナとサーバレスの使い分けによると、サーバーレスの方が実行環境やミドルウェアの管理も不要になることで、よりビジネスロジックに注力できそうです。一方制約は多くなりアプリケーションの特性によりどちらかを選択することになりそうです。
https://d1.awsstatic.com/webinars/jp/pdf/services/202107_AWS_Black_Belt_Container350-Container_and_Serverless.pdf
こちらの資料にそうした部分を踏まえたデシジョンツリーがあります。この内容から判断すると社内のスタッフ向けのツールに適していそうです。
https://d1.awsstatic.com/webinars/jp/pdf/services/202107_AWS_Black_Belt_Container350-Container_and_Serverless.pdf
3.Lambda上でのPHPアプリケーションの実行
まずは、新しいサーバーレスLAMPスタックの手順に従いLambda上でPHPアプリケーションを実行できるようにします。手順の概要は以下の内容です。
- Lambda上で利用するバージョンのPHPをコンパイルする
- コンパイルしたPHPの実行ファイルとbootstrapファイルをruntime.zipにパッケージ化する
- Guzzleのファイルをvendor.zipにパッケージ化する
- runtime.zipとvendor.zipをLambdaレイヤーとして発行する
- 関数を作成して発行した2つのレイヤーを追加する
以下の内容をindex.phpに保存して、関数のハンドラをindexに変更します。
index.php
<?php function index($data) { return "Hello, ". $data['name']; }
テストを実行してみると正しく構築できていることが確認できます。
4.RDSの設定
先程作った関数にVPCとサブネットを設定してから、新しいサーバーレスLAMPスタック – Part 2: リレーショナルデータベースを参考にしてRDSを構築してみます。
- create-db-cluster AWS CLIコマンドを呼び出して、Aurora MySQL DBクラスターを作成します。バージョンはAurora MySQL version numbers and special versionsの内容に合わせて書き換えています。
$ aws rds create-db-cluster \ --db-cluster-identifier sample-cluster \ --engine aurora-mysql \ --engine-version 8.0.mysql_aurora.3.04.0 \ --master-username **** \ --master-user-password **** \ --db-subnet-group-name default-vpc-**** \ --vpc-security-group-ids sg-**** --enable-iam-database-authentication
- 新しい DBインスタンスをクラスターに追加します。
$ aws rds create-db-instance \ --db-instance-class db.r5.large \ --db-instance-identifier sample-instance \ --engine aurora-mysql \ --db-cluster-identifier sample-cluster
- データベースの認証情報をシークレットとしてAWS Secrets Manager に保存します。
$ aws secretsmanager create-secret \ --name MyTestDatabaseSecret \ --description "My test database secret created with the CLI" \ --secret-string '{"username":"****", "password": "****", "engine":"mysql", "host": "sample-cluster.cluster-****.ap-northeast-1.rds.amazonaws.com", "port":"3306", "dbClusterIdentifier":"sample-cluster"}' { "ARN": "arn:aws:secretsmanager:ap-northeast-1:****:secret:MyTestDatabaseSecret-****", "Name": "MyTestDatabaseSecret", "VersionId": "****" }
- シークレットへの secretsmanager アクセス許可を提供する IAMポリシーを作成します。
$ aws iam create-policy \ --policy-name my-rds-proxy-sample-policy \ --policy-document '{"Version": "2012-10-17", "Statement": [{"Sid": "VisualEditor0", "Effect": "Allow", "Action": ["secretsmanager:GetResourcePolicy", "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret", "secretsmanager:ListSecretVersionIds"], "Resource": ["arn:aws:secretsmanager:ap-northeast-1:****:secret:MyTestDatabaseSecret-a9I2aS"]}, {"Sid": "VisualEditor1", "Effect": "Allow", "Action": ["secretsmanager:GetRandomPassword", "secretsmanager:ListSecrets"], "Resource": "*"}]}' { "Policy": { "PolicyName": "my-rds-proxy-sample-policy", "PolicyId": "ANPASZGRTPWCIXSLK7A7L", "Arn": "arn:aws:iam::****:policy/my-rds-proxy-sample-policy", "Path": "/", "DefaultVersionId": "v1", "AttachmentCount": 0, "PermissionsBoundaryUsageCount": 0, "IsAttachable": true, "CreateDate": "2023-10-09T07:24:49+00:00", "UpdateDate": "2023-10-09T07:24:49+00:00" } }
- RDS Proxyサービスとの信頼関係を持つIAMロールを作成します。
- 新しいポリシーをロールにアタッチします。
$ aws iam attach-role-policy --role-name my-rds-proxy-sample-role --policy-arn arn:aws:iam::****:role/my-rds-proxy-sample-role An error occurred (InvalidInput) when calling the AttachRolePolicy operation: ARN arn:aws:iam::****:role/my-rds-proxy-sample-role is not valid.
$ aws iam create-role --role-name my-rds-proxy-sample-role --assume-role-policy-document '{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "rds.amazonaws.com" }, "Action": "sts:AssumeRole" } ]}'
IAMの設定でエラーになってしまったので、IAM認証を無効にして接続を検証してみます。
5.Lambda上のPHPアプリケーションからRDSへの接続
関数のハンドラに設定しているindex.phpの内容を書き換えてRDSに接続してみます。
index.php
<?php function index($data) { $mysqli = mysqli_init(); $proxyHost="sample-cluster.cluster-cd1tao0yu0ex.ap-northeast-1.rds.amazonaws.com"; $username = "****"; $password = "****"; $db = "mysql"; $port = 3306; //Connect to Proxy using acces token $mysqli->real_connect($proxyHost, $username, $password, $db, $port, NULL, MYSQLI_CLIENT_SSL); if ($mysqli->connect_errno) { echo "Error: Failed to make a MySQL connection, here is why: <br />"; echo "Errno: " . $mysqli->connect_errno . "<br />"; echo "Error: " . $mysqli->connect_error . "<br />"; exit; } $res = mysqli_query($mysqli,"SHOW TABLES"); while($cRow = mysqli_fetch_array($res)) { $tables[] = $cRow; } echo '<pre>'; print_r($tables); echo '</pre>'; $mysqli->close(); return json_encode($tables); }
更新したコードをデプロイしてからテストを実行してみると、DBへの接続が成功してテーブル情報が取得できました。
6.まとめ
今回の検証でLambda上のPHPアプリケーションからRDSへ接続できることが確認できました。サーバーレスLAMPスタック環境を構築するには更にサーバーレスLAMPスタック – Part 3: Webサーバーの置き換えで紹介されている内容も追加していく必要があり、環境構築は大変な印象です。また、PHPの実行環境は自前で用意する必要があるので、PHPバージョンアップのタイミングではLambdaの実行環境の更新も行う必要があります。こうした部分も踏まえてECSとの比較検討を進める必要がありそうです。
次世代システム研究室では、アプリケーション開発や設計を行うアーキテクトを募集しています。アプリケーション開発者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。
皆さんのご応募をお待ちしています。
グループ研究開発本部の最新情報をTwitterで配信中です。ぜひフォローください。
Follow @GMO_RD