TP 3 - Lambda 🚄

đŸ§± Mise en place

Allez sur la plateforme AWS Academy et accédez au cours AWS Academy Learner Lab [43226]. Puis cliquez sur Modules > Learner Lab. Lancez votre environnement en cliquant sur Start Lab. Une fois le cercle passé au vert, cliquez sur AWS Details et AWS CLI. Les clés que vous voyez vont permettre un accÚs programmatique à votre compte. Cherchez le dossier .aws sur votre machine puis remplacez le contenu du fichier credentials par les clefs que vous venez de récupérer.

Ma premiĂšre Lambda

📄 DĂ©finition de la Lambda

Une fois sur la console AWS, cherchez le service Lambda dans la barre de recherche. Sur le tableau de bord Lambda, cliquez sur CrĂ©er une fonction. Laissez l’option CrĂ©er Ă  partir de zĂ©ro cochĂ©e, donnez un nom Ă  votre fonction Lambda, et, pour le langage d’exĂ©cution sĂ©lectionnez Python3.12. Conservez l’architecture x86_64, et dĂ©pliez Modifier le rĂŽle d'exĂ©cution par dĂ©faut, sĂ©lectionnez Utiliser un rĂŽle existant et sĂ©lectionnez le rĂŽle LabRole. CrĂ©ez votre fonction.

đŸ§™â€â™‚ïž À la diffĂ©rence des instances EC2, une fonction Lambda a besoin d’un rĂŽle pour fonctionner. Sans entrer dans les dĂ©tails, un rĂŽle va dĂ©terminer les droits de la fonction. Comme votre compte n’a pas le droit de crĂ©ation de rĂŽle, vous ne pouvez pas crĂ©er un rĂŽle Ă  la volĂ©e, et il faut sĂ©lectionner le rĂŽle LabRole dĂ©jĂ  créé.

Une fois sur la page de votre fonction, un code de base est proposĂ© par AWS. Ce code retourne simplement un code 200 et le texte Hello from Lambda!. Vous allez lancer cette fonction via le bouton Test. CrĂ©ez un nouvel Ă©vĂ©nement de test, que l’on va appeler test_basique, et laissez le JSON de base. Votre Ă©vĂ©nement de test sera un simple JSON de la forme :

{
  "key1": "value1",
  "key2": "value2",
  "key3": "value3"
}

Enregistrez-le et cliquez de nouveau sur Test. Normalement, tout devrait bien se passer.

Maintenant, vous allez lĂ©gĂšrement modifier la fonction. Au lieu de simplement retourner une chaĂźne de caractĂšres fixe, elle va retourner l’heure actuelle. Importez la classe datetime du module Ă©ponyme et utilisez le code datetime.now().strftime("%m/%d/%Y, %H:%M:%S") pour avoir l’heure et la date du jour sous forme de chaĂźne de caractĂšres. Comme votre fonction a Ă©tĂ© modifiĂ©e, il faut la redĂ©ployer avec le bouton Deploy. Une fois fait, testez-la de nouveau pour voir si tout fonctionne.

Ajout de l’invocation toutes les minutes

Sur la page de votre Lambda, cliquez sur + Ajouter un dĂ©clencheur. La source va ĂȘtre EventBridge. CrĂ©ez une nouvelle rĂšgle avec le nom minuteur. Le type de rĂšgle sera Expression de planification et l’expression rate(1 minute).

đŸ§™â€â™‚ïž EventBridge permet de gĂ©rer les Ă©vĂ©nements comme des alarmes quand un seuil est dĂ©passĂ©, mais aussi les Ă©vĂ©nements planifiĂ©s.

Votre fonction sera dĂ©sormais appelĂ©e toutes les minutes. Malheureusement, comme il n’y a pas de destination pour votre fonction, les rĂ©sultats disparaissent dans le nĂ©ant du cloud. Il est toutefois possible de voir qu’elle est invoquĂ©e en allant sur l’onglet Surveiller puis Journaux. Vous allez voir une ligne par minute, mais comme notre fonction ne log rien, vous n’allez voir aucun rĂ©sultat.

đŸ§™â€â™‚ïž Il est possible d’ajouter un logger (utile pour le debug) en faisant des print() (ce n’est pas idĂ©al), ou en utilisant le module logging.

import os
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)

def Lambda_handler(event, context):
 logger.info('## ENVIRONMENT VARIABLES')
 logger.info(os.environ)
    logger.info('## EVENT')
    logger.info(event)

⚒ Automatiser ce dĂ©ploiement

En vous aidant du code disponible ici https://github.com/HealerMikado/Ensai-CloudComputingLab3, créez un script terraform pour automatiser ce déploiement.

💹Pousser les rĂ©sultats dans une file SQS

Maintenant, vous allez faire en sorte que votre fonction envoie ses rĂ©sultats dans une file SQS. Cherchez le service SQS et crĂ©ez une file. Choisissez le type Standard et donnez-lui le nom de votre choix. Gardez toutes les valeurs par dĂ©faut et crĂ©ez votre file. Copiez l’URL de la file.

Retournez sur la page de votre Lambda et modifiez le code pour publier dans la file SQS en vous aidant du code suivant :

import json
import boto3
from datetime import datetime
sqs = boto3.client('sqs')  #client is required to interact with sqs

def Lambda_handler(event, context):
    # event provenant d'une Lambda
    data = int(json.loads(event["Records"][0]["body"])["data"])

    sqs.send_message(
        QueueUrl="VOTRE URL SQS",
        MessageBody=json.dumps({"body" : data})
    )
    return {
        'statusCode': 200,
        'body': data
    }

DĂ©ployez la nouvelle fonction, puis attendez quelques minutes. Ensuite, retournez sur la page de votre file SQS et cliquez sur Envoyer et recevoir des messages, puis sur Rechercher des messages. Vous devriez voir des messages apparaĂźtre. Cliquez sur l’un d’eux et vous devriez voir votre message.

🎉 FĂ©licitations ! Vous venez de mettre en place une architecture 100% serverless qui va rĂ©aliser un traitement toutes les minutes et pousser le rĂ©sultat dans une file pour ĂȘtre utilisĂ© par un autre service par la suite. MĂȘme si le code Python du traitement est assez simple, l’architecture, elle, ne l’est pas. Vous pourriez par exemple, avec ce systĂšme, faire une requĂȘte toutes les heures Ă  un webservice pour mettre Ă  jour des donnĂ©es en base.

🧼Une calculatrice

Maintenant vous allez rĂ©aliser une calculatrice en utilisant une fonction Lambda. Voici le schĂ©ma d’architecture globale.

Vous allez devoir créer :

  • Deux files SQS, une pour l’input et une pour l’output.
  • Une fonction Lambda qui va aller chercher les clĂ©s number1, number2 et operation et faire le calcul demandĂ©. Les opĂ©rations que l’on souhaite faire sont l’addition, la soustraction, la multiplication et la division.

Le déclencheur de la fonction Lambda passe des paramÚtres dans le dictionnaire event. Pour obtenir la clé number1, vous devez faire float(json.loads(event["Records"][0]["body"])["number1"]).

đŸ§™â€â™‚ïž Pour vous aider Ă  comprendre ce code, les messages rĂ©cupĂ©rĂ©s par la Lambda sont dans la clĂ© Records. SQS n’envoie pas les messages Ă  la fonction Lambda, c’est la fonction qui les pull. Sauf qu’elle peut en rĂ©cupĂ©rer plusieurs Ă  la fois, et la clĂ© Records est une liste. Pour simplifier, on ne regarde que le premier message, d’oĂč le event["Records"][0]. Si vous avez envie, vous pouvez boucler sur les Ă©lĂ©ments de la liste. Ensuite, chaque message est contenu dans la clĂ© body. Les messages sont considĂ©rĂ©s comme des strings car il n’y a aucune raison que ce soit un JSON, donc il nous faut le transformer en dictionnaire avec un json.loads(). Enfin, il est possible de rĂ©cupĂ©rer les clĂ©s que l’on souhaite. Attention Ă  leur type ! Il faut spĂ©cifier que les nombres sont bien des nombres.

Pour tester votre application, vous pouvez :

  • Faire un test via l’onglet test de la fonction Lambda avec le JSON suivant :
{
  "Records": [
    {
      "messageId": "bc8007e9-6a6d-41d4-ba09-2fcf16e5e6c3",
      "receiptHandle": "AQEB92BoJQllWCtZSiiIQ69fXXX4ac7cpxxcbTirw4/b+ziBTzAxlwXFMbj3w6wbOPom4jPusM9453dZDXi4iVH/vf97fFk6yg/EkP9UZRYrK5OwfWiIxQJkklWe8ZKK84uYVhGIDi5kBfWTCnsX6u83+GE59g/UWc0+jbYvOArOLwCCOTRqbH3spkG/GhDHlyxVwPv/K+xNM+7pqQX21yjSQdiLwwlk7dDJwiNGatRq9D1vIDHduabmHn2I1sLrq778ZkZXS4YJ6IYeFXC+kWVYlSy+lXyVxHfxBVXQcU8PsSNv6MsoBDgjU1LD43NFikQLVI5F/+HnBEX2AzhoJPBMz/eijKW1miJNZ48G9gg2H2DOt0x2OQtg2M2VqtxROmD06gHUPsr67vvBH2J5m77Oxw==",
      "body": "{\n\"number1\":1,\n\"number2\":5,\n\"operation\":\"+\"\n}",
      "attributes": {
        "ApproximateReceiveCount": "18",
        "SentTimestamp": "1681393246569",
        "SenderId": "AROAZ2UVGELJYYC7FJZIV:user2476414=__tudiant_test",
        "ApproximateFirstReceiveTimestamp": "1681393246569"
      },
      "messageAttributes": {},
      "md5OfBody": "cb76cceb2fbc7622690cdf4f256ea8e0",
      "eventSource": "aws:sqs",
      "eventSourceARN": "arn:aws:sqs:us-east-1:675696485075:lab-input-queue",
      "awsRegion": "us-east-1"
    },{
      "messageId": "bc8007e9-6a6d-41d4-ba09-2fcf16e5e6c3",
      "receiptHandle": "AQEB92BoJQllWCtZSiiIQ69fXXX4ac7cpxxcbTirw4/b+ziBTzAxlwXFMbj3w6wbOPom4jPusM9453dZDXi4iVH/vf97fFk6yg/EkP9UZRYrK5OwfWiIxQJkklWe8ZKK84uYVhGIDi5kBfWTCnsX6u83+GE59g/UWc0+jbYvOArOLwCCOTRqbH3spkG/GhDHlyxVwPv/K+xNM+7pqQX21yjSQdiLwwlk7dDJwiNGatRq9D1vIDHduabmHn2I1sLrq778ZkZXS4YJ6IYeFXC+kWVYlSy+lXyVxHfxBVXQcU8PsSNv6MsoBDgjU1LD43NFikQLVI5F/+HnBEX2AzhoJPBMz/eijKW1miJNZ48G9gg2H2DOt0x2OQtg2M2VqtxROmD06gHUPsr67vvBH2J5m77Oxw==",
      "body": "{\n\"number1\":1,\n\"number2\":5,\n\"operation\":\"+\"\n}",
      "attributes": {
        "ApproximateReceiveCount": "18",
        "SentTimestamp": "1681393246569",
        "SenderId": "AROAZ2UVGELJYYC7FJZIV:user2476414=__tudiant_test",
        "ApproximateFirstReceiveTimestamp": "1681393246569"
      },
      "messageAttributes": {},
      "md5OfBody": "cb76cceb2fbc7622690cdf4f256ea8e0",
      "eventSource": "aws:sqs",
      "eventSourceARN": "arn:aws:sqs:us-east-1:675696485075:lab-input-queue",
      "awsRegion": "us-east-1"
    }
  ]
}
  • CrĂ©ez un message dans la queue d’input et voyez si le rĂ©sultat apparaĂźt dans la queue d’output. Voici un exemple de message :

    {"number1":1,"number2":5,"operation":"+"}
    

🎉 FĂ©licitations, vous venez de mettre en place une architecture 100% serverless avec trois services qui communiquent entre eux. Mettre des files entre des services permet de dĂ©coupler les services et d’avoir un systĂšme plus modulable. Par exemple, dans notre cas, notre Lambda ne sait pas d’oĂč proviennent les donnĂ©es, elle sait juste les prendre depuis une file. Ainsi, la source des donnĂ©es peut changer, du moment que la nouvelle source alimente la file SQS, il n’y aura pas de raison de changer la Lambda. De la mĂȘme maniĂšre, notre Lambda ne se prĂ©occupe pas du service qui va utiliser les donnĂ©es qu’elle produit. Elle les dĂ©pose simplement dans une file pour qu’un consommateur puisse les rĂ©cupĂ©rer. Les files SQS agissent comme des zones tampons entre les services.

S’il vous reste du temps pendant le TP, commencez le TP notĂ©.