Serverless PHP on AWS Lambda

Original author: Rob Allen's
  • Transfer
Hello. On Monday, the first lesson will be held in the new group of the course "Backend PHP Developer" . In this regard, we continue to publish useful material on the topic. Let's get started.



Like Simon Wordley , I believe that serverless computing is an extremely interesting area, primarily because of the granular payment system (pay only when your code is executed), and you do not need to worry about servicing and preparing servers and containers. So much so that I work with the open PHP Runtime for Apache OpenWhisk , a commercial version of which is available as one of the features of the IBM Cloud .

There are other serverless providers, and AWS Lambdais a market leader, but until recently, PHP support was extremely cumbersome and unpretentious. This changed at the end of 2018 with the new Lambda runtime API and layer support .

Let's take a look at the practical aspects of serverless PHP on Lambda with the Serverless Framework .

TL; DR


The source code for a simple Hello World is in my lambda-php repository on Github. Go to the Notes section and we can continue.

Php runtime


The runtime API allows you to use any runtime with Lambda. In a way, this is similar to OpenWhisk, as there is an HTTP API between the serverless platform and the runtime. There is one big difference that with Lambda, the runtime sends a request to the platform to receive the call data, while OpenWhisk calls the endpoint that the runtime should provide. For more information, see Michael Moussa's AWS blog post that inspired me to do the job.

To get started, we need the PHP runtime for Lambda. It will consist of a PHP executable, PHP code to call a serverless function, and a filebootstrapas required by the platform. From these three things we collect a layer. Layers can be reused in different accounts, so I am surprised that AWS does not provide us with a PHP account. Incredible, but true, they do not use PHP 7.3, so we will have to build our own.
All the files we put in the directory layer/phpin our project.

Building a PHP executable


We need a PHP executable that will run inside Lambda containers. The easiest way to do this is to compile it on the same platform as Lambda, so we will use EC2. Michael’s article explains how to do this, and I wrapped these commands in the compile_php.sh script , then to copy it to an EC2 instance, run and copy the executable file back to my computer:

$ export AWS_IP=ec2-user@{ipaddress}
$ export SSH_KEY_FILE=~/.ssh/aws-key.rsa
$ scp -i $SSH_KEY_FILE compile_php.sh $AWS_IP:doc/compile_php.sh
$ ssh -i $SSH_KEY_FILE -t $AWS_IP "chmod a+x compile_php.sh && ./compile_php.sh 7.3.0"
$ scp -i $SSH_KEY_FILE $AWS_IP:php-7-bin/bin/php layer/php/php


This approach will make it well reproducible, and hopefully it will just upgrade to new versions of PHP.

Bootstrapping


Since we use the runtime API, we need a bootstrapfile. Lambda itself requires such a name to specify the file; it responds to a function call that matches the images by calling the API in a loop.

In essence, we need to be in a loop and call the endpoint in /nextorder to understand what to call next, call it, and then send the answer to the endpoint /response.
AWS provides an example in BASH using curl :

while true
do
  HEADERS="$(mktemp)"
  # Get an event
  EVENT_DATA=$(curl -sS -LD "$HEADERS" -X GET "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
  REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS" | tr -d '[:space:]' | cut -d: -f2)
  # Execute the handler function from the script
  RESPONSE=$($(echo "$_HANDLER" | cut -d. -f2) "$EVENT_DATA")
  # Send the response
  curl -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response"  -d "$RESPONSE"
done


We want to do the same in PHP, and although I could write it myself, Pariksit Agnihotri is already ahead of me in PHP-Lambda-Runtime / runtime.php , so we just copy this into layer/php/runtime.php. In my version, I made several changes, added json_encoding and improved the error handler.
The file is layer/php/bootstrapvery simple, and all that is required of it is to run the PHP executable file with this file:

#!/bin/sh
cd $LAMBDA_TASK_ROOT
/opt/php /opt/runtime.php


That's all. Now we have three files in layer / php:

  • php - PHP executable file;
  • runtime.php - Working file runtime API;
  • bootstrap - required Lambda file.


As a result, all this will become a PHP Layer (layer) in our Lambda application.

Configure Serverless Framework


The Serverless Framework provides repeatable configuration and deployment of a serverless application. I am a fan of this concept and I want to use more of such tools. We will use the Serverless Framework for our PHP Hello World.
Since there is no convenient template for applications in PHP in the Serverless Framework, we simply create a file serverless.ymlin the directory with our project.
For starters, the most basic:

service: php-hello-world
provider:
  name: aws
  runtime: provided
  region: eu-west-2
  memorySize: 128


We will name our application php-hello-worldand use AWS as a provider. Since I am in the UK, I have established the London region . We do not need a lot of memory, so 128 MB will be enough.
Runtime is usually the language in which you want your function to execute. To use runtime APIwhich our bootstrapfile will execute , you set this field to provided .
And you will need a .gitignorefile containing:

.serverless


Since gitwe do not need this directory.
Next, let's add our layer to serverless.yml, adding:

layers:
  php:
    path: layer/php


This will create an AWS layer and give it a name PhpLambdaLayerthat we can reference in our function.

Let's write a function Hello World
Now we can write our serverless PHP function. This must be entered in the file  handler.php : 

 "hello from PHP " . PHP_VERSION];
}


The function takes information about the event and returns an associative array.
To tell Serverless Framework about the deployment of our function, you need to add the following to the file serverless.yml:

functions:
  hello:
    handler: handler.hello
    layers:
      - {Ref: PhpLambdaLayer}


Serverless Framework supports several functions for one application. Each of them has a name, in this case  hello , and, in our case, a handler, which is the name of the file without the extension, followed by a period, and then the name of the function in this file. Thus, the handler  handler.hello means that we will run the function  hello() in  handler.php .
Finally, we also report functions to our PHP layer so that it can execute PHP code.

Deployment in Lambda


To expand our function with its layer, we run the following command:

$ sls deploy


If the command is executed for as long as possible, an output similar to this will be obtained:



Fulfillment of our function


After deployment, we can call the function using the command:

$ sls invoke -f hello -l




And you're done!

To summarize


With new layers and runtime APIs, you can now easily run PHP serverless functions in Lambda. This is good news for PHP developers tied to AWS.

Waiting for your comments, friends!

Also popular now: