Il y a quelques temps, nous avions découvert comment déployer du code sur AWS Lambda. Même si ce déploiement est assez simple, il y a quelques opérations annexes à faire pour configurer la sécurité ou les traces applicatives par exemple. De plus, le déploiement unitaire de fonctions a pour conséquence de multiplier le nombre de commandes à exécuter.

Heureusement pour nous, il existe un framework qui permet d’augmenter notre productivité quand on souhaite monter une architecture serverless sur AWS (pour le moment) à base de fonctions Lambda (et bien plus !). Ce framework se nomme : Serverless Framework. Reprenons notre premier exemple avec ce framework.

Installation

L’installation de Serverless framework nécessite NPM et s’exécute en une ligne de commande :

$ npm install serverless -g

Implémentation

Comme tout bon framework de développement, il est possible de créer un nouveau projet pré-configuré via une seule instruction :

$ serverless create --template aws-nodejs --name hello-world
Serverless: Generating boilerplate…
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.1.0
 -------'

Serverless: Successfully generated boilerplate for template: "aws-nodejs"

Le projet généré contient un exemple d’implémentation de fonction Lambda en Node.JS dans handler.js :

'use strict';

module.exports.hello = (event, context, callback) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Go Serverless v1.0! Your function executed successfully!',
      input: event,
    }),
  };

  callback(null, response);

  // Use this code if you don't use the http event with the LAMBDA-PROXY integration
  // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
};

Remplaçons le contenu par notre précédent exemple :

console.log('Loading function');

module.exports.hello = function(event, context, callback) {
    console.log('Received event:', JSON.stringify(event, null, 2));
    callback(null, "Hello world");
};

Vous remarquerez qu’il y a également un fichier de configuration serverless.yml. Ce fichier sera extrêmement important pour de futurs exemples.

Déploiement

Puisque la simplicité est de mise, le déploiement sur AWS se fait de cette façon :

$ serverless deploy
Serverless: Creating Stack…
Serverless: Checking Stack create progress…
.....
Serverless: Stack create finished…
Serverless: Deprecation Notice: Starting with the next update, we will drop support for Lambda to implicitly create LogGroups. Please remove your log groups and set "provider.cfLogs: true", for CloudFormation to explicitly create them for you.
Serverless: Packaging service…
Serverless: Uploading CloudFormation file to S3…
Serverless: Uploading service .zip file to S3…
Serverless: Updating Stack…
Serverless: Checking Stack update progress…
............
Serverless: Stack update finished…

Service Information
service: hello-world
stage: dev
region: us-east-1
api keys:
  None
endpoints:
  None
functions:
  hello-world-dev-hello: arn:aws:lambda:us-east-1:client-id:function:hello-world-dev-hello

Exécution

Comme on ne change pas une équipe qui gagne, l’exécution de la fonction Lambda peut se faire via le framework :

$ serverless invoke --function hello
"Hello world"

Si vous souhaitez passer des paramètres à la fonction, c’est tout aussi simple :

$ serverless invoke --function hello --path event.json
"Hello world"

Les logs de CloudWatch logs sont bien évidemment accessibles via serverless :

$ serverless logs -f hello
2016-11-18 00:22:53.628 (+00:00)        undefined       Loading function
2016-11-18 00:22:53.633 (+00:00)        238e925c-ad25-11e6-b980-af26dc49fedc    Received event: {}
END RequestId: 238e925c-ad25-11e6-b980-af26dc49fedc
REPORT RequestId: 238e925c-ad25-11e6-b980-af26dc49fedc  Duration: 2.82 ms       Billed Duration: 100 ms         Memory Size: 1024 MB    Max Memory Used: 34 MB

START RequestId: 68f35ab0-ad26-11e6-8c5a-a1572b47f13e Version: $LATEST
2016-11-18 00:31:56.307 (+00:00)        68f35ab0-ad26-11e6-8c5a-a1572b47f13e    Received event: {
  "key3": "value3",
  "key2": "value2",
  "key1": "value1"
}
END RequestId: 68f35ab0-ad26-11e6-8c5a-a1572b47f13e
REPORT RequestId: 68f35ab0-ad26-11e6-8c5a-a1572b47f13e  Duration: 0.92 ms       Billed Duration: 100 ms         Memory Size: 1024 MB    Max Memory Used: 34 MB

Il est même possible d’afficher les traces applicatives au fil de l’eau dans une console :

$ serverless logs -f hello -t
2016-11-18 00:22:53.628 (+00:00)        undefined       Loading function
2016-11-18 00:22:53.633 (+00:00)        238e925c-ad25-11e6-b980-af26dc49fedc    Received event: {}
END RequestId: 238e925c-ad25-11e6-b980-af26dc49fedc
REPORT RequestId: 238e925c-ad25-11e6-b980-af26dc49fedc  Duration: 2.82 ms       Billed Duration: 100 ms         Memory Size: 1024 MB    Max Memory Used: 34 MB

START RequestId: 68f35ab0-ad26-11e6-8c5a-a1572b47f13e Version: $LATEST
2016-11-18 00:31:56.307 (+00:00)        68f35ab0-ad26-11e6-8c5a-a1572b47f13e    Received event: {
  "key3": "value3",
  "key2": "value2",
  "key1": "value1"
}
END RequestId: 68f35ab0-ad26-11e6-8c5a-a1572b47f13e
REPORT RequestId: 68f35ab0-ad26-11e6-8c5a-a1572b47f13e  Duration: 0.92 ms       Billed Duration: 100 ms         Memory Size: 1024 MB    Max Memory Used: 34 MB

Nettoyage

Pour finir, il est possible de supprimer tout ce qui a été créé pour ce test ainsi :

$ serverless remove
Serverless: Getting all objects in S3 bucket…
Serverless: Removing objects in S3 bucket…
Serverless: Removing Stack…
Serverless: Checking Stack removal progress…
........
Serverless: Stack removal finished…

A noter que les logs ne sont pas supprimés, il faut donc le faire avec le client AWS :

$ aws logs delete-log-group   --log-group-name "/aws/lambda/hello-world-dev-hello"

Conclusion

Cette première découverte de Serverless Framework nous a permis de reproduire ce que nous avions fait à la main avec le client AWS. Nous avons exécuté à peu près le même nombre de commandes. En revanche, elles sont beaucoup plus simples. De plus, l’ajout de nouvelles fonctions ne nécessite pas l’exécution de nouvelles commandes. Ce qui permet d’augmenter significativement notre productivité.
Si vous avez été attentif, vous avez pu remarquer que le framework utilise AWS CloudFormation pour déployer sur AWS. C’est une solution bien plus industrielle que notre collection de lignes de commande AWS !

Enfin, une architecture serverless est généralement orientée événements. Or, la gros plus-value d’AWS Lambda, c’est la diversité des types d’événements supportés. Vous vous doutez bien qu’ils n’ont pas été oubliés par ce framework. Cela sera sûrement sujet à de futurs articles !

Comme son nom l’indique, c’est un framework. Son utilisation ajoute donc un risque en terme de dépendance, stabilité, évolutivité, … Cependant, le gain en terme de productivité étant tellement important que je pense que le jeu en vaut la chandelle. Et je devrais donc vous en reparler très prochainement. 😉