Déployer une application Laravel Serverless avec Bref en 5 minutes

Published in LaravelServerlessBref on Jul 15, 2020

Je me lance enfin dans la rédaction d'une série d'articles, fruit de mon expérience passée autour de PHP Serverless, et plus particulièrement avec le framework Laravel.

Tout à démarrer grâce au travail de Matthieu Napoli avec Bref, et notamment ce post de blog.

Alors bien sûr, en mai 2018, Bref n'avait pas la maturité d'aujourd'hui, mais cela avait déclenché chez moi pas mal de réflexion, étant alors à cette époque en train de concevoir une marketplace dans le domaine du marketing d'influence. Je cherchais alors une solution pour avoir un nombre important de worker pour un coût moindre.

Avec la version 0.3.x de Bref, tout s'est éclaircit grâce à l'utilisation du runtime d'AWS Lambda.
Bref, sans jeu de mot, tout est devenu plus, simple, les versions se sont alors enchaînées, pour être actuellement à la dernière en date à 0.5.29.

Vous pouvez également utiliser Vapor, excellent produit de l'écosystème Laravel et de Taylor Otwell, mais Bref vous donne la possibilité d'avoir la maîtrise des ressources via l'utilisation du Serverless Framework.

Sans plus attendre, attaquons nous à la création de notre première application PHP Serverless avec le framework Laravel :

Création de l'application

Ici, rien de particulier, juste à suivre la documentation de Laravel :

laravel new laravel-lambda-5min

Et voilà Bref

Vous avez plusieurs possibilités :

  • Soit vous suivez la section Laravel de la documentation, et vous aurez alors à implémenter plusieurs ajustements permettant de respecter les contraintes d'AWS Lambda : Bref

  • Soit vous utilisez le package tout frais qu'à créer Matthieu Napoli :
    brefphp/laravel-bridge

Personnellement, je vous recommande de suivre la première étape, cela vous permettra d'appréhender le fonctionnement et les contraintes.

Let's go

composer require bref/bref

Il faut ensuite créer le fichier serverless.yml, pour cela, un helper va vous permettre de le créer en fonction du use case :

vendor/bin/bref init

Dans ce premier post, je souhaite avoir rapidement l'affichage de la page par défaut de Laravel, on va donc prendre le modèle "HTTP Application".

Un script index.php va être créé ainsi que notre fichier de configuration serverless.yml.

Vous pouvez ici supprimer le fichier index.php qui vient d'être créé.
On va ensuite effectuer quelques ajustement à notre application Laravel.

Ouvrez le fichier app/Providers/AppServiceProvider.php et modifier le comme suit :

public function boot()
{
	// Make sure the directory for compiled views exist
    if (! is_dir(config('view.compiled'))) {
		mkdir(config('view.compiled'), 0755, true);
    }
}

Ouvrez ensuite le fichier app/Http/Middleware/TrustProxies.php, et définissez la valeur de $proxies comme suit :

protected $proxies = ['0.0.0.0/0', '2000:0:0:0:0:0:0:0/3'];

Nous allons ensuite nous occuper du fichier serverless.yml pour le modifier comme suit :

service: laravel-lambda-5min

provider:
	name: aws
	region: eu-west-1
	runtime: provided
	httpApi:
    	payload: '2.0'
	environment:
    	APP_KEY: <your_app_key>
    	VIEW_COMPILED_PATH: /tmp/storage/framework/views
    	SESSION_DRIVER: array
    	LOG_CHANNEL: stderr

plugins:
	- ./vendor/bref/bref

functions:
	web:
    	handler: public/index.php
    	description: ''
    	timeout: 28 # in seconds (API Gateway has a timeout of 29  seconds)
    	layers:
        	- ${bref:layer.php-74-fpm}
    	events:
        	- httpApi: '*'

package:
	exclude:
    	- .env
    	- node_modules/**
    	- public/storage
    	- resources/assets/**
    	- storage/**
    	- tests/**
        

A titre personnel, je préfère déployer une HTTP API, vous verrez ici les différences, depuis l'annonce de 2019. Cela évite les problème d'environnement dans les routes notamment.

N'oubliez pas de définir votre APP_KEY.

Le répertoire de stockage de compilation des views a été surchargé du fait de l'unique possibilité dans une Lambda d'écrire dans le répertoire /tmp.

Je n'ai pas besoin de session en l'état, par suite je publierais un autre post pour montrer comment stocker les sessions dans DynamoDB.

Enfin, les logs seront poussés vers Cloudwatch.

Nous avons alors une seule fonction 'web' au sens serverless qui utilise le layer Bref PHP 7.4 avec FPM.

Il est important d'avoir une archive de code la plus légère possible, il peut y avoir un impact notable sur les performances, pour cela nous excluons les répertoires présentés ci-dessus.

J'ajoute, qu'à titre personnel, je n'aime pas déployer de fichier .env sur mes environnements Serverless, je préfère exposer les variables d'environnements via le fichier serverless.yml, je vous présenterai également dans un autre post la gestion de ces variables via SSM (Parameter Store).

Enfin, par facilité, voici un Makefile

deploy:
	composer install --prefer-dist --optimize-autoloader --no-dev
	php artisan config:clear
	serverless deploy
    

Nous voilà fin prêt à déployer notre première Lambda :

make deploy

Le framework Serverless va alors s'occuper de toute la partie déploiement et provisionning des ressources.

Résultat

serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
........
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service laravel-lambda-5min.zip file to S3 (7.54 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
..............................
Serverless: Stack update finished...
Service Information
service: laravel-lambda-5min
stage: dev
region: eu-west-1
stack: laravel-lambda-5min-dev
resources: 11
api keys:
None
endpoints:
	ANY - https://ijlpfecr7j.execute-api.eu-west-1.amazonaws.com
functions:
	web: laravel-lambda-5min-dev-web
layers:
	None
    

Voici l'URL exposée par API Gateway : https://ijlpfecr7j.execute-api.eu-west-1.amazonaws.com

Conclusion

Il s'agit de mon premier post, ma plume n'étant pas très à l'aise, je vous remercie pour votre indulgence.

J'ai donc montré ici, comment en quelques minutes déployer une application Laravel en Serverless via AWS Lambda et Bref.

Je vous propose de poursuivre mes posts sur les sujets suivants :

  • Stockage des sessions dans DynamoDB
  • Traitements de queue SQS au sein de la même application
  • Traitements de queue SQS entre applications tierces
  • Gérer des évènements asynchrones avec un délai supérieur à 15min (limite de SQS)
  • Déploiement via Gitlab CI
  • Parsing d'email via SES
  • Gestion des migrations de base de données
  • Connexion à RDS
  • Indexation Elastic en asynchrone via Laravel Scout

N'hésitez pas à m'indiquer quels cas d'architecture vous souhaiteriez que j'aborde.

A vos commentaires et critiques !