モジュール 3: AWS Lambda での .NET
学習モジュール
ここで紹介した例を参考にしてもかまいませんが、その必要はありません。
AWS Lambda は、x86_64 アーキテクチャと Arm64 (Graviton2) アーキテクチャの両方で、複数の .NET バージョンをサポートしているため、お好きなアーキテクチャを自由に選択できます。コードとデプロイプロセスは変わりません。
Lambda はサーバーレスサービスであるため、お支払いいただくのは使用した分のみです。Lambda 関数を 1 日に数回実行する必要がある場合は、それだけで済みます。ただし、ニーズに合わせて拡張でき、同時に 1,000 個のインスタンスを起動できるからです。
所要時間
60 分
料金
前述のように、お支払いいただくのは使用した分のみです。お支払い金額は、Lambda 関数が実行された時間の長さ (ミリ秒単位に切り上げた値) と、関数に割り当てたメモリ量に基づいて計算されます。
価格計算に使用されるのは割り当てられたメモリの量であり、呼び出し中に使用された量ではないことに注意してください。そのため、関数をテストして、呼び出し時に使用する最大メモリ量を評価するのはやりがいのある作業です。割り当てられたメモリを必要最低限に抑えることで、Lambda 関数の使用コストを削減できます。詳細については、このページの AWS Lambda 料金表を参照してください。
Lambda 関数が S3、Kinesis などの他のサービスを使用している場合、それらのサービスにも料金が発生する可能性があることに注意してください。
サポートされている .NET のバージョン
Lambda プラットフォームで .NET バイナリを実行するにはさまざまな方法があります。最も一般的で最初に検討すべきことは、AWS が提供するマネージドランタイムを使用することです。これは最も簡単に始める方法であり、最も便利で、最高のパフォーマンスを提供します。マネージドランタイムを使用したくない、または使用できない場合は、他に 2 つの選択肢があります。カスタムランタイムとコンテナイメージです。どちらのオプションにもそれぞれ長所と短所があり、以下で詳しく説明します。
マネージドランタイム
AWS Lambda サービスには、コードを実行するためのさまざまな一般的なランタイムが用意されています。.NET ランタイムに関しては、AWS はランタイムを最新の状態に保ち、必要に応じて Microsoft から入手できる最新バージョンでパッチを適用します。開発者は、使い慣れた .csproj ファイルで使用したいバージョンを指定する以外に、コードが使用するランタイムの管理に関して何もする必要はありません。
現時点で、AWS が提供しているマネージドランタイムは、長期サポート (LTS) バージョンの .NET ランタイム (.NET 3.1 と .NET 6) のみです。.NET マネージドランタイムは x86_64 アーキテクチャと arm64 アーキテクチャの両方で使用でき、Amazon Linux 2 で実行できます。AWS が提供しているバージョン以外のバージョンの .NET を使用する場合は、独自のカスタムランタイムを構築するか、ニーズに合ったコンテナイメージを作成できます。
.NET の世界から飛び出すことに興味があるなら、Lambda サービスが Node.js、Python、Ruby、Java、Go といった他の言語でもマネージドランタイムを提供していることを知っておくとよいでしょう。マネージドランタイムとサポートされている言語のバージョンのリストの詳細については、利用可能なランタイムに関するこのページを参照してください。
カスタムランタイム
カスタムランタイムは、自分でビルドしてバンドルするランタイムです。これを行う理由はいくつかあります。最も一般的なのは、Lambda サービスによってマネージドランタイムとして提供されていないバージョン .NET を使用したい場合です。あまり一般的ではないもう 1 つの理由は、ランタイムのマイナーバージョンとパッチバージョンを正確に制御したい場合です。
カスタムランタイムの作成には、ほとんど手間がかかりません。あなたがしなければならないのは合格することだけです:
--ビルドコマンドに忠実な自己完結型。
これは dotnet ビルドで直接行うことができます。また、aws-lambda-tools-defaults.json ファイルを使用して次のパラメータを指定して実行することもできます。
「msbuild-parameters」:「--self-contained true」
あとは、.NET Lambda 関数をバンドルするときの単純なコンパイラフラグだけです。これで、デプロイするパッケージには、コードと、選択した.NET ランタイムの必要なファイルが含まれます。
これで、必要に応じてランタイムにパッチを適用して更新するかどうかは、あなた次第です。ランタイムを更新するには、関数コードとランタイムが一緒にパッケージ化されているため、関数を再デプロイする必要があります。
デプロイされるパッケージには、必要なランタイムファイルがすべて含まれているため、マネージドランタイムに比べて大幅に大きくなります。これはコールドスタート時間に悪影響を及ぼします(これについては後で詳しく説明します)。このサイズを減らすには、.NET コンパイル機能の [トリミング] と ReadyToRun の使用を検討してください。ただし、その前にこれらの機能に関するドキュメントをお読みください。
Linux 上で動作する任意のバージョンの .NET でカスタムランタイムを作成できます。一般的な使用例は、「最新の」バージョンまたは .NET プレビューバージョンで関数をデプロイすることです。
カスタムランタイムを使用する場合、コミュニティが提供する非常に幅広い言語を使用できます。あるいは、他の人が Erlang や COBOL のような言語を実行するために行っているように、独自のカスタムランタイムを構築することもできます。
ツールとコンテナイメージ
マネージドランタイムとカスタムランタイムに加えて、AWS Lambda サービスでは、コードをコンテナイメージにパッケージ化し、そのイメージを Lambda サービスにデプロイすることもできます。このオプションは、コードの構築とコンテナへのデプロイに時間を費やしたチームや、コードが実行されるオペレーティングシステムと環境をより細かく制御する必要があるチームに適しています。最大 10 GB のサイズの画像がサポートされます。
AWS には、.NET と .NET Core 用にさまざまなベースイメージが用意されています。https://gallery.ecr.aws/lambda/dotnet、これらを使用するとすぐに使い始めることができます。
もう 1 つのオプションは、関数専用のカスタムイメージを作成することです。これはより高度なユースケースであり、ニーズに合わせて Dockerfile を編集する必要があります。このアプローチはこのコースでは取り上げませんが、その道を進む場合は、このリポジトリにある Dockerfiles (https://github.com/aws/aws-lambda-dotnet/tree/master/LambdaRuntimeDockerfiles/Images) を見てください。
Lambda 関数の更新は、アップロードのサイズが大きいため、コンテナを使用すると最も時間がかかることに注意してください。また、コンテナは 3 つのオプションの中でコールドスタートが最も悪いです。これについては、モジュールの後半で詳しく説明します。
自分に合ったランタイムの選択
最高の起動パフォーマンス、デプロイのしやすさ、使い始めやすさが必要で、LTS バージョンの .NET を使い続けたいなら、マネージド .NET ランタイムを使用してください。
コンテナイメージは、AWS がさまざまな .NET バージョン用に作成したイメージを使用できる優れたオプションです。または、独自のコンテナイメージを選択して、コードが実行されるオペレーティングシステムと環境を微調整することもできます。コンテナイメージは、すでにコンテナを幅広く使用している組織にも適しています。
.NET とそのランタイムライブラリのバージョンに関する特定の要件があり、それらを自分で制御したい場合は、カスタムランタイムの使用を検討してください。ただし、ランタイムのメンテナンスとパッチはユーザー次第であることに注意してください。Microsoft がセキュリティ更新プログラムをリリースした場合は、それを認識し、カスタムランタイムを適切に更新する必要があります。パフォーマンスの観点から見ると、カスタムランタイムは 3 つのうち起動が最も遅くなります。
Lambda 関数が起動すると、マネージドランタイム、コンテナイメージ、カスタムランタイムのパフォーマンスはほぼ同じになります。
AWS SDK for .NET
AWS サービスを使用する .NET アプリケーションを開発している場合は、おそらく AWS SDK for .NET を使用したことがあるでしょう。SDK により、.NET 開発者は一貫性のある使い慣れた方法で AWS サービスを簡単に呼び出すことができます。SDK は、サービスがリリースされたり、更新されたりしても、常に最新の状態に保たれます。SDK は NuGet からダウンロードできます。
AWS に関連する多くのものと同様に、SDK は小さなパッケージに分割され、それぞれが単一のサービスを扱います。
たとえば、.NET アプリケーションから S3 バケットにアクセスする場合は、AWSSDK.S3 NuGet パッケージを使用します。または、.NET アプリケーションから DynamoDB にアクセスしたい場合は、AWSSDK.DynamoDBv2 NuGet パッケージを使用してください。
ただし、追加するのは必要な NuGet パッケージだけです。SDK を小さなパッケージに分割することで、独自のデプロイパッケージを小さく保つことができます。
Lambda 関数ハンドラーが他の AWS サービスからイベントを受信する必要がある場合は、特定のイベント関連の NuGet パッケージを探してください。これらには、イベントを処理するための関連タイプが含まれています。パッケージは AWSSDK.Lambda の命名パターンに従っています。[SERVICE] イベント。
たとえば、Lambda 関数が-によってトリガーされたとします。
受信する S3 イベントについては、AWSSDK.lambda.S3Events パッケージを使用してください
受信する Kinesis イベントについては、AWSSDK.lambda.KinesisEvents パッケージを使用してください
受信 SNS 通知については、AWSSDK.Lambda.SNSEvents パッケージを使用してください
受信する SQS メッセージについては、AWSSDK.lambda.SQSEvents パッケージを使用してください
SDK を使用して AWS サービスとやり取りするのはとても簡単です。プロジェクトに NuGet パッケージへの参照を追加し、他の.NET ライブラリを使用する場合と同様にサービスを呼び出します。
Lambda 関数から SDK を使用していても、その使用方法には影響しません。
AWS SDK NuGet パッケージをプロジェクトに追加する場合、必ずしもが必要ではないことに注意してください。たとえば、Lambda 関数が AWS RDS SQL サーバーを呼び出す場合、エンティティフレームワークを使用するだけでデータベースにアクセスできます。AWS 固有のライブラリを追加する必要はありません。ただし、シークレットマネージャーからデータベースのユーザー名/パスワードを取得する場合は、AWSSDK.SecretsManager NuGet パッケージを追加する必要があります。
権限に関するメモ
一般的なルールとして、タスクの実行に必要な最低レベルの権限を使用してください。 このコース全体を通して、皆さんは励まされ、その方法が示されます。
ただし、このコースを簡単に教えるために、AdministratorAccess ポリシーが添付された AWS ユーザーを使用することをお勧めします。このポリシーにより、Lambda 関数をデプロイするときに必要なロールを作成できます。コースに取り組んでいないときは、このポリシーを AWS ユーザーから削除する必要があります。
ハローワールドスタイルの .NET Lambda 関数
前のモジュールで説明したように、.NET Lambda 関数の作成、デプロイ、呼び出しは非常に簡単です。このセクションでは、同じことを少しゆっくり行い、各ステップで何が起こっているかを説明します。生成されたコードと構成ファイルについて説明します。
ファンクションの作成
これを実行するには、必要なツールをインストールする必要があります。その方法の詳細については、モジュール 3 を参照してください。
今すぐそこに行きたくない場合は、ここに簡単なリマインダーがあります。
.NET Lambda 関数テンプレートをインストールします。
dotnet new -i Amazon.Lambda.Templates
Lambda 関数をデプロイして管理するための .NET ツールをインストールします。
dotnet tool install -g Amazon.Lambda.Tools
テンプレートがインストールされたので、新しい関数を作成できます。
コマンドラインから以下を実行します。
dotnet new lambda.EmptyFunction -n HelloEmptyFunction
これにより、HelloEmptyFunction という名前の新しいディレクトリが作成されます。その中にはさらに 2 つのディレクトリ、src と test があります。名前が示すように、src ディレクトリには関数のコードが格納され、test ディレクトリには関数の単体テストが含まれます。これらのディレクトリに移動すると、それぞれに別のディレクトリが含まれていることがわかります。これらのサブディレクトリ内には、関数のコードファイルとユニットテストファイルがあります。
HelloEmptyFunction
├───src
│ └───HelloEmptyFunction
│ aws-lambda-tools-defaults.json // The default configuration file
│ Function.cs // The code for the function
│ HelloEmptyFunction.csproj // Standard C# project file
│ Readme.md // A readme file
│
└───test
└───HelloEmptyFunction.Tests
FunctionTest.cs // The unit tests for the function
HelloEmptyFunction.Tests.csproj // Standard C# project file
まず、Function.cs ファイルを見てみましょう。
using Amazon.Lambda.Core;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace HelloEmptyFunction;
public class Function
{
/// <summary>
/// A simple function that takes a string and does a ToUpper
/// </summary>
/// <param name="input"></param>
/// <param name="context"></param>
/// <returns></returns>
public string FunctionHandler(string input, ILambdaContext context)
{
return input.ToUpper();
}
}
少し説明が必要な行に関する注意事項:
4 行目では、JSON 入力を .NET クラスに変換できます。
17 行目では、関数への JSON 入力が文字列に変換されます。
17 行目では、ILambdaContext オブジェクトがパラメータとして渡されます。このオブジェクトは、ロギング、関数名、関数の実行時間などの情報に使用できます。
ご覧のとおり、コードは非常にシンプルで、C# を使ったことのある人なら誰でも知っているはずです。
ここで説明する FunctionHandler メソッドは同期型ですが、Lambda 関数は他の.NET メソッドと同様に非同期でもかまいません。必要なのは、FunctionHandler を次のように変更することだけです。
パブリック async Task<string>FunctionHandler (..)
それでは、aws-lambda-tools-defaults.json ファイルを見てみましょう。
{
"Information": [
"This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
"To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
"dotnet lambda help",
"All the command line options for the Lambda command can be specified in this file."
],
"profile": "",
"region": "",
"configuration": "Release",
"function-runtime": "dotnet6",
"function-memory-size": 256,
"function-timeout": 30,
"function-handler": "HelloEmptyFunction::HelloEmptyFunction.Function::FunctionHandler"
}
10 行目では、関数をリリース構成で組み込む必要があると明記しています。
11 行目では、使用するランタイムを Lambda サービスに指定します。
12 行目では、関数に割り当てるメモリの量 (この場合は 256 MB) を指定しています。
13 行目では、関数のタイムアウトを指定します。この場合は 30 秒です。最大許容タイムアウトは 15 分です。
14 行目では、関数ハンドラーを指定します。これは、この関数が呼び出されたときに Lambda サービスによって呼び出されるメソッドです。
関数ハンドラーは次の 3 つの部分で構成されています。
「アセンブリ名:: 名前空間。クラス名:: メソッド名」
少し後に、このファイルの設定を使用してこの関数を構築し、AWS Lambda サービスにデプロイします。
でもまず、テストプロジェクトとその HelloEmptyFunction.Tests.cs ファイルを見てみましょう:
using Xunit;
using Amazon.Lambda.Core;
using Amazon.Lambda.TestUtilities;
namespace HelloEmptyFunction.Tests;
public class FunctionTest
{
[Fact]
public void TestToUpperFunction()
{
// Invoke the lambda function and confirm the string was upper cased.
var function = new Function();
var context = new TestLambdaContext();
var upperCase = function.FunctionHandler("hello world", context);
Assert.Equal("HELLO WORLD", upperCase);
}
}
ここのコードは比較的単純で、xUnit テストフレームワークを使用しています。他のメソッドをテストするのと同じように Lambda 関数をテストできます。
14 行目では、Function クラスの新しいインスタンスを作成します。
15 行目では、TestLambdaContext クラスの新しいインスタンスを作成します。このインスタンスは、次の行で Lambda 関数に渡されます。
16 行目では、関数の FunctionHandler メソッドを呼び出し、文字列「hello world」とコンテキストを渡しています。レスポンスは upperCase 変数に格納されます。
18 行目では、upperCase 変数が「HELLO WORLD」と等しいことをアサートしています。
このテストは、コマンドラインまたはお使いの IDE 内で実行できます。Lambda 関数で実行できるテストは他にもあります。これについて詳しく知りたい場合は、後のモジュールで Lambda 関数をテストおよびデバッグするさまざまな方法について学習してください。
関数のデプロイ
これで Lambda 関数が完成し、ユニットテストを実行したかもしれません。今度は、Lambda 関数を AWS Lambda サービスにデプロイします。
コマンドラインから、HelloEmptyFunction.csproj ファイルが含まれているディレクトリに移動し、次のコマンドを実行します。
dotnet lambda deploy-function HelloEmptyFunction
以下を含む出力が表示されます(わかりやすくするために省略しています)-
... dotnet publish --output "C:\dev\Lambda_Course_Samples\HelloEmptyFunction\src\HelloEmptyFunction\bin\Release\net6.0\publish" --configuration "Release" --framework "net6.0" /p:GenerateRuntimeConfigurationFiles=true --runtime linux-x64 --self-contained false
Zipping publish folder C:\dev\Lambda_Course_Samples\HelloEmptyFunction\src\HelloEmptyFunction\bin\Release\net6.0\publish to C:\dev\Lambda_Course_Samples\HelloEmptyFunction\src\HelloEmptyFunction\bin\Release\net6.0\HelloEmptyFunction.zip
... zipping: Amazon.Lambda.Core.dll
... zipping: Amazon.Lambda.Serialization.SystemTextJson.dll
... zipping: HelloEmptyFunction.deps.json
... zipping: HelloEmptyFunction.dll
... zipping: HelloEmptyFunction.pdb
... zipping: HelloEmptyFunction.runtimeconfig.json
Created publish archive (C:\dev\Lambda_Course_Samples\HelloEmptyFunction\src\HelloEmptyFunction\bin\Release\net6.0\HelloEmptyFunction.zip).
1 行目は、プロジェクトをコンパイルして公開します。ランタイムは linux-x64 で、自己完結型フラグは false であることに注意してください (つまり、この関数はカスタムランタイムではなく、Lambda サービス上のマネージド.NET ランタイムを使用します)。
2 行目では、公開されたプロジェクトを zip ファイルに圧縮します。
3 行目から 8 行目には、圧縮されているファイルが表示されます。
9 行目では、zip ファイルが作成されたことを確認します。
次に、「コードに AWS 認証情報を提供する IAM ロールを選択してください」という質問が表示され、以前に作成したロールのリストが表示される場合がありますが、リストの一番下に「*** Create new IAM Role ***」というオプションがあり、そのオプションの横にその番号を入力します。
「新しい IAM ロールの名前を入力してください:」と表示されます。「HelloEmptyFunctionRole」と入力します。
次に、「新しいロールにアタッチして権限を付与する IAM ポリシーを選択」するように求められ、ポリシーのリストが表示されます。以下のリストのように見えますが、あなたのものはもっと長いかもしれません-
1) AWSLambdaReplicator (Grants Lambda Replicator necessary permissions to replicate functions ...)
2) AWSLambdaDynamoDBExecutionRole (Provides list and read access to DynamoDB streams and writ ...)
3) AWSLambdaExecute (Provides Put, Get access to S3 and full access to CloudWatch Logs.)
4) AWSLambdaSQSQueueExecutionRole (Provides receive message, delete message, and read attribu ...)
5) AWSLambdaKinesisExecutionRole (Provides list and read access to Kinesis streams and write ...)
6) AWSLambdaBasicExecutionRole (Provides write permissions to CloudWatch Logs.)
7) AWSLambdaInvocation-DynamoDB (Provides read access to DynamoDB Streams.)
8) AWSLambdaVPCAccessExecutionRole (Provides minimum permissions for a Lambda function to exe ...)
9) AWSLambdaRole (Default policy for AWS Lambda service role.)
10) AWSLambdaENIManagementAccess (Provides minimum permissions for a Lambda function to manage ...)
11) AWSLambdaMSKExecutionRole (Provides permissions required to access MSK Cluster within a VP ...)
12) AWSLambda_ReadOnlyAccess (Grants read-only access to AWS Lambda service, AWS Lambda consol ...)
13) AWSLambda_FullAccess (Grants full access to AWS Lambda service, AWS Lambda console feature ...)
「AWSLambdaBasicExecutionRole」を選択して下さい。私のリストの6番目です。
しばらくすると、次のようになります-
Waiting for new IAM Role to propagate to AWS regions
............... Done
New Lambda function created
これで、関数を呼び出すことができます。
関数を呼び出しています
コマンドライン:
dotnet lambda ツールを使用して、任意のシェルから関数を呼び出すことができます。
dotnet lambda invoke-function HelloEmptyFunction --payload "Invoking a Lambda function"
上記のような単純な Lambda 関数の場合、エスケープする JSON はありませんが、逆シリアル化する必要がある JSON を渡す場合、ペイロードのエスケープは使用しているシェルによって異なります。
次のような出力が表示されます。
Amazon Lambda Tools for .NET Core applications (5.4.1)
Project Home: https://github.com/aws/aws-extensions-for-dotnet-cli, https://github.com/aws/aws-lambda-dotnet
Payload:
"INVOKING A LAMBDA FUNCTION"
Log Tail:
START RequestId: 3d43c8be-8eca-48a1-9e51-96d9c84947b2 Version: $LATEST
END RequestId: 3d43c8be-8eca-48a1-9e51-96d9c84947b2
REPORT RequestId: 3d43c8be-8eca-48a1-9e51-96d9c84947b2 Duration: 244.83 ms Billed Duration: 245 ms
Memory Size: 256 MB Max Memory Used: 68 MB Init Duration: 314.32 ms
出力「ペイロード:」は Lambda 関数からのレスポンスです。
ログテールには、実行時間やメモリ使用量など、Lambda 関数の呼び出しに関する有用な情報が含まれていることに注意してください。このような単純な関数の場合、244.83 ミリ秒は長いように思えるかもしれませんが、関数が呼び出されたのはこれが初めてでした。つまり、より多くの作業を実行する必要があり、その後の呼び出しの方が速かったでしょう。詳細については、コールドスタートのセクションを参照してください。
コードを少し変更して、独自のログステートメントをいくつか追加してみましょう。
FunctionHandler メソッドの return ステートメントの上に以下を追加します。
context.Logger.LogInformation("Input: " + input);
以下を使用して再度デプロイします。
dotnet lambda deploy-function HelloEmptyFunction
今回は、役割や権限に関する質問はありません。
関数がデプロイされたら、再度呼び出すことができます。
dotnet lambda invoke-function HelloEmptyFunction --payload "Invoking a Lambda function"
今回の出力には、追加のログステートメントが含まれます。
Payload:
"INVOKING A LAMBDA FUNCTION"
Log Tail:
START RequestId: 7f77a371-c183-494f-bb44-883fe0c57471 Version: $LATEST
2022-06-03T15:36:20.238Z 7f77a371-c183-494f-bb44-883fe0c57471 info Input: Invoking a Lambda function
END RequestId: 7f77a371-c183-494f-bb44-883fe0c57471
REPORT RequestId: 7f77a371-c183-494f-bb44-883fe0c57471 Duration: 457.22 ms Billed Duration: 458 ms
Memory Size: 256 MB Max Memory Used: 62 MB Init Duration: 262.12 ms
6 行目にはログステートメントがあります。Lambda 関数ログは CloudWatch ログにも書き込まれます (Lambda 関数にそのためのアクセス権限を付与している場合)。
AWS コンソール
この関数を呼び出すもう 1 つの方法は、AWS コンソールから呼び出す方法です。
AWS コンソールにログインし、呼び出す Lambda 関数を選択します。
[テスト] タブをクリックします。
「イベント JSON」セクションまでスクロールし、引用符を含めて「Lambda 関数を呼び出す」と入力します。
次に、[テスト] ボタンをクリックします。
次のような出力が表示されます。
ログ出力も表示されていることに注意してください。
JSON ペイロードを受け取る.NET Lambda 関数
前の例は、文字列を受け取って文字列を返す単純な関数でした。これは始めるのに良い例です。
しかし、おそらく JSON ペイロードを Lambda 関数に送信したいと思うでしょう。実際、別の AWS サービスが Lambda 関数を呼び出すと、JSON ペイロードが送信されます。これらの JSON ペイロードは非常に複雑な場合が多いですが、ペイロードのモデルは NuGet から入手できます。たとえば、Kinesis イベントを Lambda 関数で処理する場合、Amazon.lambda.KinesisEvents パッケージには KinesisEvent モデルがあります。S3 イベント、SQS イベントなどについても同じことが言えます。
これらのモデルを今すぐ使用するのではなく、人を表すペイロードを使用して新しい Lambda 関数を呼び出します。
{
"FirstName": "Alan",
"LastName": "Adams"
}
JSON ペイロードを逆シリアル化するための適切な C# クラスは次のとおりです。
public class Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
}
関数を作成する
前と同じように、次のコマンドを使用して新しい関数を作成します。
dotnet new lambda.EmptyFunction -n HelloPersonFunction
関数をテストします。
FunctionHandler メソッドのコードを次のように変更します。
public string FunctionHandler(Person input, ILambdaContext context)
{
return $"Hello, {input.FirstName} {input.LastName}";
}
public class Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
}
これは数分前に使用したのと同じコマンドです。
dotnet lambda deploy-function HelloPersonFunction
関数を呼び出す
これで、Lambda 関数は JSON ペイロードを受け取ることができますが、JSON が各シェルでエスケープされる方法のため、呼び出す方法は使用しているシェルによって異なります。
PowerShell または bash を使用している場合は、以下を使用してください。
dotnet lambda invoke-function HelloPersonFunction --payload '{ \"FirstName\": \"Alan\", \"LastName\": \"Adams\" }'
dotnet lambda invoke-function HelloPersonFunction --payload "{ \"FirstName\": \"Alan\", \"LastName\": \"Adams\" }"
AWS コンソールにログインし、呼び出す Lambda 関数を選択します。
{
"FirstName": "Alan",
"LastName": "Adams"
}
次のような出力が表示されます。
次のセクションでは、HTTP リクエストに応答する Lambda 関数をデプロイする方法を説明します。
Lambda 関数としてウェブ API アプリケーションを作成して実行する
ただし、Lambda 関数を HTTP リクエストで呼び出すこともでき、これは非常に一般的なユースケースです。
.NET 用 AWS ツールには、ウェブ API アプリケーションをホストするシンプルな Lambda 関数を作成するために使用できるテンプレートがいくつか用意されています。
最もよく知られているのは、おそらく Serverless.AspNetCoreWebAPI テンプレートでしょう。これにより、HTTP リクエストを介して呼び出すことができるシンプルな Web API アプリケーションが作成されます。プロジェクトテンプレートには、HTTP リクエストを Lambda 関数に転送する API ゲートウェイを作成する CloudFormation 設定テンプレートが含まれています。
AWS Lambda にデプロイされると、API ゲートウェイは HTTP リクエストを API ゲートウェイイベントに変換し、この JSON を Lambda 関数に送信します。Lambda サービスにデプロイされるとき、Lambda 関数では Kestrel サーバーは実行されていません。
しかし、ローカルで実行すると、Kestrel Web サーバーが起動します。これにより、どの Web API アプリケーションでも使い慣れた方法でコードを記述してテストするのが非常に簡単になります。通常の行ごとのデバッグを行うこともできます。どちらのコンソールでも、最高の環境をご利用いただけます。
関数を作成する
dotnet new serverless.AspNetCoreWebAPI -n HelloAspNetCoreWebAPI
├───src
│ └───AspNetCoreWebAPI
│ │ appsettings.Development.json
│ │ appsettings.json
│ │ AspNetCoreWebAPI.csproj
│ │ aws-lambda-tools-defaults.json // basic Lambda function config, and points to serverless.template file for deployment
│ │ LambdaEntryPoint.cs // Contains the function handler method, this handles the incoming JSON payload
│ │ LocalEntryPoint.cs // Equivalent to Program.cs when running locally, starts Kestrel (only locally)
│ │ Readme.md
│ │ serverless.template // CloudFormation template for deployment
│ │ Startup.cs // Familiar Startup.cs, can use dependency injection, read config, etc.
│ │
│ └───Controllers
│ ValuesController.cs // Familiar API controller
│
└───test
└───AspNetCoreWebAPI.Tests
│ appsettings.json
│ AspNetCoreWebAPI.Tests.csproj
│ ValuesControllerTests.cs // Unit test for ValuesController
│
└───SampleRequests
ValuesController-Get.json // JSON representing an APIGatewayProxyRequest, used by the unit test
関数をデプロイする
サーバーレス機能をデプロイする前に、S3 バケットが必要です。これは、デプロイツールが CloudFormation スタックを格納するために使用されます。
既存の S3 バケットを使用することも、持っていない場合は以下の手順を使用することもできます。
aws s3api create-bucket --bucket your-unique-bucket-name1234
aws s3api create-bucket --bucket your-unique-bucket-name1234 --create-bucket-configuration LocationConstraint=REGION
aws s3api create-bucket --bucket lambda-course-2022
dotnet lambda deploy-serverless
Enter CloudFormation Stack Name: (CloudFormation stack name for an AWS Serverless application)
次に、S3 バケット名の入力を求められます。以前に作成したバケットの名前、またはこの目的で使用したい既存のバケットの名前を使用してください。
これを入力すると、ビルドとデプロイのプロセスが開始されます。
作成して接続するインフラストラクチャが多いため、lambda.* プロジェクトテンプレートを使用する例よりも時間がかかります。
出力は 2 つの異なるセクションに分割されます。
一番上のセクションは、先に関数をデプロイしたときに見たプロジェクトのパブリッシュと ZIP に似ていますが、今回はアーティファクトが S3 にアップロードされます。
..snip
... zipping: AspNetCoreWebAPI.runtimeconfig.json
... zipping: aws-lambda-tools-defaults.json
Created publish archive (C:\Users\someuser\AppData\Local\Temp\AspNetCoreFunction-CodeUri-Or-ImageUri-637907144179228995.zip).
Lambda project successfully packaged: C:\Users\ someuser\AppData\Local\Temp\AspNetCoreFunction-CodeUri-Or-ImageUri-637907144179228995.zip
Uploading to S3. (Bucket: lambda-course-2022 Key: AspNetCoreWebAPI/AspNetCoreFunction-CodeUri-Or-ImageUri-637907144179228995-637907144208759417.zip)
... Progress: 100%
Uploading to S3. (Bucket: lambda-course-2022 Key: AspNetCoreWebAPI/AspNetCoreWebAPI-serverless-637907144211067892.template)
... Progress: 100%
Found existing stack: False
CloudFormation change set created
... Waiting for change set to be reviewed
Created CloudFormation stack AspNetCoreWebAPI
Timestamp Logical Resource Id Status
-------------------- ---------------------------------------- ----------------------------------------
6/10/2022 09:53 AM AspNetCoreWebAPI CREATE_IN_PROGRESS
6/10/2022 09:53 AM AspNetCoreFunctionRole CREATE_IN_PROGRESS
6/10/2022 09:53 AM AspNetCoreFunctionRole CREATE_IN_PROGRESS
6/10/2022 09:54 AM AspNetCoreFunctionRole CREATE_COMPLETE
6/10/2022 09:54 AM AspNetCoreFunction CREATE_IN_PROGRESS
6/10/2022 09:54 AM AspNetCoreFunction CREATE_IN_PROGRESS
6/10/2022 09:54 AM AspNetCoreFunction CREATE_COMPLETE
6/10/2022 09:54 AM ServerlessRestApi CREATE_IN_PROGRESS
6/10/2022 09:54 AM ServerlessRestApi CREATE_IN_PROGRESS
6/10/2022 09:54 AM ServerlessRestApi CREATE_COMPLETE
6/10/2022 09:54 AM ServerlessRestApiDeploymentcfb7a37fc3 CREATE_IN_PROGRESS
6/10/2022 09:54 AM AspNetCoreFunctionProxyResourcePermissionProd CREATE_IN_PROGRESS
6/10/2022 09:54 AM AspNetCoreFunctionRootResourcePermissionProd CREATE_IN_PROGRESS
6/10/2022 09:54 AM AspNetCoreFunctionProxyResourcePermissionProd CREATE_IN_PROGRESS
6/10/2022 09:54 AM AspNetCoreFunctionRootResourcePermissionProd CREATE_IN_PROGRESS
6/10/2022 09:54 AM ServerlessRestApiDeploymentcfb7a37fc3 CREATE_IN_PROGRESS
6/10/2022 09:54 AM ServerlessRestApiDeploymentcfb7a37fc3 CREATE_COMPLETE
6/10/2022 09:54 AM ServerlessRestApiProdStage CREATE_IN_PROGRESS
6/10/2022 09:54 AM ServerlessRestApiProdStage CREATE_IN_PROGRESS
6/10/2022 09:54 AM ServerlessRestApiProdStage CREATE_COMPLETE
6/10/2022 09:54 AM AspNetCoreFunctionProxyResourcePermissionProd CREATE_COMPLETE
6/10/2022 09:54 AM AspNetCoreFunctionRootResourcePermissionProd CREATE_COMPLETE
6/10/2022 09:54 AM AspNetCoreWebAPI CREATE_COMPLETE
Stack finished updating with status: CREATE_COMPLETE
Output Name Value
------------------------------ --------------------------------------------------
ApiURL https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/Prod/
一番下には、API を呼び出すために使用できる公開 URL があります。
関数を呼び出しています
次に、https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/Prod/api/values を開いてみてください。通常の Web API アプリケーションと同じように、値コントローラーの GET メソッドが呼び出されます。
API Gateway を使用する場合、ゲートウェイは 29 秒という独自のタイムアウトを課すことに注意してください。Lambda 関数がこれより長く実行されると、応答は届きません。
興味があれば、作成されたリソースを確認する方法がいくつかあります。
作成された AWS リソースを確認するには、以下を使用できます。
aws cloudformation describe-stack-resources --stack-name AspNetCoreWebAPI
より簡潔な出力が必要な場合は、以下を使用してください。
aws cloudformation describe-stack-resources --stack-name AspNetCoreWebAPI --query 'StackResources[].[{ResourceType:ResourceType, LogicalResourceId:LogicalResourceId, PhysicalResourceId:PhysicalResourceId}]'
これらの例を使用して、独自の Lambda 関数を作成してデプロイできます。また、.NET Lambda 関数がどのように呼び出されるかについても少し理解できたかもしれません。それが次のセクションの主題です。
関数 URL — API ゲートウェイの代替手段
作成したリソースをクリーンアップする
dotnet lambda delete-function HelloEmptyFunction
dotnet lambda delete-function HelloPersonFunction
上記のコマンドでは、作成したロールは削除されないことに注意してください。
Web API アプリケーションをホストしていた Lambda 関数と関連するすべてのリソースを削除するには、以下を実行します。
dotnet lambda delete-serverless AspNetCoreWebAPI
.NET ラムダ関数を呼び出す方法
上記の例からわかるように、.NET Lambda 関数は単純な文字列、JSON オブジェクト、および HTTP リクエストで呼び出すことができます。Lambda 関数は、S3 (ファイルの変更が発生した場合)、Kinesis (イベントが到着したとき)、DynamoDB (テーブルに変更が発生した場合)、SMS (メッセージが到着したとき)、ステップ関数などの他のサービスからも呼び出すことができます。
Lambda 関数はこのようなさまざまな呼び出し方法をどのように処理するのでしょうか?
内部的には、これらの Lambda 関数は、Lambda サービスが関数ハンドラーを実行して JSON 入力を渡したときに呼び出されます。aws-lambda-tools-defaults.json を見てみると、「関数ハンドラー」: 指定されていることがわかります。.NET Lambda 関数の場合、handler は「アセンブリ名:: 名前空間。クラス名:: メソッド名」で構成されます。
Lambda 関数はストリームを渡すことで呼び出すこともできますが、これはあまり一般的ではないシナリオです。詳細については、ストリームの処理に関するページを参照してください。
各 Lambda 関数には 1 つの関数ハンドラーがあります。
JSON 入力に加えて、Lambda 関数ハンドラーはオプションの ILambdaContext オブジェクトを受け取ることもできます。これにより、完了までの残り時間、関数名、バージョンなど、現在の呼び出しに関する情報にアクセスできます。ILambdaContext オブジェクトを使用してログメッセージをに書き込むこともできます。
すべてのイベントは JSON です
AWS サービスが.NET Lambda 関数を簡単に呼び出せる理由は、これらのサービスが JSON を出力し、前述のように、.NET Lambda 関数が JSON 入力を受け入れることです。さまざまなサービスによって発生するイベントはすべて異なる形の JSON を生成しますが、AWS Lambda イベント NuGet パッケージには、JSON をユーザーが操作できるオブジェクトにシリアル化するために必要なすべての関連オブジェクトタイプが含まれています。
利用可能な Lambda パッケージのリストについては、 https://www.nuget.org/packages?packagetype=&sortby=relevance&q=Amazon.Lambda&prerel=True を参照してください。それらの結果の中から関心のあるイベントタイプを検索する必要があります。
たとえば、S3 バケットのファイル変更に応じて Lambda 関数をトリガーする場合は、S3Event タイプのオブジェクトを受け入れる Lambda 関数を作成する必要があります。次に、Amazon.Lambda.S3Events パッケージをプロジェクトに追加します。次に、関数ハンドラーメソッドを次のように変更します。
public async string FunctionHandler(S3Event s3Event, ILambdaContext context)
{
...
}
S3 イベントの処理に必要なのはこれだけです。プログラムでイベントを調べ、ファイルに対してどのようなアクションが実行されたか、どのバケットにあったかなどを確認できます。Amazon.Lambda.S3Events を使用すると、S3 自体ではなくイベントを操作できます。S3 サービスとやり取りしたい場合は、AWSSDK.S3 NuGet パッケージをプロジェクトに追加する必要もあります。後のモジュールでは、Lambda 関数を呼び出す AWS サービスについて説明します。
他のタイプのイベントについても同じパターンで、NuGet パッケージを追加し、パラメータを関数ハンドラに変更すると、イベントオブジェクトを操作できるようになります。
他のサービスからのイベントを処理するために使用できる一般的なパッケージをいくつか紹介します-
https://www.nuget.org/packages/Amazon.Lambda.SNSEvents
https://www.nuget.org/packages/Amazon.Lambda.DynamoDBEvents
https://www.nuget.org/packages/Amazon.Lambda.CloudWatchEvents
https://www.nuget.org/packages/Amazon.Lambda.KinesisEvents
https://www.nuget.org/packages/Amazon.Lambda.APIGatewayEvents
Lambda 関数を呼び出す際には、AWS 定義のイベントタイプを使用することに限定されません。どのタイプのイベントも自分で作成できます。Lambda 関数は送信した JSON をすべて取得できることを覚えておいてください。
シリアル化の仕組み
「lambda」の場合。」テンプレートでは、Function.cs ファイルの先頭付近にアセンブリ属性があります。これにより、受信イベントを関数ハンドラーの .NET タイプに逆シリアル化できます。.csproj ファイルには、Amazon.lambda.Serialization.SystemTextJson パッケージへの参照があります。
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
「サーバーレス」用.」テンプレートの場合、動作が少し異なります。
関数ハンドラーはサーバーレス .template ファイルで指定されます。Serverless.AspNetCoreWebAPI アプリケーションをデプロイする場合は、resources.AspNetCoreFunction.Properties.Handler の値を確認してください。このタイプのプロジェクトのハンドラーは、最終的には-Assembly::名前空間 LambdaEntryPoint::FunctionHandlerAsync. 関数という形式になります。
LambdaEntryPoint クラスはプロジェクトに含まれており、FunctionHandlerAsync メソッドを持つクラスから継承されます。
関数ハンドラーは、API ゲートウェイ REST API、API ゲートウェイ HTTP API ペイロードバージョン 1.0、API ゲートウェイ HTTP API ペイロードバージョン 2.0、および Application Load Balancer の 4 つの異なるイベントタイプを処理するように設定できます。
LambdaEntryPoint が継承するクラスを変更することで、関数ハンドラーが処理する JSON イベントのタイプを変更できます。
Lambda 関数が送信した HTTP リクエストに、ユーザーが定義した JSON で応答しているように見えても、そうではありません。実際には、HTTP リクエストはゲートウェイまたはロードバランサーによって処理され、JSON イベントが作成されて関数ハンドラーに送信されます。この JSON イベントには、HTTP リクエストに元々含まれていたデータ、ソース IP アドレスに至るすべてのデータ、およびリクエストヘッダーが含まれます。
同時実行
Lambda 関数を使用する際に考慮すべき同時実行には、リザーブド同時実行とプロビジョニングされた同時実行の 2 種類があります。
AWS アカウントには、Lambda の同時実行数にデフォルトの上限があります。この記事の執筆時点では、その制限は 1,000 です。
関数に予約済みの同時実行を指定すると、その関数が指定した数の同時実行数に達することが保証されます。たとえば、関数に 200 の同時実行が予約されている場合、その関数が 200 回の同時実行に達することが保証されます。これにより、他の関数では同時実行が 800 回残っていることに注意してください (1000-200=800)。
プロビジョニングされた同時実行を指定すると、指定した数の Lambda 実行環境を初期化することになります。これらが初期化されると、Lambda 関数はリクエストにすぐに応答できるようになり、「コールドスタート」の問題を回避できます。ただし、プロビジョニングされた同時実行の使用には料金がかかります。
詳細については、「Lambda リザーブド同時実行の管理」および「Lambda プロビジョニング同時実行の管理 」を参照してください。
コールドスタートとウォームスタート
Lambda 関数を呼び出す前に、実行環境を初期化する必要があります。これはユーザーに代わって Lambda サービスによって行われます。ソースコードは、AWS が管理する S3 バケット (マネージドランタイムとカスタムランタイムを使用する関数用) または Elastic Container Registry (コンテナイメージを使用する関数の場合) からダウンロードされます。
関数を初めて実行するときは、コードを JITed して、初期化コードを実行する必要があります (例:コンストラクター)。これにより、コールドスタート時間が長くなります。
関数が定期的に呼び出されている場合、その関数は「ウォーム」のままになります。つまり、実行環境が維持されます。それ以降に関数を呼び出しても、コールドスタート時間は影響を受けません。「ウォームスタート」は「コールドスタート」よりも大幅に高速です。
関数が一定期間呼び出されない場合 (Lambda サービスによって正確な時間が指定されていない場合)、実行環境は削除されます。次に関数を呼び出すと、再びコールドスタートになります。
関数コードの新しいバージョンをアップロードした場合、次に関数を呼び出すとコールドスタートになります。
Lambda で .NET を実行するための 3 つのオプション、マネージドランタイム、カスタムランタイム、コンテナホストには、それぞれ異なるコールドスタートプロファイルがあります。最も遅いのはコンテナ、次に遅いのはカスタムランタイム、最も速いのはマネージドランタイムです。可能であれば、.NET Lambda 関数を実行するときは常にマネージドランタイムを選択してください。
コールドスタートは、本番環境よりもテスト環境または開発環境でより頻繁に発生することがわかっています。AWS の分析では、コールドスタートは呼び出しの 1% 未満で発生しています。
あまり使用されないがリクエストに迅速に応答する必要がある Lambda 関数が本番環境にあり、コールドスタートを避けたい場合は、プロビジョニングされた同時実行機能を使用するか、関数を頻繁に「ping」するメカニズムを使用して関数を暖かく保つことができます。
Lambda 関数の最適化について詳しく知りたい場合は、 AWS Lambda デベロッパーガイドでコールドスタート、ウォームスタート、プロビジョニングされた同時実行について読むか、「Lambda の運用:パフォーマンスの最適化」ブログシリーズ James Beswick — パート 1、パート 2、パート 3 をご覧ください。
.NET 7 より前の .NET バージョンのトリミングと実行準備完了
.NET 7 より前のバージョンの .NET で Lambda カスタムランタイムを使用することを選択した場合、コールドスタート時間を短縮するために使用できる.NET 機能がいくつかあります。
PublishTrimmed は、パッケージから不要なライブラリを削除することで、デプロイするパッケージ全体のサイズを小さくします。
PublishReadyToRun はコードを事前にコンパイルするので、必要なジャストインタイムコンパイルの量が減ります。ただし、デプロイするパッケージのサイズは大きくなります。
最適なパフォーマンスを得るには、これらのオプションを使用するときに関数をテストする必要があります。
.csproj ファイルから PublishTrimmed と PublishReadyToRun をオンにできます。
<PublishTrimmed>true</PublishTrimmed>
<PublishReadyToRun>true</PublishReadyToRun>
まとめ
.NET 7 用のネイティブ事前コンパイル
dotnet new -i "Amazon.Lambda.Templates::*"dotnet tool update -g Amazon.Lambda.Tools
知識のチェック
これで、モジュール 2「AWS Lambda を使用した .NET 開発用ツール」を完了しました。以下のテストでは、これまでに学んだことを確認できます。
1.Lambda サービスが提供している .NET マネージドランタイムのバージョンは何ですか?(2 つ選択してください)
b. NET 6
c. NET 7
d. .NET Core 3.1
e. .NET Framework 4.8
2.コールドスタートとは何を指しますか?(1 つ選択してください)
b.AWS S3 グレイシャーストレージを使用する Lambda 関数です。
c.コードを Lambda サービスにデプロイするのにかかる時間。
d.関数の更新にかかる時間
3..NET Lambda 関数で AWS .NET SDK をどのように使用していますか?
a.SDK パッケージへの参照をプロジェクトファイルに追加します。
b.Lambda 関数テンプレートに含まれているので、その必要はありません。
c.その必要はありません。IDE のツールキットには付属しています。
d.AWS コンソールを使用して SDK を Lambda サービスに追加します。
4.新しい Lambda.EmptyFunction プロジェクトを作成するとき、関数の構成を指定するファイルの名前は何ですか?
b. lambda.csproj
c. aws-lambda-tools-defaults.json
5.Lambda 関数を呼び出す方法は次のうちどれですか?
b.HTTPS リクエスト
c.他の AWS のサービスからのアクセス
d.上記のすべて
回答:1-ベッド、2-a、3-a、4-c、5-d