Fonctions .NET avec compilation anticipée native - AWS Lambda

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Fonctions .NET avec compilation anticipée native

.NET 8 prend en charge la compilation native ahead-of-time (AOT). Avec la compilation anticipée native, vous pouvez compiler le code de votre fonction Lambda dans un format d’environnement d’exécution natif, ce qui élimine la nécessité de compiler le code .NET au moment de l’exécution. La compilation anticipée native peut réduire le temps de démarrage à froid des fonctions Lambda que vous écrivez en .NET. Pour plus d'informations, consultez Présentation de l'environnement d'exécution .NET 8 AWS Lambda sur le AWS Compute Blog.

Le fichier d’exécution Lambda

Pour déployer une fonction Lambda compilée avec une compilation AOT native, utilisez le runtime Lambda géré .NET 8. Ce runtime prend en charge l'utilisation des architectures x86_64 et arm64.

Lorsque vous déployez une fonction .NET Lambda sans utiliser AOT, votre application est d'abord compilée en code Intermediate Language (IL). Au moment de l'exécution, le compilateur just-in-time (JIT) du moteur d'exécution Lambda prend le code IL et le compile en code machine selon les besoins. Avec une fonction Lambda compilée à l'avance avec l'AOT natif, vous compilez votre code en code machine lorsque vous déployez votre fonction. Ainsi, vous ne dépendez pas du runtime .NET ou du SDK du runtime Lambda pour compiler votre code avant son exécution.

L'une des limites de l'AOT est que le code de votre application doit être compilé dans un environnement doté du même système d'exploitation Amazon Linux 2023 (AL2023) que celui utilisé par le moteur d'exécution .NET 8. La CLI .NET Lambda fournit des fonctionnalités permettant de compiler votre application dans un conteneur Docker à l'aide d'une image AL2023.

Pour éviter d'éventuels problèmes de compatibilité entre architectures, nous vous recommandons vivement de compiler votre code dans un environnement doté de la même architecture de processeur que celle que vous avez configurée pour votre fonction. Pour en savoir plus sur les limites de la compilation entre architectures, consultez la section Compilation croisée dans la documentation Microsoft .NET.

Prérequis

Docker

Pour utiliser l'AOT natif, votre code de fonction doit être compilé dans un environnement doté du même système d'exploitation AL2023 que le moteur d'exécution .NET 8. Les commandes .NET CLI décrites dans les sections suivantes utilisent Docker pour développer et créer des fonctions Lambda dans un environnement AL2023.

KIT DE DÉVELOPPEMENT LOGICIEL .NET 8

La compilation native AOT est une fonctionnalité de .NET 8. Vous devez installer le SDK .NET 8 sur votre machine de compilation, et pas uniquement sur le moteur d'exécution.

Amazon.Lambda.Tools

Pour créer vos fonctions Lambda, utilisez l’Amazon.Lambda.Tools extension outils globaux .NET. Pour installer Amazon.Lambda.Tools, exécutez la commande suivante :

dotnet tool install -g Amazon.Lambda.Tools

Pour plus d'informations sur l'extension Amazon.Lambda.Tools .NET CLI, consultez le référentiel AWS Extensions for .NET CLI sur GitHub.

Amazon.Lambda.Templates

Pour générer le code de votre fonction Lambda, utilisez le Amazon.Lambda.Templates NuGet package. Pour installer ce package de modèle, exécutez la commande suivante :

dotnet new install Amazon.Lambda.Templates

Premiers pas

La CLI globale .NET et le AWS Serverless Application Model (AWS SAM) fournissent tous deux des modèles de démarrage pour créer des applications utilisant l'AOT natif. Pour créer votre première fonction Lambda à l’aide de la compilation anticipée native, suivez les étapes décrites dans les instructions suivantes.

Pour initialiser et déployer une fonction Lambda compilée à l’aide de la compilation anticipée native
  1. Initialisez un nouveau projet en utilisant le modèle de la compilation anticipée native, puis naviguez dans le répertoire contenant les fichiers créés .cs et .csproj. Dans cet exemple, nous allons nommer notre fonction NativeAotSample.

    dotnet new lambda.NativeAOT -n NativeAotSample cd ./NativeAotSample/src/NativeAotSample

    Le fichier créé Function.cs par le modèle de la compilation anticipée native contient le code de fonction suivant.

    using Amazon.Lambda.Core; using Amazon.Lambda.RuntimeSupport; using Amazon.Lambda.Serialization.SystemTextJson; using System.Text.Json.Serialization; namespace NativeAotSample; public class Function { /// <summary> /// The main entry point for the Lambda function. The main function is called once during the Lambda init phase. It /// initializes the .NET Lambda runtime client passing in the function handler to invoke for each Lambda event and /// the JSON serializer to use for converting Lambda JSON format to the .NET types. /// </summary> private static async Task Main() { Func<string, ILambdaContext, string> handler = FunctionHandler; await LambdaBootstrapBuilder.Create(handler, new SourceGeneratorLambdaJsonSerializer<LambdaFunctionJsonSerializerContext>()) .Build() .RunAsync(); } /// <summary> /// A simple function that takes a string and does a ToUpper. /// /// To use this handler to respond to an AWS event, reference the appropriate package from /// https://github.com/aws/aws-lambda-dotnet#events /// and change the string input parameter to the desired event type. When the event type /// is changed, the handler type registered in the main method needs to be updated and the LambdaFunctionJsonSerializerContext /// defined below will need the JsonSerializable updated. If the return type and event type are different then the /// LambdaFunctionJsonSerializerContext must have two JsonSerializable attributes, one for each type. /// // When using Native AOT extra testing with the deployed Lambda functions is required to ensure // the libraries used in the Lambda function work correctly with Native AOT. If a runtime // error occurs about missing types or methods the most likely solution will be to remove references to trim-unsafe // code or configure trimming options. This sample defaults to partial TrimMode because currently the AWS // SDK for .NET does not support trimming. This will result in a larger executable size, and still does not // guarantee runtime trimming errors won't be hit. /// </summary> /// <param name="input"></param> /// <param name="context"></param> /// <returns></returns> public static string FunctionHandler(string input, ILambdaContext context) { return input.ToUpper(); } } /// <summary> /// This class is used to register the input event and return type for the FunctionHandler method with the System.Text.Json source generator. /// There must be a JsonSerializable attribute for each type used as the input and return type or a runtime error will occur /// from the JSON serializer unable to find the serialization information for unknown types. /// </summary> [JsonSerializable(typeof(string))] public partial class LambdaFunctionJsonSerializerContext : JsonSerializerContext { // By using this partial class derived from JsonSerializerContext, we can generate reflection free JSON Serializer code at compile time // which can deserialize our class and properties. However, we must attribute this class to tell it what types to generate serialization code for. // See https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-source-generation

    La compilation anticipée native permet de compiler votre application en un seul fichier binaire natif. Le point d’entrée de ce fichier binaire est la méthode static Main. Dans static Main, l’exécution Lambda est amorcée et la méthode FunctionHandler est configurée. Dans le cadre de l’amorçage de l’exécution, un sérialiseur généré par la source est configuré à l’aide de new SourceGeneratorLambdaJsonSerializer<LambdaFunctionJsonSerializerContext>()

  2. Pour déployer votre application sur Lambda, assurez-vous que Docker est en cours d’exécution dans votre environnement local et exécutez la commande suivante.

    dotnet lambda deploy-function

    Dans les coulisses, la CLI globale .NET télécharge une image Docker AL2023 et compile le code de votre application dans un conteneur en cours d'exécution. Le fichier binaire compilé est renvoyé vers votre système de fichiers local avant d’être déployé sur Lambda.

  3. Testez votre fonction en exécutant la commande suivante. Remplacez <FUNCTION_NAME> par le nom que vous avez choisi pour votre fonction dans l’assistant de déploiement.

    dotnet lambda invoke-function <FUNCTION_NAME> --payload "hello world"

    La réponse de la CLI comprend des détails sur les performances pour le démarrage à froid (durée d’initialisation) et la durée totale d’exécution de l’invocation de la fonction.

  4. Pour supprimer les AWS ressources que vous avez créées en suivant les étapes précédentes, exécutez la commande suivante. Remplacez <FUNCTION_NAME> par le nom que vous avez choisi pour votre fonction dans l’assistant de déploiement. En supprimant AWS les ressources que vous n'utilisez plus, vous évitez que des frais inutiles ne soient facturés à votre Compte AWS compte.

    dotnet lambda delete-function <FUNCTION_NAME>

Sérialisation

Pour déployer des fonctions sur Lambda à l’aide de la compilation anticipée native, le code de votre fonction doit utiliser la sérialisation générée par la source. Au lieu d’utiliser la réflexion au moment de l’exécution pour rassembler les métadonnées nécessaires à l’accès aux propriétés des objets pour la sérialisation, les générateurs de sources génèrent des fichiers sources C# qui sont compilés lorsque vous créez votre application. Pour configurer correctement le sérialiseur généré par la source, assurez-vous d’inclure tous les objets d’entrée et de sortie utilisés par votre fonction, ainsi que tous les types personnalisés. Par exemple, une fonction Lambda qui reçoit des événements d’API Gateway pour une API REST et renvoie un type de Product personnalisé inclurait un sérialiseur défini comme suit.

[JsonSerializable(typeof(APIGatewayProxyRequest))] [JsonSerializable(typeof(APIGatewayProxyResponse))] [JsonSerializable(typeof(Product))] public partial class CustomSerializer : JsonSerializerContext { }

Réduction

La compilation anticipée native permet de réduire le code de votre application dans le cadre de la compilation afin de s’assurer que le fichier binaire est aussi petit que possible. .NET 8 pour Lambda offre une meilleure prise en charge du découpage par rapport aux versions précédentes de .NET. Support a été ajouté aux bibliothèques d'exécution Lambda, au SDK AWS .NET, aux annotations .NET Lambda et au .NET 8 lui-même.

Ces améliorations offrent la possibilité d'éliminer les avertissements de découpage au moment de la création, mais .NET ne sera jamais totalement sûr en matière de découpage. Cela signifie que certaines parties des bibliothèques sur lesquelles votre fonction repose peuvent être supprimées lors de l’étape de compilation. Vous pouvez gérer cela en le définissant dans TrimmerRootAssemblies le cadre de votre .csproj fichier, comme indiqué dans l'exemple suivant.

<ItemGroup> <TrimmerRootAssembly Include="AWSSDK.Core" /> <TrimmerRootAssembly Include="AWSXRayRecorder.Core" /> <TrimmerRootAssembly Include="AWSXRayRecorder.Handlers.AwsSdk" /> <TrimmerRootAssembly Include="Amazon.Lambda.APIGatewayEvents" /> <TrimmerRootAssembly Include="bootstrap" /> <TrimmerRootAssembly Include="Shared" /> </ItemGroup>

Notez que lorsque vous recevez un avertissement de découpage, l'ajout de la classe qui génère l'avertissement TrimmerRootAssembly risque de ne pas résoudre le problème. Un avertissement de découpage indique que la classe essaie d'accéder à une autre classe qui ne peut être déterminée avant l'exécution. Pour éviter les erreurs d'exécution, ajoutez cette deuxième classe àTrimmerRootAssembly.

Pour en savoir plus sur la gestion des avertissements de découpage, voir Présentation des avertissements de découpage dans la documentation Microsoft .NET.

Résolution des problèmes

Error: Cross-OS native compilation is not supported. (Erreur : la compilation native entre systèmes d’exploitation n’est pas prise en charge).

Votre version de l’outil global .NET Core Amazon.Lambda.Tools n’est pas à jour. Mettez à jour vers la dernière version et réessayez.

Docker : l’image du système d’exploitation « linux » ne peut pas être utilisée sur cette plateforme.

Docker sur votre système est configuré pour utiliser des conteneurs Windows. Passez aux conteneurs Linux pour exécuter l’environnement de création anticipée native.

Pour plus d'informations sur les erreurs courantes, consultez le référentiel AWS NativeAOT pour .NET sur. GitHub