Symfony on a lambda: first deployment

hyoa

Matsounga Jules

Posted on November 8, 2019

Symfony on a lambda: first deployment

Symfony on a lambda: first deployment

English isn't my first language, help me improve my posts by pointing my mistakes

We can run serveless on many platforms, and same goes for cloud functions. As Bref only support AWS, we will focus on this platform.

As mentioned, we will use Bref. It help run PHP on a AWS Lambda.

We will use it with Symfony, a popular PHP framework.

If you are lost, you can find the project on Github: link
Each branch will match a chapter.

Requirements

  • Have the requirements to run Symfony on your computer (PHP and some extensions)

  • Have an AWS account(you can create one here: registration). We will stay below free tier limit, so no worries for your wallet.

  • Create an access key:

    • Create a new user here
    • Add a user name
    • Enable Programmatic access
    • Click Attach existing policies directly, search for **AdministratorAccess **and select it.

    Warning: it is recommended to only select right that you really need. But too keep this presentation simple, we will use a full access key.

    • Finish creating the user
    • Take note of keys generated, we will need them after
  • Install serverless: npm install -g serverless

  • Create the configuration of serverless: serverless config credentials --provider aws --key <key> --secret <secret> where key and secret are from the keys generated earlier

Symfony

We now have everything we need to start our development. Let's go !

Installation of Symfony

In your terminal, type the following command at the root of your projects composer create-project symfony/website-skeleton [my_project_name] (remember to replace [my_project_name] with yours)

Once the installation done, you can go in the folder where is your Symfony application.

We can now install Bref, which is required to deploy PHP on a lambda. To do so, once in the project, type composer require bref/bref

Creation of the serverless.yml

This file will define the architecture that we will deploy on AWS, that will be called CloudFormation. It's in this file that we will define services and resources and their configurations that we want on AWS.

To create this file, Bref give us a command that will help init a project. Type vendor/bin/bref init et select HTTP application.

The command create our serverless.yml file and an index.php file at the root of our project. You can delete index.php we wont use it.

The serverless.yml should look like this:

service: app #Name of your application

provider:
    name: aws #Provider used by Serverless
    region: us-east-1 #Region where you will deploy your CloudFormation
    runtime: provided

plugins:
    - ./vendor/bref/bref

functions:
    api: #Name of the function
        handler: index.php
        description: ''
        timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
        layers:
            - ${bref:layer.php-73-fpm}
        events:
            -   http: 'ANY /'
            -   http: 'ANY /{proxy+}'

The most interesting part is functions where we will be able to define our functions that we need (it can be commands, apis, crons, etc...).

  • handler: the php file used by the lambda
  • description: well, a description ?
  • timeout: maximum execution time of the function
  • layers: Layers are environment used by the lambda to run, you can have multiple layers to add other extensions, dependencies etc. Here, we use the layer of Bref, that run PHP with the layer of Node (more on layers)
  • events: events that will trigger the function. On this function, the HTTP event will trigger the lambda, but there is a lot of other events triggered by AWS that we can listen. We will see an other one later

Now that we have a better understanding of our file, lets changed it to run Symfony.

service: cloud-project

provider:
    name: aws
    region: eu-west-2
    runtime: provided
    stage: dev
    environment:
        APP_ENV: prod
plugins:
    - ./vendor/bref/bref

functions:
    website:
        handler: public/index.php
        timeout: 28
        layers:
            - ${bref:layer.php-73-fpm}
        events:
            -   http: 'ANY /'
            -   http: 'ANY /{proxy+}'

    console:
        handler: bin/console
        timeout: 120
        layers:
            - ${bref:layer.php-73}
            - ${bref:layer.console}

Not too many change. I changed the name of the application in cloud-project (you can put whatever you want). I also add a stage that define the environment publish.
In environment we have the environment variables used by our functions.
I also create 2 functions:

  • website that is the same than the api function we had in the file. We only change the handler that now target the index.php of Symfony.
  • console used to run Symfony command

Symfony configuration

We will have to change some files in Symfony to make it work on a lambda.

System file is readonly except /tmp, we have to change where are stored cache and logs.
In src/Kernel.php, we need to add 2 methods:

// src/Kernel.php
...

public function getLogDir(): string
{
  if (getenv('LAMBDA_TASK_ROOT') !== false) {
    return '/tmp/log/';
  }

  return parent::getLogDir();
}

public function getCacheDir(): string
{
  if (getenv('LAMBDA_TASK_ROOT') !== false) {
    return '/tmp/cache/'.$this->environment;
  }

  return parent::getCacheDir();
}

We also need to change index.php.

Once deployed, the lambda that use API Gateway have a domain that is created and that end with th stage deployed (ex: https://lamnda/dev). It can create some issue with PHP framework. You can easily solve this by creating a custom domain that get ride of this suffix (more information](https://bref.sh/docs/environment/custom-domains.html)). But to keep this presentation accessible, we won't do it.
We have to change some servers variables so the Symfony routing wont break.

// public/index.php

$_SERVER['SCRIPT_NAME'] = '/dev/index.php';
if (strpos($_SERVER['REQUEST_URI'], '/dev') === false) {
    $_SERVER['REQUEST_URI'] = '/dev'.$_SERVER['REQUEST_URI'];
}

You need to put this line before new Kernel(...). /dev is the stage defined in serverless.yml. If you create your own application, you should really create your own domain. It can be a bit long (propagation of DNS) but otherwise it's quite simple.

We don't need anything else. Let's code a bit.

Building a homepage

We will create a simple landing page si we have something to deploy. But we will keep it simple:

Create a file HomeController in src/Controller

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class HomeController extends AbstractController
{
    /**
     * @Route("/", name="home")
     */
    public function homeAction(): Response
    {
        return $this->render('home/index.html.twig');
    }
}

Create a file index.html.twig in templates/home

{% extends 'base.html.twig' %}

{% block body %}
    <h1>Symfony and lambdas</h1>
{% endblock %}

Yes, it's really simple but we don't really need anything else.

To see if it's working, type: php bin/console server:run and go to the url displayed. You should see your page.

Now, let's deploy it !

Deploy in the cloud

It might disappoint you, but you just need to run serverless deploy. The command will package your project, create the required resources on AWS. After few minutes, the endpoints of your function will be displayed. Use the first one, and you should see your site deployed !

You can see your CloudFormation on AWS here. You can also see the resources created by selecting Model then Display in Designer.


We now have a Symfony application running on AWS. Of course we are only at the beginning, but we will discover more in the next chapters.

In the next chapter we will talk about assets. Because without assets, there is no CSS or JS !

💖 💪 🙅 🚩
hyoa
Matsounga Jules

Posted on November 8, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related