Since AWS lambda supports custom runtimes you can use PHP to create AWS lambda functions. But it comes with two major drawbacks
With bref.sh these problems will disappear. Let's try to run Symfony framework as a serverless app.
What does it mean that something is Serverless? Does it mean there are no servers at all? Of course not. There are still servers behind scenes, but you don't have to worry about maintaining the servers and reserve their capacity. Your infrastructure is scaled automatically, and you just pay only for what you use. Does this kind of architecture have only pros or there are some drawbacks? Let's leave the discussion of all the smaller pros and cons of serverless applications for another article. I will focus on the biggest drawback which is an impact on our code. Frameworks that we use in our daily PHP development are not ready to work with lambdas because they were not designed for those kinds of architecture. Imagine you are a PHP developer and you want to run serverless microservice using one of the most popular frameworks like Symfony or Laravel. Imagine you can develop your microservice locally and just deploy it as lambda functions. Is it possible with PHP programming language? Yes, it is. Even if AWS Lambda does not have native support for PHP.
Since AWS lambda supports custom runtimes, you can create one for PHP and run your lambda functions written in that language. There are plenty of articles which describe the process of creating custom runtimes, but believe me it's time-consuming and not super easy. Let's take a look at the bref.sh project and try to run a simple Symfony app as lambda.
I assume you have knowledge about Symfony framework, or you have an existing project and some knowledge about AWS platform.
Before we start please make sure you have installed:
First, we have to add Bref to our project with composer require mnapoli/bref
Then from your project root command line run vendor/bin/bref init
It will create two additional files in your project template.yaml and index.php.
You can remove index.php for this moment, as it will be unnecessary.
As you may know, AWS lambda filesystem is read-only excluding /tmp
dir
So we have to extend src/Kernel.php
of Symfony with these two functions
public function getLogDir(): string
{
// When on the lambda only /tmp is writeable
if (getenv('LAMBDA_TASK_ROOT') !== false) {
return '/tmp/log/';
}
return $this->getProjectDir().'/var/log';
}
public function getCacheDir(): string
{
// When on the lambda only /tmp is writeable
if (getenv('LAMBDA_TASK_ROOT') !== false) {
return '/tmp/cache/'.$this->environment;
}
return $this->getProjectDir().'/var/cache/'.$this->environment;
}
Let's take a closer look at template.yaml
Resources:
Website:
Type: AWS::Serverless::Function
Properties:
FunctionName: 'symfony-website'
CodeUri: .
Handler: public/index.php
Timeout: 30 # in seconds (API Gateway has a timeout of 30 seconds)
MemorySize: 1024
Runtime: provided
Layers:
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73-fpm:1'
Events:
HttpRoot:
Type: Api
Properties:
Path: /
Method: ANY
HttpSubPaths:
Type: Api
Properties:
Path: /{proxy+}
Method: ANY
Console:
Type: AWS::Serverless::Function
Properties:
FunctionName: 'symfony-console'
CodeUri: .
Handler: bin/console
Timeout: 120 # in seconds
Runtime: provided
Layers:
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73:1' # PHP
- 'arn:aws:lambda:us-east-1:209497400698:layer:console:1' # The "console" layer
Thanks to the configuration stored in template.yaml, Bref will create CloudFormation with two most important resources which are lambda functions that will handle all the requests. One called symfony-website and the second symfony-console, both names are defined under FunctionName
key.
Their execution will be available thanks to API Gateway which also will be created during the deploy process.
For testing purpose, you don't have to change template file much. Please remember to check your AWS default region if it's different than us-east-1
just change it in all Layers
key of your Resources.
OK. Let's check how it works and deploy.
First, we need to create s3 bucket per our app with simple AWS CLI command aws s3 mb s3://<bucket-name>
Then upload the code and generate the stack configuration:
sam package \
--output-template-file .stack.yaml \
--s3-bucket <bucket-name>
Finnaly deploy our microservice:
sam deploy \
--template-file .stack.yaml \
--capabilities CAPABILITY_IAM \
--stack-name <stack-name>
After we receive output "Successfully created/updated stack -
Lambda Functions:
API Gateway:
Just check your execution url in API Gateway:
Then run it in your browser. You should see symfony default page.
Performance:
Other drawbacks:
But still I think this is a great starting point and I believe it can solve two major problems of the "serverless PHP":
Improved Common Table Expressions in recent release of Postgres