Comment faire du Serverless

Nous avons vu dans le précédent article (Les architectures Serverless) une définition et la promesse que les architectures Serverless pouvaient offrir. Cependant nous étions restés dans l'expectative. Dans cet article nous verrons concrètement quelles sont les technologies disponibles aujourd’hui pour développer son architecture Serverless de demain.

Déballons la “Function as a Service”

Précédemment nous avons vu ce qu'était le FaaS dans les grandes lignes. Mais creusons un peu plus cette notion. Pour ce faire, je me suis inspiré du découpage de Mike Roberts qui me semble très clair et qui traite correctement chacunes des couches du FaaS. Pour commencer, reprenons la définition AWS du produit “Lambda” puis étudions chaque concept un par un.

AWS Lambda vous permet d'exécuter du code sans avoir à mettre en service ou gérer des serveurs (1). Vous payez uniquement pour le temps de calcul consommé, il n'y a aucun frais lorsque votre code n'est pas exécuté. Avec Lambda, vous pouvez exécuter du code pour pratiquement n'importe quel type d'application ou service dorsal (back-end) (2), sans aucune tâche administrative. Il vous suffit de charger votre code : Lambda fait le nécessaire pour l'exécuter (3) et le dimensionner (4) en assurant une haute disponibilité. Vous pouvez configurer votre code de sorte qu'il se déclenche automatiquement depuis d'autres services AWS (5), ou l'appeler directement à partir de n'importe quelle application Web ou mobile (6).

  1. Fondamentalement, FaaS concerne l'exécution de code back-end sans gérer de systèmes de serveurs ou de serveurs applicatifs. Cette seconde clause “serveurs applicatifs” est la différence clé lorsque l’on compare cette technologie avec d’autres tendances architecturales modernes comme le PaaS ou la conteneurisation.
  2. L’offre FaaS ne nécessite pas de coder au travers d’un framework ou d’une librairie spécifique. L’unique dépendance d’environnement que l’on peut avoir est liée aux possibilités offertes par le service selon le fournisseur. Par exemple, à ce jour les fonctions AWS Lambda peuvent être implémentées en JavaScript, Python ou tout autre langage issu de la JVM (Java, Clojure, Scala, …) alors que Google Cloud Platform propose uniquement le JavaScript (dû principalement à la très haute performance de son moteur JavaScript). Cet environnement d'exécution n’est cependant pas fixe en raison de notre capacité à exécuter d’autres processus. De ce fait, il nous est possible d’utiliser tous les langages sous condition qu’ils puissent être compilés par un processus Unix. Nous pouvons toutefois retrouver des restrictions d’architectures principalement lorsque l’on parle d’état ou de durée d'exécution, mais nous reviendrons plus tard sur ces points.
  3. À partir du moment où nous n’avons pas de serveurs applicatifs pour héberger le code, l’exécution est de ce fait très différente des systèmes traditionnels. Le processus de mise à jour commence par l’upload du code au fournisseur de service puis l’appel d’une API de fournisseur pour signifier la mise à jour du code.
  4. Le scaling horizontal (augmentation du nombre d’instances) est complètement automatique, élastique et géré par le fournisseur de services. Si votre système a besoin de répondre à 100 requêtes en parallèle, le fournisseur du service s’en chargera sans aucune intervention de votre part sur la configuration.
  5. Rappelons que le FaaS est un service basé sur l’event-driven. De ce fait, les fonctions sont déclenchées par des événements. Nous pouvons avoir différents types d’événement comme ceux issus des services du fournisseur. Parmi ceux-ci nous avons des événements lors de la mise à jour d’un fichier sur un bucket, des événements planifiés (cron) ou même la réception de messages via un système de queuing. Votre fonction devra par la suite fournir des paramètres spécifiques à la source de l’événement à laquelle elle est liée.
  6. Il vous sera aussi possible de déclencher des fonctions en réponse à des requêtes HTTP entrantes, généralement au travers d’une passerelle API (API Gateway, WebTask, Cloud endpoints).

Cycle de vie

Les fonctions FaaS ont des restrictions importantes en ce qui concerne leurs cycles de vie. La principale est son mode “Stateless”, aucune donnée ne sera disponible lors d’une invocation ultérieure, cela inclut les données en mémoire ou celles que vous auriez pu écrire en local sur le disque. Cela peut avoir un énorme impact sur votre architecture applicative mais rappelons-le, cette spécification est aussi présente dans “The twelve-factor App”.
Durée d'exécutionLes fonctions FaaS sont limitées en durée d’exécution. Par exemple les AWS Lambda ne sont pas autorisées à s’exécuter plus de 5 minutes et si elles le font, elles se termineront automatiquement à la fin de cette période.

Cela remet l’accent sur le fait que les fonctions FaaS ne sont pas appropriées à tous les use-cases ou du moins devront être adaptées pour pallier ces contraintes. Par exemple, dans une application traditionnelle vous pouvez avoir un seul service qui exécute une longue tâche alors qu’en FaaS, il vous faudra sûrement le séparer en différentes fonctions indépendantes les unes des autres mais possiblement séquencées.

Latence de démarrage

Le temps de réponse de votre fonction FaaS à une demande dépend d'un grand nombre de facteurs et peut aller de 10 ms à 2 minutes. Soyons un peu plus précis, en utilisant AWS Lambda comme exemple. Si votre fonction est implémentée en JavaScript ou Python qui sont des langages interprétés avec un contenu simple (moins d'un millier de lignes de code), la durée de chargement (warmup) devrait se situer entre 10 et 100 ms. Des fonctions plus importantes peuvent occasionnellement voir ce temps augmenter. Si votre fonction Lambda est exécutée dans une JVM (Java, Scala, Kotlin, …), vous pourrez avoir un temps de démarrage drastiquement plus long (> 10 secondes) rien que pour le chargement de la JVM. Cependant, ceci ne se produit que pour l'un ou l'autre des scénarios suivants :

  • Votre fonction traite rarement des événements (plus de 10 minutes entre les invocations)
  • Vous avez des pics très soudains dans le trafic, par exemple : vous traitez 10 requêtes par seconde, mais cela accélère jusqu'à 100 requêtes par seconde en moins de 10 secondes.

Il est possible d’éviter la première situation via le maintien opérationnel de votre fonction au travers d’un “ping” toutes les N secondes.

Ces problèmes sont-ils préoccupants ?

Cela dépend du style et de la forme du trafic de votre application et du maintien en activité de vos fonctions. Cela dit, si vous étiez en train d'écrire une application à faible latence, vous ne voudriez probablement pas utiliser les systèmes FaaS à ce moment-là, quel que soit le langage que vous utilisez pour la mise en œuvre.
Si vous pensez que votre application peut avoir des problèmes comme celui-ci, vous devriez tester avec une charge représentative de la production pour effectuer un bench des performances. Si votre cas d'utilisation ne fonctionne pas maintenant, gardez à l’esprit qu’il s'agit d'un domaine majeur de développement par les fournisseurs de FaaS.

La Gateway API

Jusqu’à maintenant nous avons abordé de nombreuses notions et services liés au FaaS. Mais je tiens particulièrement à mettre l’accent sur l’un d’eux qui est la Gateway API. Une Gateway API est un serveur HTTP où les contrats / endpoints sont définis au travers d’une configuration. Ceux-ci vont alors générer un événement qui pourra être utilisé au travers d’une fonction FaaS. En règle générale, la Gateway API permet le mapping des paramètres d’une requête HTTP aux arguments d’entrée d’une fonction FaaS puis elle transformera le résultat de l’appel à la fonction en une réponse HTTP et la renverra à l’appelant d’origine. Au-delà des demandes de routage simple, ce service permet aussi d’avoir des notions d’authentification ou même de validation des paramètres.

L’utilisation combinée des API Gateway + FaaS peut donner lieu à la création de microservices http-frontend de type serverless avec tous ses avantages comme par exemple le scaling automatique.

À l’heure actuelle, l’outillage pour les passerelles API est immature et comporte de nombreuses lacunes lorsque l’on veut y appliquer des processus de développement (versioning, ...).

L’outillage

Ce manque de maturité des outils liés aux services d’API Gateway s’applique malheureusement aussi aux services FaaS. Cependant il existe des exceptions : un exemple est Auth0 Webtask qui accorde une priorité significative au développement d’interfaces orientées utilisateurs.

Parmi ces lacunes, nous retrouvons le manque de fonctionnalités de débogage, de versioning ou de logging, même si celles-ci commencent à être comblées petit à petit (exemple X-Ray chez AWS)

Comment faire du Serverless

Après avoir expliqué le Pourquoi et le Quand passons maintenant au Comment.

Ne nous voilons pas la face, aujourd’hui le FaaS a du mal à être adopté au sein des sociétés, seuls certains use cases sont à ce jour applicables. La principale raison vient du fait qu’il est encore difficile de simuler en interne toutes les briques BaaS et FaaS permettant de développer et tester sa solution avant une mise en production.

Cependant de nombreuses solutions sont en cours de développement à la fois par la communauté Open source et les Cloud Providers afin d’offrir le niveau de services suffisant pour pallier ce problème.

Je ne pourrai pas vous détailler tous les services disponibles de type Serverless dans cet article mais je vous invite à vous rendre sur la page suivante pour avoir un listing exhaustif :

https://github.com/anaibol/awesome-serverless

BaaS et nos amis les Cloud Providers

Comme détaillé dans les architectures présentées dans l’article précédent, il n’y a pas de FaaS sans BaaS. Les principaux fournisseurs de ces services managés “clé en main” sont bien évidemment nos amis les Cloud Providers. Nous pouvons lister 3 acteurs majeurs aujourd’hui. Nous retrouvons bien sûr les géants : Amazon Web Services, Google Cloud Platform et Microsoft Azure mais des solutions comme Auth0 et Iron commencent à faire parler d’elles.

Vous trouverez ci-dessous un tableau récapitulatif des principales solutions 100% managées disponibles dans le Cloud.

Amazon Web Services Google Cloud Platform Microsoft Azure Services
Compute
AWS Lambda Google Cloud Functions Azure Functions
Storage
Amazon Glacier and Amazon S3 Standard - Infrequent Access Google Cloud Storage Nearline Azure Cool Block Storage
Amazon S3 Google Cloud Storage Standard Azure Block Storage
Amazon EC2 Container Registry Google Container Registry Azure Container Registry
Database
Amazon DynamoDB Google Cloud Datastore or Google Cloud Bigtable Azure DocumentDB
Big data
AWS Data Pipeline Google Cloud Dataflow and Google Cloud Dataproc Azure HD Insight
Amazon Kinesis and Amazon Simple Queue Service (SQS) Google Cloud Pub/Sub Azure Event Hubs and Azure Service Bus
Amazon Redshift Google BigQuery Azure SQL Data Warehouse and Azure Data Lake Analytics
Monitoring
Amazon CloudWatch Google Cloud Monitoring and Google Cloud Logging Azure Application Insights and Azure Operational Insights

Faire du FaaS

L’intégration d’une fonction est relativement simple. Il s’agit généralement d’un bout de code dans un langage compatible avec le fournisseur du service (généralement NodeJS, Java, C#, Go et Python) qui est compilé, zippé et déployé. La partie complexe se trouve dans la configuration et l'interaction des fonctions avec les autres services (API Gateway, DB, Stockage, …).

C’est pourquoi nous avons aujourd’hui deux approches qui sont en train d’émerger au sein des frameworks Open Source.

  • La première plus orientée infrastructure vous permettra de gérer relativement facilement l’intégration de vos fonctions et de toutes les ressources liées à elles. Ces frameworks se basent généralement sur les API fournies par les Cloud Providers ou les services de type DevOps (exemple de CloudFormation chez AWS).
  • La seconde, plus orientée API et ressources Web correspond le plus à la vision actuelle des développeurs de solution avec une abstraction simple de la communication entre une API Gateway et une fonction.

Vision infrastructure

A ce jour la tendance de développement de la communauté Open Source se dirige plus vers une vision InfraAsCode. Ils permettent d’une façon relativement simple, via des CLI et des fichiers de configuration, d’interagir avec les différents services Cloud et de gérer l’intégralité de la stack technique liée à une fonction.

L’un des acteurs les plus connus à ce jour est le framework Serverless. Il est compatible avec les solutions Cloud suivantes : AWS, IBM OpenWhisk, Microsoft Azure, GCP, Kubeless, Spotinst, Webtask.

Afin de vous donner une première vision de ce que vous pouvez faire, voici un petit Getting Started que vous pouvez faire assez rapidement et voir la puissance que ces fonctions serverless peuvent avoir.

Pré-requis : AWS Cli avec un compte AWS fonctionnel

$ mkdir my-first-function && cd my-first-function
$ serverless create --template aws-nodejs

Modifiez ensuite le fichier serverless.yml comme suit :

service: aws-nodejs
provider:
  name: aws
  runtime: nodejs6.10
  region: eu-central-1

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: users
          method: get

Puis exécutez les commandes suivantes pour tester votre nouvelle fonction :

$ serverless deploy [--stage stage_name]
$ serverless invoke [local] --function function_name
$ serverless info
$ curl $URL
$ serverless remove

Vision API

L’un des exemples d’implémentation de cette vision est le framework Chalice. Pour le petit historique, ce framework a été initialement développé par AWS afin de permettre de concilier et simplifier l’implémentation pour les développeurs. Il est à ce jour à la version 1.0.3 et évolue très rapidement.

Il vous permettra d’avoir le niveau d’abstraction nécessaire pour qu’un développeur sans réelle connaissance du monde du cloud ou des services associés puisse en 5min mettre en place une fonction accessible via un contrat REST.

Au même titre que l’article sur le framework Serverless, voici un aperçu rapide de celui-ci :

Pré-requis : AWS Cli avec un compte AWS fonctionnel et bien sûr le package Chalice

$ chalice new-project s3test && cd s3test

Remplacer le contenu du fichier app.py par celui-ci. Il vous permettra de créer un contrat REST ‘/objects/{key}’ accessible via GET et PUT afin de pouvoir lire ou déposer un contenu sur un bucket S3.

import json
import boto3
from botocore.exceptions import ClientError

from chalice import Chalice
from chalice import NotFoundError

app = Chalice(app_name='s3test')

S3 = boto3.client('s3', region_name='eu-west-1')
BUCKET = 'ippevent-public'

@app.route('/objects/{key}', methods=['GET', 'PUT'])
def s3objects(key):
    request = app.current_request
    if request.method == 'PUT':
        S3.put_object(Bucket=BUCKET, Key=key,
                      Body=json.dumps(request.json_body))
    elif request.method == 'GET':
        try:
            response = S3.get_object(Bucket=BUCKET, Key=key)
            return json.loads(response['Body'].read())
        except ClientError as e:
            raise NotFoundError(key)

Puis exécuter les commandes suivantes :

$ chalice local
$ http put  http://localhost:8000/objects/document.json value1=123
$ http get http://localhost:8000/objects/document.json
$ chalice deploy
$ chalice url

En l’espace de quelques lignes il vous est possible d’accomplir une tâche qui en prendrait beaucoup plus si vous deviez gérer le démarrage ou la gestion d’un serveur.

Conclusion

Au cours de cet article, nous sommes allés un peu plus en profondeur sur la notion de FaaS et son intéraction au sein d’un environnement Cloud. Comme vous avez pu le voir au cours des deux exemples d’implémentation, la communauté Open Source produit un énorme effort pour pallier les nombreuses lacunes que possède cette technologie. Celles-ci sont principalement dues à sa jeunesse et il est encore difficile de l’imaginer dans des processus de développement complexes ou même d’industrialisation. L’application backend full Serverless de demain n’est pas encore pour tout de suite mais ne saurait tarder.

Author image
Architecte Cloud & DevOps chez Ippon Technologies, évangéliste Serverless et contributeur sur des projets Open Source comme JHipster et daSWAG. Il est fier d’être un #GeekEnthusiast.
Lyon LinkedIn