Accueil Nos publications Blog Support de .NetCore dans AWS Lambda

Support de .NetCore dans AWS Lambda

Amazon a annoncé le 1er décembre 2016, lors de sa conférence re:Invent 2016, l’intégration du framework .NetCore à l’un de ses services : AWS Lambda. L’objectif de cet article est de faire une introduction à ce service fourni par AWS, à quoi sert-il, et dans quelle mesure peut-il nous être utile. Ensuite, nous mettrons en place notre environnement pour développer des fonctions en C# et les envoyer sur le cloud. Enfin pour finir, je vous montrerais comment porter facilement vos applications ASP.Net WebApi sur AWS Lambda sans effectuer de grosses modifications de code.

AWS Lambda, c’est quoi ?

AWS Lambda est un service permettant d’effectuer des opérations sans posséder de serveur. En effet, notre code est exécuté lorsqu’un évènement est levé, et AWS gère automatiquement l’allocation des ressources pour effectuer l’opération. Pour faire simple, il suffit de coder une fonction, de l’envoyer à AWS Lambda, et nous pourrons appeler ce bout de code autant de fois que nous le voulons. AWS dimensionne automatiquement ses serveurs pour nous permettre d’exécuter notre bout de code autant de fois que nous le souhaitons (allant de quelques requêtes par jour à plusieurs milliers par seconde).

Étant donné que le bout de code envoyé sur AWS est réparti dans plusieurs zones géographiques, AWS nous garantit une disponibilité permanente de nos fonctions. De plus, nous avons la possibilité de gérer les droits, les logs, et bien d’autres informations directement depuis le panel d’administration AWS ou en ligne de commande.

AWS Lambda permet, si vous le souhaitez, d’interagir avec d’autres éléments AWS et peut être appelé par un évènement levé par un autre produit AWS. Par exemple, nous pouvons lever un évènement et appeler une fonction lorsqu’un fichier arrive dans un bucket S3 pour incrémenter un compteur dans une table DynamoDB (ou dans une base de données au sein de nos data-centers).

Du côté de la facturation, nous ne payons que lorsque les fonctions sont appelées. Deux facteurs sont à prendre en compte : la mémoire allouée à la fonction et la durée d’exécution. Le site officiel fournit plusieurs simulations de facturation, je vous invite à aller y faire un tour pour vous faire une idée du coût.

Avec le compte gratuit, nous pouvons lancer 1 000 000 requêtes gratuites par mois. Cela sera largement suffisant pour effectuer tous nos tests !

Mise en place de l’environnement

Pour tester AWS Lambda, il va falloir configurer notre environnement. Nous allons utiliser le SDK pour interagir avec AWS. La liste des éléments à télécharger et installer est la suivante :

Le toolkit AWS va nous permettre d’interagir avec AWS directement depuis Visual Studio. En effet, nous pouvons effectuer un grand nombre d’opérations directement depuis le toolkit sans avoir à nous connecter au panel d’administration web. Pour ce faire, il nous faut créer un compte sur AWS et lui assigner des droits afin de l’utiliser avec le SDK.

Connectons-nous maintenant au compte AWS, que vous pouvez créer gratuitement si vous ne l’avez pas encore fait.

Une fois connectés, nous souhaitons accéder au service appelé “Identity and Access Management”, ou plus simplement “IAM”. Nous avons besoin de créer un utilisateur pour Visual Studio et un rôle pour nos fonctions.

Cela se passe donc dans les sous-menus suivants:
aws_iam

Dans la création de l’utilisateur, nous avons besoin d’un ID d’accès et d’une clé secrète. Nous allons donc cocher la case “Programmatic access”. Notre utilisateur ne sera jamais utilisé pour se connecter à la console AWS. Concernant les droits, pour cet article, nous allons lui donner « AWSLambdaFullAccess » et “AdministratorAccess”. Voici un résumé des opérations à effectuer :
aws_iam_final

Une fois l’utilisateur créé, pensez à copier/coller les valeurs des deux champs suivants pour les mettre plus tard dans Visual Studio :

  • Access Key ID
  • Secret access key

Pour la création du rôle, que je vais appeler “LambdaRole”, nous allons aussi lui donner le droit “AWSLambdaFullAccess” accessible depuis le sous-menu “AWS Lambda”. Une fois le rôle créé, mettez de côté son ID qui nous sera utile plus tard. L’id est du type “arn:aws:iam::666666666666:role/LambdaRole”. Vous pouvez fermer la console AWS car nous n’en auront plus besoin.

Dans Visual Studio, vous avez normalement un nouvel onglet appelé “AWS Explorer”. Si vous ne l’avez pas, vous pouvez facilement le retrouver depuis le menu “View”. Pour ajouter l’utilisateur que nous avons créé, il suffit de cliquer sur le bouton “New Account Profile” (1) puis de renseigner les deux clés sauvegardées précédemment (2 et 3) :
aws_vs_1

Création d’une fonction simple

Pour tester notre configuration, nous allons installer une fonction simple : une méthode “Hello World” dans AWS Lambda.

Pour ce faire, dans Visual Studio, créez un nouveau projet de type “AWS Lambda Project” :
aws_vs_2

Dans l’écran suivant, nous utiliserons une “empty function” pour faire au plus simple. En effet, les autres projets utilisent d’autres composants AWS. Une fois la solution créée, si vous rencontrez un problème lors de la restauration des dépendances, il vous suffit de fermer Visual Studio et de le relancer.

Vous avez donc tous normalement une arborescence de projet comme suit :
aws_vs_3

La classe “Function” (1) vous permet d’écrire le code de votre fonction. Elle contient déjà une fonction de test appelée “FunctionHandler” qui transforme une chaine de caractères en son équivalent en majuscule.

Le fichier “aws-lambda-tools-defaults.json” (2) permet de définir la configuration de la publication sur AWS. Ce fichier peut être renseigné directement en entrant les valeurs, ou il sera automatiquement rempli lors de notre première publication.

Dans la classe “Function”, la méthode déjà présente possède deux paramètres :

  • string input
  • ILambdaContext context

La première variable est utilisée pour récupérer le contenu passé en paramètre de l’appel à la méthode. Il s’agit majoritairement d’un objet Json contenant des informations. Il peut aussi s’agir d’un texte plein. La seconde variable est le contexte d’exécution de la lambda. Cela permet d’effectuer plusieurs opérations par exemple, écrire des logs dans la console AWS.

J’ai donc ajouté la fonction suivante dans cette classe :


public string HelloWorld(string input, ILambdaContext context)
{
    context.Logger.LogLine(string.Format("Input value : {0}", input));
    return string.Format("Hello {0}", input);
}

Envoyons maintenant ce code sur AWS Lambda pour le tester. Pour ce faire, faîtes un clic droit sur le projet et cliquez sur le bouton “Publish to AWS Lambda…”. Cela va ouvrir une fenêtre permettant de configurer la publication :
aws_vs_4

Si vous avez bien ajouté l’utilisateur dans la partie précédente, il est affiché dans la partie 1. Vous pouvez sélectionner une région sur laquelle envoyer la fonction (2). Il faut aussi donner un nom à cette fonction (3). Et enfin, il faut spécifier à AWS quelle fonction lier à cette lambda (4). Pour cela, il faut renseigner l’assembly, le nom de la classe (avec le namespace) et le nom de la méthode.

L’écran suivant vous permet de donner les permissions à notre fonction. Nous allons donc lui associer le rôle créé précédemment “LambdaRole”.

Lorsque vous cliquez sur “Upload” la fonction est créée dans votre compte AWS. L’opération peut durer quelques secondes et vous amène sur une page de test :
aws_vs_5

En entrant le texte de votre choix dans le champ texte (1) et en cliquant sur le bouton “Invoke” (2), la fonction est exécutée sur le cloud et le résultat est retourné (3). Nous pouvons aussi constater l’affichage du log que nous avons défini en utilisant notre contexte (4). Le premier lancement va prendre un peu de temps, car AWS crée l’ensemble les ressources nécessaires. Le second lancement est instantané.

Application ASP.Net Core WebApi

L’exemple précédent était assez simple, mais il a permis de valider la configuration de l’environnement de développement, du compte et du rôle créé. Nous allons maintenant déployer un webservice WebApi dans le cloud de la même manière. Si vous avez déjà une solution que vous souhaitez utiliser, vous pouvez l’ouvrir. Dans le cas contraire, prenez comme moi le projet par défaut lorsque vous créez une application WebApi.

Pour rappel, il suffit dans Visual Studio de créer un nouveau projet de type .Net Core et de choisir le template “Web API” dans le menu de création :
aws_api_1

Pour porter notre application dans le cloud avec AWS Lambda, nous n’avons pas à toucher aux classes ou à la logique de notre application. Nous n’avons que deux opérations à effectuer :

  • Configurer le hostBuilder
  • Configurer les routes et redirections sur AWS

Nous allons voir cela en détail. Dans un premier temps, ouvrez votre fichier “project.json” pour ajouter les références suivantes :
aws_api_2

“Lambda.AspNetCoreServer” va permettre à AWS de formater le projet pour être utilisé sur le cloud et “Lambda.Tools” nous permet d’ajouter l’option de publication depuis Visual Studio. C’est pour cela qu’elle est uniquement visible lors d’un “build”. Lorsque vous sauvegardez vos modifications, les nouveaux paquets sont automatiquement téléchargés.

Si vous ouvrez le fichier “Program.cs” de votre solution, vous verrez la création de l’host utilisant IIS et Kestrel dans tous les projets .NetCore :
aws_api_3

Nous allons devoir créer un autre point d’entrée pour AWS Lambda. Pour ce faire, nous créons une classe que j’ai choisi d’appeler “LambdaHost”. Cette classe hérite de Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction et définit une méthode à implémenter : “Init(IWebHostBuilder builder)”.

Le code à mettre est le suivant :


public class LambdaHost : Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction
{
protected override void Init(IWebHostBuilder builder)
{
builder.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>
.UseApiGateway();
}
}

Lorsque nous allons déployer notre application sur AWS Lambda, nous le lierons à cette classe. Cela permettra à AWS de savoir comment lancer l’application web.

La seconde opération consiste à créer un fichier template pour le déploiement. Pour cela, effectuez un clic droit sur le projet, “Add”, “AWS Serverless Template”. Cela va créer un fichier “serverless.template” dans le projet. Il s’agit d’un template CloudFormation permettant de créer l’ensemble des composants nécessaires pour lancer l’application. En effet, il est obligatoire d’avoir un bucket S3 pour stocker les sources de l’application permettant la création des services lors du premier appel par exemple.

Nous allons effectuer quelques modifications dans le fichier :

  1. La propriété “Handler” doit être définie. Comme précédemment, il s’agit de la référence à l’assembly, la classe (avec le namespace) et la fonction “FunctionHandlerAsync” (qui fait partie de la classe “APIGatewayProxyFunction” dont notre classe hérite). Ici, pour ma part, la valeur est la suivante : CloudWebApi::CloudWebApi.LambdaHost::FunctionHandlerAsync
  2. Dans le rôle, nous allons lui donner l’id du rôle “LambdaRole” créé au début de l’article.
  3. Supprimer la ligne “Policies”. En effet, cela permet de créer un rôle à la volée et de lui donner des droits. Dans notre cas, le rôle existe déjà.

La capture suivante montre le fichier de configuration :
aws_api_4

Il s’avère que AWS utilise un service appelé API Gateway pour gérer les redirections d’URL d’appels vers la bonne lambda fonction.

Nous sommes prêts à déployer l’application dans AWS. Comme précédemment, faîtes un clic droit sur le projet et cliquez sur “Publish to AWS Lambda …”. La fenêtre suivante s’ouvre :
aws_api_5

Il nous faut spécifier un nom (1), et un bucket S3 pour stocker les sources. Si vous n’en possédez pas, il suffit de cliquer sur “New” (2) et d’en créer un nouveau. Lorsque vous cliquez sur “Publish”, les différents éléments nécessaires sont créés et une page s’ouvre dans Visual Studio affichant les différentes opérations en cours. Au bout d’une minute environ, vous devriez avoir l’affichage suivant :
aws_api_6

L’URL est l’endpoint de votre application WebApi. Si nous ouvrons maintenant Postman pour effectuer une requête vers cette adresse, nous pouvons accéder à nos classes et nos méthodes.

Si, comme moi, vous avez créé un projet vide, vous aurez accès à la classe “Values” qui affiche des données de test en ajoutant “/api/values” à la fin de l’adresse.

Voici le rendu que vous aurez sous Postman :
aws_api_7

Conclusion

Nous avons donc testé l’outil AWS Lambda, qui permet d’envoyer du code sur le cloud et de le scaller pour l’exécuter aussi souvent que nous le voulons. Il y a peu de modifications à apporter pour porter vos webservices sur AWS, les classes et la logique métier n’ayant pas à être modifiées. Pour simplifier la présentation, j’ai volontairement ignoré tous les aspects d’authentification et d’autorisation au sein des applications ASP.Net Core WebApi, qui sont bien entendu gérés par AWS.

L’article parle aussi implicitement d’applications sans serveur, appelé « Serverless Applications ». Si ce concept vous intéresse, vous trouverez plus d’information sur le site du framework ServerLess et sur la page AWS prévue à cet effet.

© SOAT
Toute reproduction interdite sans autorisation de la société SOAT