AUTO1 Group

Take a deep Bref, and run your Symfony app serverless

By Wojciech Oroński

Wojciech is a Senior Software Engineer at AUTO1 Group.

< Back to list
Coding Jun 24

tl;dr

Since AWS lambda supports custom runtimes you can use PHP to create AWS lambda functions. But it comes with two major drawbacks

  • first running custom runtime for PHP is not very easy,
  • the second which is limiting usage of popular PHP frameworks in lambda functions development process.

With bref.sh these problems will disappear. Let's try to run Symfony framework as a serverless app.

What is serverless ?

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.

Here comes Bref.

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 - " our serverless microservice is ready to use. Let's check our resources in the AWS console. SAM deploy created the corresponding AWS Lambda Functions and API Gateway resources.

Lambda Functions:

lambda

API Gateway:

api-gateway

Just check your execution url in API Gateway:

aws-api-invoke

Then run it in your browser. You should see symfony default page.

symfony

Performance:

  • PHP Performance on Lambda isn't super-hot. During my tests, I achieved ~40ms for a simple CRUD POST request with 2048 MB of the memory set.

Other drawbacks:

  • While using MySQL or PqSql cold starts (around 5s)
  • Bref is a young project in advanced beta stage.
  • Still, it's a unicorn and only AWS is supported
  • Not all PHP extensions are working out of the box, but almost every extension can be used thanks to custom extension Bref PHP

But still I think this is a great starting point and I believe it can solve two major problems of the "serverless PHP":

  • easily deploy process on serverless platforms
  • make development with PHP frameworks like before

Further info

Stories you might like:
CodingSep 9
By Oleg Osipenko

This blog post explains how you could set up your environment in order to test your fragments in...

CodingJul 2
By Nicholas Peretti

Create forms at scale with Formik and Yup

CodingApr 4
By Chirag Swadia

How we use ES6 generators instead of thunk to simplify our React Redux application code and...