Comment utiliser les microservices pour gérer le Serverless

Les applications monolitiques peuvent être trop lourdes pour migrer sur une architecture Serverless. Les microservices peuvent être d’une grande aide.

Si les entreprises ont commencé à développer leurs propres API, il  existe des risques que les anciens services monolithiques soient tout simplement trop lourds à provisionner avec des outils comme AWS CloudFormation. C'est un signe : il est temps de passer à l’ère du composant et de diviser chaque service en plusieurs services plus petits. Voyons comment et pourquoi les microservices peuvent aider à créer et à gérer des API serverless.

L'erreur du  Serverless Framework

Serverless Framework est un outil de création et de gestion d'API sur AWS Lambda. Il se connecte à API Gateway et Lambda via un template CloudFront - ce qui facilite l'écriture d'une application et son déploiement dans les environnements de staging et de production. Mais ce Serverless Framework peut aussi générer une erreur capable d’effrayer certains développeurs :

The CloudFormation template is invalid: Template format error: Number of resources, 201, is greater than maximum allowed, 200

Ce message d'erreur peut semer la confusion chez les développeurs qui n'ont pas plus de 200 endpoints (ce qu’indique pourtant le message).  Ce malentendu se produit parce que le terme « resources » ne fait pas référence aux endpoints d’API.  Le endpoint d'une API peut ressembler à une ressource unique alors qu'il est dans Serverless Framework, mais une fois compilé dans le modèle CloudFormation, il peut être divisé en trois ou quatre ressources différentes : une ressource pour la connexion à API Gateway, une pour la fonction Lambda, une pour un rôle lié à la gestion des identités et accès et éventuellement une autre si Simple Queue Service ou Simple Notification Service y sont associés.

Il n'y a aucun autre moyen de décomposer les endpoints de ces API serverless, que de les diviser en plusieurs phases déploiement, de sorte que les développeurs doivent ré-architecturer leur API.

Diviser en microservices

En partant du principe qu'une seule stack CloudFormation ne peut pas vraiment contenir plus de quelques endpoints d'API, les développeurs doivent diviser ce service en plusieurs services. Beaucoup de développeurs le font déjà. Ils peuvent même diviser les tâches courantes, telles que l'authentification utilisateur, en fonctions Lambda entièrement distinctes, pouvant être appelées par chaque microservice.  

Par exemple, une entreprise peut avoir un service Serverless qui récupère une licence via un identifiant, un second qui met à jour une licence par un autre identifiant et un troisième qui récupère les informations d’un compte. Tous ces services partagent la tâche commune d'authentification et de validation des droits d'accès des utilisateurs à l'API.

Puisque chacune de ces API Serverless est un service complètement séparé, elles créent chacune leur propre stack CloudFormation et leur passerelle API. Par conséquent, les développeurs ne peuvent pas créer une fonction d'autorisation pour la partager. Au lieu de cela, ils ont placé cette fonction d'autorisation en son propre microservice.

Dans cet exemple, la fonction d'autorisation se trouve en fait dans son propre référentiel séparé. Cela repose sur une fonction Lambda et on utilise CodeBuild avec une configuration de base buildspec.yml :

version: 0.2

phases:

  install:

    commands:

      # Pre-install dependencies and environment config

      - apt-get update

      - apt-get install -y ssh

      # Download SSH keys from S3

      - aws s3 sync s3://company-config/home/ ~/

      - chmod 0600 ~/.ssh/*

      - npm install npm@6 --global

      # Install dependencies needed for running tests

      - npm install

  pre_build:

    commands:

      # Discover and run unit tests in the 'tests' directory

      - npm test

  build:

    commands:

      # Build the js files

      - ./node_modules/.bin/tsc

      # Zip everything up excluding the node_modules/@types directory

      -

        zip -r archive.zip

        *.js src/*.js node_modules

        -x "node_modules/@types/*"

      # Use the AWS CLI directly to upload our lambda function

      -

        aws lambda update-function-code

        --function-name authenticate

        --zip-file fileb://archive.zip

        --publish > ./resp.json   

      # Tag the new version

      -

        aws lambda update-alias

        --function-name authenticate

        --name $BUILD_ENV

        —function-version

        $(echo "console.log(require('./resp.json').Version)"|node)

Ce script basique permet d'éviter les coûts inutiles liés à l'utilisation d'un framework, comme Serverless ou Apex, et se connecte directement à la fonction Lambda depuis les autres microservices. En utilisant directement la ligne de commande AWS, vous pouvez télécharger une nouvelle version de votre microservice et la taguer en fonction de l'environnement de compilation, ou même de taguer des versions spécifiques par type de version. On peut également maintenir une version séparée du code utilisé pour le développement, le staging et la production en définissant la propriété « Qualifier » sur lambda.invoke :

const lambda_resp = await lambda.invoke({

         FunctionName: 'authenticate',

         Qualifier: process.env.BUILD_ENV,

         Payload: JSON.stringify(event),

      }).promise();

Notez que cette méthode ne gère pas automatiquement les rôles IAM ni les variables d'environnement. Les rôles IAM ne devraient pas changer fréquemment.

Regrouper tous les microservices dans un seul domaine

L’autre difficulté est d'exposer tous ces services à un seul domaine. En utilisant le plug-in Serverless Framework serverless-domain-manager, on peut configurer un domaine personnalisé qui référence chacun des microservices sous un chemin de base différent. Voici un exemple :

custom:

  customDomain:

    domainName: api.example.com

    basePath: licenses

Malheureusement, le chemin de base ne peut pas contenir de slashes, donc les développeurs doivent utiliser des noms de domaine séparés pour chaque environnement de compilation en ajoutant cette étape à DomainName :

domainName: api-${opt:stage, self:provider.stage}.example.com

Dans cet exemple, chaque étape relève d'un domaine distinct (comme api-dev.example.com/licences). Pour mettre à jour une licence, cependant, l'API ne peut pas vivre sous le même chemin de base, ce qui signifie que les opérations list, fetch et update doivent toutes exister sous le même service Serverless - si vous utilisez le Serverless Framework.

Alternativement, vous pouvez créer chaque microservice comme une simple fonction Lambda et créer manuellement une gateway d’API pour y accéder. En la créant séparément de la fonction Lambda, on peut plus facilement déployer des mises à jour de microservices et tous les lier ensuite à une unique passerelle API et un domaine personnalisé.

Serverless Framework : un ciment pour les microservices

Le problème avec Serverless Framework est qu'il ne simplifie pas le processus de division des fonctions Lambda en microservices, capables de se déployer individuellement. Chaque fois que vous exécutez sls deploy, il regroupe tout le code dans le répertoire courant et l’upload sous forme de stack CloudFormation. Chaque fonction Lambda de ce service utilise donc la même base de code avec un point d’entrée différent. Cette configuration va à l'encontre des bases des microservices : faire fonctionner chaque microservice séparément et indépendamment les uns des autres.

Il est également difficile de diviser chaque microservice en son propre service Serverless, car on ne  peut pas avoir plusieurs microservices sous un seul chemin de base. Pour utiliser des API Serverless avec des microservices, il convient de garder séparée chaque gateway d'API les unes des autres et de produire une stack CloudFormation séparée pour chaque microservice. Ce n'est certes pas l'idéal. Cependant, la meilleure approche consiste à utiliser Serverless Framework pour déployer cette colle qui relie chacun des microservices déployés séparément sous une seule gateway.

Pour approfondir sur Architectures logicielles et SOA