教程:使用 适用于 .NET 的 AWS 开发工具包 管理 Amazon EC2 Spot 实例 - AWS Lambda
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

教程:使用 适用于 .NET 的 AWS 开发工具包 管理 Amazon EC2 Spot 实例

您可以使用 适用于 .NET 的 AWS 开发工具包 通过 C# 代码管理 Amazon EC2 Spot 实例。利用开发工具包,您可以使用 Amazon EC2 API 创建 Spot 实例请求、确定满足请求的时间、删除请求以及标识创建的实例。

本教程提供执行这些任务的代码以及可本地或在 AWS 上运行的示例应用程序。它包含一个示例项目,可将该项目部署到 AWS Lambda 的 .NET Core 2.1 运行时。


      一个用于管理 Spot 请求和 Amazon EC2 实例的 Lambda 函数。

有关 Spot 实例使用情况和最佳实践的更多信息,请参阅《Amazon EC2 用户指南》中的 Spot 实例

先决条件

为了遵循本指南中的步骤,您需要命令行终端或外壳,以便运行命令。命令显示在列表中,以提示符 ($) 和当前目录名称(如果有)开头:

~/lambda-project$ this is a command this is output

对于长命令,使用转义字符 (\) 将命令拆分到多行中。

在 Linux 和 macOS 中,可使用您首选的外壳程序和程序包管理器。在 Windows 10 中,您可以 安装 Windows Subsystem for Linux,获取 Ubuntu 和 Bash 与 Windows 集成的版本。

本教程使用开发人员指南的 GitHub 存储库中的代码。该存储库还包含执行其过程所需的帮助程序脚本和配置文件。克隆 github.com/awsdocs/aws-lambda-developer-guide 上的存储库。

要使用示例代码,您需要以下工具:

  • AWS CLI – 要将示例应用程序部署到 AWS,请安装 AWS CLI。在本地运行示例代码时,AWS CLI 还会向该代码提供凭证。

  • .NET Core CLI – 要本地运行和测试代码,请安装 .NET Core 开发工具包 2.1

  • Lambda .NET Core Global Tool – 要为 Lambda 构建部署程序包,请安装带 .NET Core CLI 的 .NET Core Global Tool

    $ dotnet tool install -g Amazon.Lambda.Tools

本教程中的代码可管理启动 Amazon EC2 实例的 Spot 请求。要本地运行代码,您需要具有开发工具包凭证并有权使用以下 API。

  • ec2:RequestSpotInstance

  • ec2:GetSpotRequestState

  • ec2:CancelSpotRequest

  • ec2:TerminateInstances

要在 AWS 中运行示例应用程序,您需要有权使用 Lambda 和以下服务。

标准费用适用于每项服务。

查看代码

sample-apps/ec2-spot 下的指南存储库中查找示例项目。此目录包含 Lambda 函数代码、测试、项目文件、脚本和 AWS CloudFormation 模板。

Function 类包含一个 FunctionHandler 方法,该方法调用其他方法来创建 Spot 请求、检查其状态并进行清理。它在静态构造函数中使用 适用于 .NET 的 AWS 开发工具包 中创建 Amazon EC2 客户端,以便能够在整个类中使用它。

Function.cs – FunctionHandler

using Amazon.EC2; ... public class Function { private static AmazonEC2Client ec2Client; static Function() { AWSSDKHandler.RegisterXRayForAllServices(); ec2Client = new AmazonEC2Client(); } public async Task<string> FunctionHandler(Dictionary<string, string> input, ILambdaContext context) { // More AMI IDs: aws.amazon.com/amazon-linux-2/release-notes/ // us-east-2 HVM EBS-Backed 64-bit Amazon Linux 2 string ami = "ami-09d9edae5eb90d556"; string sg = "default"; InstanceType type = InstanceType.T3aNano; string price = "0.003"; int count = 1; var requestSpotInstances = await RequestSpotInstance(ami, sg, type, price, count); var spotRequestId = requestSpotInstances.SpotInstanceRequests[0].SpotInstanceRequestId;

RequestSpotInstance 方法可创建 Spot 实例请求。

Function.cs – RequestSpotInstance

using Amazon; using Amazon.Util; using Amazon.EC2; using Amazon.EC2.Model; ... public async Task<RequestSpotInstancesResponse> RequestSpotInstance( string amiId, string securityGroupName, InstanceType instanceType, string spotPrice, int instanceCount) { var request = new RequestSpotInstancesRequest(); var launchSpecification = new LaunchSpecification(); launchSpecification.ImageId = amiId; launchSpecification.InstanceType = instanceType; launchSpecification.SecurityGroups.Add(securityGroupName); request.SpotPrice = spotPrice; request.InstanceCount = instanceCount; request.LaunchSpecification = launchSpecification; RequestSpotInstancesResponse response = await ec2Client.RequestSpotInstancesAsync(request); return response; } ...

接下来,您需要等待直至 Spot 请求进入 Active 状态,然后继续到最后一步。要确定 Spot 请求的状态,请使用 DescribeSpotInstanceRequests 方法来获取要监视的 Spot 请求 ID 的状态。

public async Task<SpotInstanceRequest> GetSpotRequest(string spotRequestId) { var request = new DescribeSpotInstanceRequestsRequest(); request.SpotInstanceRequestIds.Add(spotRequestId); var describeResponse = await ec2Client.DescribeSpotInstanceRequestsAsync(request); return describeResponse.SpotInstanceRequests[0]; }

最后一步是清除您的请求和实例。重要的是,要取消所有未完成的请求并终止所有实例。只取消请求不会终止您的实例,这意味着您需要继续为它们支付费用。如果您终止了实例,那么 Spot 请求可能会被取消,但在某些情况下,例如,如果您使用的是持久请求,那么只终止实例是不足以停止请求的,以至于这些请求会重新执行。因此,最好的做法是取消所有活跃的请求并终止所有正在运行的实例。

您使用 CancelSpotInstanceRequests 方法来取消 Spot 请求。以下示例演示了如何取消 Spot 请求。

public async Task CancelSpotRequest(string spotRequestId) { Console.WriteLine("Canceling request " + spotRequestId); var cancelRequest = new CancelSpotInstanceRequestsRequest(); cancelRequest.SpotInstanceRequestIds.Add(spotRequestId); await ec2Client.CancelSpotInstanceRequestsAsync(cancelRequest); }

您可使用 TerminateInstances 方法终止实例。

public async Task TerminateSpotInstance(string instanceId) { Console.WriteLine("Terminating instance " + instanceId); var terminateRequest = new TerminateInstancesRequest(); terminateRequest.InstanceIds = new List<string>() { instanceId }; try { var terminateResponse = await ec2Client.TerminateInstancesAsync(terminateRequest); } catch (AmazonEC2Exception ex) { // Check the ErrorCode to see if the instance does not exist. if ("InvalidInstanceID.NotFound" == ex.ErrorCode) { Console.WriteLine("Instance {0} does not exist.", instanceId); } else { // The exception was thrown for another reason, so re-throw the exception. throw; } } }

本地运行代码

在本地计算机上运行代码以创建 Spot 实例请求。满足请求后,代码将删除请求并终止实例。

运行应用程序代码

  1. 导航到 ec2Spot.Tests 目录。

    $ cd test/ec2Spot.Tests
  2. 使用 .NET CLI 运行项目的单元测试。

    test/ec2Spot.Tests$ dotnet test Starting test execution, please wait... sir-x5tgs5ij open open open open open active Canceling request sir-x5tgs5ij Terminating instance i-0b3fdff0e12e0897e Complete Test Run Successful. Total tests: 1 Passed: 1 Total time: 7.6060 Seconds

单元测试调用 FunctionHandler 方法来创建 Spot 实例请求、监控它并进行清理。它是在 xUnit.net 测试框架中实现的。

部署应用程序

在 Lambda 中运行代码作为创建无服务器应用程序的起点。

部署和测试应用程序

  1. 将您的区域设置为 us-east-2

    $ export AWS_DEFAULT_REGION=us-east-2
  2. 为部署构件创建存储桶。

    $ ./create-bucket.sh make_bucket: lambda-artifacts-63d5cbbf18fa5ecc
  3. 创建部署程序包并部署应用程序。

    $ ./deploy.sh Amazon Lambda Tools for .NET Core applications (3.3.0) Project Home: https://github.com/aws/aws-extensions-for-dotnet-cli, https://github.com/aws/aws-lambda-dotnet Executing publish command ... Created publish archive (ec2spot.zip) Lambda project successfully packaged: ec2spot.zip Uploading to ebd38e401cedd7d676d05d22b76f0209 1305107 / 1305107.0 (100.00%) Successfully packaged artifacts and wrote output template to file out.yaml. Execute the following command to deploy the packaged template aws cloudformation deploy --template-file out.yaml --stack-name <YOUR STACK NAME> Waiting for changeset to be created.. Waiting for stack create/update to complete Successfully created/updated stack - ec2-spot
  4. 打开 Lambda 控制台的“Applications”(应用程序)页面

    
            Lambda 控制台中的示例应用程序。
  5. Resources (资源) 下,选择 function (函数)

  6. 选择 Test (测试) 并从默认模板创建测试事件。

  7. 再次选择 Test (测试) 以调用该函数。

查看日志和追踪信息以了解 Spot 请求 ID 以及对 Amazon EC2 的调用的顺序。

要查看服务映射,请打开 X-Ray 控制台中的“Service map (服务映射)”页面


        示例应用程序的 X-Ray 服务映射。

在服务映射中选择一个节点,然后选择 View traces (查看跟踪) 以查看跟踪列表。从列表中选择跟踪以查看函数对 Amazon EC2 进行的调用的时间线。


        示例应用程序的 X-Ray 时间线。

清除

本教程中提供的代码旨在创建和删除 Spot 实例请求,并终止它们启动的实例。但是,如果出现错误,可能不会自动清理请求和实例。在 Amazon EC2 控制台中查看 Spot 请求和实例。

确认已清理 Amazon EC2 资源

  1. 在 Amazon EC2 控制台中打开“Spot Requests (Spot 请求)”页面

  2. 验证请求的状态是否为 Cancelled (已取消)

  3. Capacity (容量) 列中选择实例 ID 以查看实例。

  4. 验证实例的状态是 Terminated (已终止) 还是 Shutting down (正在关闭)

要清理示例函数和支持资源,请删除其 AWS CloudFormation 堆栈以及您创建的构件存储桶。

$ ./cleanup.sh Delete deployment artifacts and bucket (lambda-artifacts-63d5cbbf18fa5ecc)?y delete: s3://lambda-artifacts-63d5cbbf18fa5ecc/ebd38e401cedd7d676d05d22b76f0209 remove_bucket: lambda-artifacts-63d5cbbf18fa5ecc

不会自动删除函数的日志组。您可以在 CloudWatch Logs 控制台中删除它。X-Ray 中的跟踪在几周后过期,并且会被自动删除。