LambdaのCustom Runtime のPHPを使って ALB + VPC Lambdaの構成でRDSに接続してみた
西田@大阪です。
この記事は AWS Lambda Custom Runtimes芸人 Advent Calendar 2018 の 6日目 です。
今回は Custom Runtime のLambda (PHP) を使ってALB + VPC Lambdaの構成でRDSのデータをブラウザに表示するところまでやってみました
(本当はWordPressを動かすところまでやりたかったのですが時間が足りず断念しました><)
構成図
前提
RDS, VPC, ALB はすでに作成済みで、RDSに接続できるSubnet, Security Groupがあるものとします
Lambda
ALBのHeath Checkを通すために提供されているPHP Custom Runtimeを修正
STACKERYより提供されているこちらのLayerを使って作成します
そのままですとALBのHealth Checkに失敗するのでリポジトリをCloneし、以下のファイルを修正をします
bootstrap
修正する箇所
response['statusDescription']
にHTTP のReason-Phraseまで含めた値を設定しますresponse['isBase64Encoded']
にfalseを設定します
差分
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $header) use (&$response) { - if (preg_match('/HTTP\/1.1 (\d+) .*/', $header, $matches)) { - $response['statusCode'] = intval($matches[1]); + if (preg_match('/HTTP\/1.1 ((\d+) .*)/', $header, $matches)) { + $response['statusCode'] = intval($matches[2]); + $response['statusDescription'] = trim($matches[1]); + $response['isBase64Encoded'] = false; return strlen($header); }
修正後のコード
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $header) use (&$response) { if (preg_match('/HTTP\/1.1 ((\d+) .*)/', $header, $matches)) { $response['statusCode'] = intval($matches[2]); $response['statusDescription'] = trim($matches[1]); $response['isBase64Encoded'] = false; return strlen($header);
修正したら make
コマンドを実行し作成されたzipファイルを使い以下の記事を参考にLambdaのLayerを作成します
DB接続に必要なPDOを追加するLambdaのLayerを作成
本番環境のLambdaをステップ実行!! Lambdaのカスタムランタイム環境(PHP用)にExtensionを組み込んでみた #reinvent
こちらを参考にすすめていきます
以下のシェルをbuild.sh
という名前で作成します
#!/bin/bash yum install -y php71-mysqlnd mkdir -p /tmp/layer/ cd /tmp/layer mkdir -p lib/php/7.1/modules for lib in mysqli.so mysqlnd.so pdo_mysql.so pdo.so; do cp "/usr/lib64/php/7.1/modules/${lib}" lib/php/7.1/modules done zip -r /opt/layer/php71_pdo.zip .
作成したシェルを使ってLayerにするzipファイルを作成します
docker run --rm -v $(ROOT_DIR):/opt/layer lambci/lambda:build-nodejs8.10 /opt/layer/build.sh
作成されたzipファイルを使って新しくLambdaのLayerを作成します
VPC Lambdaに必要な IAM Roleを作成
AWSLambdaVPCAccessExecutionRole がアタッチされた IAM Roleを作成します
Lambdaを作成
全体のファイル構成です
├── src │ └── php │ ├── php.ini │ └── index.php └── template.yaml
src/php/php.ini
mysql操作に必要なライブラリを有効にします
extension=mysqlnd.so extension=mysqli.so extension=pdo.so extension=pdo_mysql.so
src/php/index.php
動作確認用のコードです。testという名前のテーブルで、id, nameという列がありすでにデータが登録されている想定です
※ ALBのHealth Checkを通すためにContent-Type
はtext/html; charset=utf-8
と設定する必要がありました
<?php header('Content-Type: text/html; charset=utf-8'); $pdo = new PDO('${RDSのホスト名};dbname=${DB名};charset=utf8', '${ユーザー}', '${パスワード}', array(PDO::ATTR_EMULATE_PREPARES => false)); $stmt = $pdo->query("SELECT * FROM test"); ?> <html> <ul> <?php while($row = $stmt->fetch()): ?> <li><?php echo 'id:' . $row['id'] . ', name: ' . $row['name'] ?></li> <?php endwhile; ?> </ul> </html>
template.yaml
SAMのテンプレートです
AWSTemplateFormatVersion: 2010-09-09 Description: My PHP Application Transform: AWS::Serverless-2016-10-31 Resources: phpserver: Type: AWS::Serverless::Function Properties: FunctionName: !Sub ${AWS::StackName}-phpserver Description: PHP Webserver CodeUri: src/php Runtime: provided Handler: index.php MemorySize: 3008 Timeout: 30 Tracing: Active Role: ${LambdaにアタッチするIAM Role のarn} Layers: - ${PHP Layerのarn} - ${PHP PDO Layerのarn} VpcConfig: SecurityGroupIds: - ${RDSに接続できるSecurity Group} SubnetIds: - ${RDSに接続できるSubnet} Events: api: Type: Api Properties: Path: /{proxy+} Method: ANY
デプロイ用のS3に作成しSAMを実行しLambdaをデプロイします
sam package --template-file template.yaml --output-template-file serverless-output.yaml --s3-bucket ${S3バケット} sam deploy --template-file serverless-output.yaml --stack-name my-first-serverless-php-service --capabilities CAPABILITY_IAM
ALB
こちらを参考ALBを作成し、ターゲットグループに作成したLambdaを登録します
注意点として、STACKERYより提供されているこちらのLayerはmultiValueHeadersを返すようになってるのでALB側も複数値のヘッダーを有効にしないと Health Check に失敗します
ブラウザで確認
データベースに登録されている内容が表示されれば成功です
さいごに
WordPressを動かそうとしていろいろ試行錯誤した結果を残して置きます。
また時間を作ってWordPressを動かすところまでやりたいと思います。