LoginSignup
5

More than 3 years have passed since last update.

posted at

updated at

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

はじめに

この記事は、駆け出しエンジニアのための 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

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
What you can do with signing up
5