LoginSignup
8
5

More than 5 years have passed since last update.

AWS LambdaでPHP動かして DynamoDBを操作する

Last updated at Posted at 2018-12-16

はじめに

この記事は、駆け出しエンジニアのための Advent Calendar 2018の15日目の記事です

re:Invent2018

先日ラスベガスで開催された、AWS re:Invent2018にて、
AWS Lambdaに、Custom Runtimeという機能が追加され、
Lambdaのサポート外の言語もLambda上で実行可能となりました。

今回は、PHPをLambda上で動かすために、STACKERYより提供されているこちらのPHPの Custom Runtimeを使用し、
Lambda上のPHPからDynamodbを操作するためにAWSが提供しているAWS SDK for PHPを使います。

環境

  • AWS CLI
    デプロイ用

  • AWS SAM CLI
    デプロイ用

  • Composer
    AWS SDK for PHPをインストールするために使用します。

インストールはリンクのURLを参考にしてください

開発準備

  • 処理対象となる、DynamoDBを作成する

  • 以下IAMポリシーがあるロールを作成する

    • AmazonDynamoDBFullAccess
    • AWSLambdaDynamoDBExecutionRole
  • デプロイ用にファイルを上げるS3バケットを作成する

  • 以下の構成でディレクトリを作成

|-- src
|   `-- php
`-- template.yml //AWS SAM CLI のデプロイ時に必要な構成ファイル
  • AWS SDK for PHPのインストール
$ php composer require aws/aws-sdk-php
  • php.iniの編集

今回使用しているPHPのCustom Runtime上ではデフォルトで、json.soの機能が使えません。
AWS SDK for PHPでは内部でjson.soを使用しているため有効化する必要があります。

PHPのCustom Runtime上で、json.soを有効化するために、php.iniファイルを作成し、
以下のようにextension を追加します。

php.ini
extension=json.so

こちらについては以下のカスタムランタイムのGithubのREADMEにて解説があります。
https://github.com/stackery/php-lambda-layer

プログラムの作成

データ登録処理

post.php
<?php
require 'vendor/autoload.php';

use Aws\Sdk;
use Aws\DynamoDb\Marshaler;
use Aws\DynamoDb\Exception\DynamoDbException;

$tableName = 'php_test'; //対象のテーブル名
$name = $_GET["name"]; //GETでリクエストされたデータ(name)を取得

$sdk = new Sdk([
    'region'   => 'ap-northeast-1', //使用するregion情報
    'version'  => 'latest'
]);

$dynamodb = $sdk->createDynamoDb();
$marshaler = new Marshaler();

$uid = uniqid(); //登録用にuuidを作成

$item = $marshaler->marshalJson('{
        "id": "' . $uid . '",
        "name": "'. $name .'"
    }
');

$params = [
    'TableName' => $tableName,
    'Item' => $item
];

try {
    $result = $dynamodb->putItem($params);
    echo "Added item success id:". $uid;
} catch (DynamoDbException $e) {
    echo "Unable to add item:\n";
    echo $e->getMessage() . "\n";
}

データ取得処理

getphp
<?php
require 'vendor/autoload.php';

use Aws\Sdk;
use Aws\DynamoDb\Marshaler;
use Aws\DynamoDb\Exception\DynamoDbException;

$tableName = 'php_test'; //対象のテーブル名
$id = $_GET["id"]; //GETでリクエストされたデータ(id)を取得

$sdk = new Sdk([
    'region'   => 'ap-northeast-1', //使用するregion情報
    'version'  => 'latest'
]);

$dynamodb = $sdk->createDynamoDb();
$marshaler = new Marshaler();

$key = $marshaler->marshalJson('{
        "id": "' . $id . '"
    }
');

$params = [
    'TableName' => $tableName,
    'Key' => $key
];

try {
    $result = $dynamodb->getItem($params);
    print_r($result["Item"]);
} catch (DynamoDbException $e) {
    echo "Unable to get item:\n";
    echo $e->getMessage() . "\n";
}

最終的なディレクト構成 以下ようになります

|-- src
|   `-- php
|       |-- vendor //AWS SDK for PHP
|       |-- composer.json //Composer file
|       |-- composer.lock //Composer file
|       |-- get.php //データ取得用処理
|       |-- php.ini // php.ini
|       `-- post.php //データ登録用処理
`-- template.yml

AWS SAM CLI 用のデプロイファイル

template.yml
AWSTemplateFormatVersion: 2010-09-09
Description: My PHP Application
Transform: AWS::Serverless-2016-10-31
Resources:
  phppost:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub test-phppost
      Description: PHP Post
      Role: [作成したロール情報]
      CodeUri: src/php
      Runtime: provided
      Handler: post.php
      MemorySize: 3008
      Timeout: 30
      Tracing: Active
      Layers:
        - !Sub arn:aws:lambda:[region]:887080169480:layer:php71:5
      Events:
        api:
          Type: Api
          Properties:
            Path: /post
            Method: ANY

  phpget:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub test-phpget
      Description: PHP Get
      Role: [作成したロール情報]
      CodeUri: src/php
      Runtime: provided
      Handler: get.php
      MemorySize: 3008
      Timeout: 30
      Tracing: Active
      Layers:
        - !Sub arn:aws:lambda:[region]:887080169480:layer:php71:5
      Events:
        api:
          Type: Api
          Properties:
            Path: /get
            Method: ANY

デプロイ

パッケージしてS3バケットへアップロード

$ sam package --template-file template.yml --output-template-file serverless-output.yaml --s3-bucket [作成したS3バケット]

デプロイ

sam deploy --template-file serverless-output.yaml --stack-name custom-runtime-php71  --capabilities CAPABILITY_IAM

動作検証

API Gatewayも同時に作成されているので、自動的に作成されたURLを確認し動作検証する

  • 登録処理   登録する内容をURLパラメータ name をリクエストする
https://xxxxxxx.execute-api.[resion].amazonaws.com/Prod/post?name=tanaka


レスポンスとして、発行されたIDが返却される

Added item success id:5c14940af36b0
  • データ取得処理

発行されたIDを取得用のキーとするためURLパラメータ id をリクエストする

https://xxxxxx.execute-api.[resion].amazonaws.com/Prod/get?id=5c14940af36b0


以下のようにDynamoDBから取得したデータが表示される

Array ( [id] => Array ( [S] => 5c1524cec4aa7 ) [name] => Array ( [S] => tanaka ) )

DynamoDBを確認するとリクエストしたデータが登録されているはずです

参考

https://dev.classmethod.jp/cloud/aws/php-vpc-lambda-alb-rds/
https://dev.classmethod.jp/cloud/aws/lambda-custom-runtime-php-extension
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/GettingStarted.PHP.03.html

8
5
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
8
5