Amazon EC2 スポットインスタンスのチュートリアル - AWS SDK for .NET

数回クリックするだけで .NET アプリケーションを AWS にデプロイしたいと思いませんか? シンプルなデプロイエクスペリエンスを実現する、新しい .NET CLI ツールをお試しください。

Ourオリジナルのブログ投稿だけでなく、投稿を更新デプロイプロジェクトへの投稿。フィードバックを送信するGitHub! 詳細については、このガイドのデプロイツールに関するセクションを参照してください。

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

Amazon EC2 スポットインスタンスのチュートリアル

このチュートリアルでは、以下の方法を示します。AWS SDK for .NETをクリックして Amazon EC2 スポットインスタンスを管理します。

概要

スポットインスタンスを使用すると、オンデマンド価格より低価で未使用の Amazon EC2 容量をリクエストできます。これにより、中断される可能性のあるアプリケーションの EC2 コストを大幅に削減できます。

スポットインスタンスのリクエストおよび使用方法の概要は次のとおりです。

  1. スポットインスタンスリクエストを作成します。料金の上限を指定します。

  2. リクエストが満たされたら、他の Amazon EC2 インスタンスと同様にインスタンスを実行します。

  3. 必要な期間インスタンスを実行し、終了する。スポット価格インスタンスが自動的に終了するように変更されます。

  4. 不要になったスポットインスタンスリクエストをクリーンアップして、スポットインスタンスが作成されなくなります。

これは、スポットインスタンスの非常に高いレベルの概要です。スポットインスタンスについては、「」でスポットインスタンスについて理解を深めることができます。Linux インスタンス用 Amazon EC2 ユーザーガイドまたはWindows インスタンス用 Amazon EC2 ユーザーガイド

このチュートリアルの内容

このチュートリアルでは、以下の方法を使用します。AWS SDK for .NETをクリックして、次の作業を行います。

  • スポットインスタンスリクエストを作成する

  • スポットインスタンスリクエストが受理されたかどうかを判断する

  • スポットインスタンスリクエストをキャンセルする

  • 関連するインスタンスを終了させる

次のセクションでは、この例のスニペットおよびその他の情報について説明します。-例の完全なコードはスニペットの後に表示され、そのままビルドして実行できます。

前提条件

API と前提条件の詳細については、親セクション (Amazon EC2 の操作).

必要なものを集める

スポットインスタンスリクエストを作成するには、いくつかのものが必要です。

  • インスタンス時間あたりに支払うことができる上限価格。すべてのインスタンスタイプ(オンデマンドインスタンスとスポットインスタンスの両方)の価格は、Amazon EC2 料金表。このチュートリアルのデフォルト価格については、後で説明します。

スポットインスタンスをリクエストするには複数の方法があります。の一般的な戦略は以下のとおりです。

  • リクエストは、オンデマンド料金を下回るコストを確実にします。

  • 計算結果の値に基づいてリクエストを実行します。

  • 計算キャパシティーをできるだけ早く獲得するようにリクエストを行います。

以下の説明は、「スポット価格」の履歴を参照してください。Linux インスタンス用 Amazon EC2 ユーザーガイドまたはWindows インスタンス用 Amazon EC2 ユーザーガイド

実行完了までに何時間も、あるいは何日間もかかるバッチ処理ジョブがあるとします。ただし、いつ開始していつ終了するかについては、特に決められていないものとします。このジョブを完了するためのコストを、オンデマンドインスタンスを使用する場合よりも低くできるかどうかを考えます。

インスタンスタイプのスポット料金の履歴を、Amazon EC2 コンソールまたは Amazon EC2 API を使用して調べます。使用したいインスタンスタイプの、特定のアベイラビリティーゾーンでの価格履歴を分析した後は、リクエストのアプローチとして次の 2 つも考えられます。

  • スポット料金の範囲の上限 (ただしオンデマンド価格より下) でリクエストを指定します。このようにすれば、この 1 回限りのスポットインスタンスリクエストが受理される可能性が高くなり、ジョブが完了するまで連続して実行できるからです。

  • 価格範囲の下限でリクエストを指定し、1 つの永続リクエストで次々とインスタンスを起動するよう計画を立てます。これらのインスタンスの実行時間を合計すると、ジョブを完了するのに十分な長さとなり、合計コストも低くなります。

データ処理ジョブを実行するとします。このジョブの結果の価値は判明しており、計算コストに換算してどれくらいになるかもわかっています。

使用するインスタンスタイプのスポット料金履歴の分析が完了した後で、価格を選択します。計算時間のコストがこのジョブの結果の価値を上回ることがないように、価格を決定します。永続リクエストを作成し、スポット料金がリクエスト以下となったときに断続的に実行するよう設定します。

追加のキャパシティーが突然、短期間だけ必要になることがあり、オンデマンドインスタンスではそのキャパシティーを獲得できないとします。使用するインスタンスタイプのスポット料金履歴の分析が完了した後で、履歴の価格の最大値を超える価格を選択します。このようにすれば、リクエストがすぐに受理される可能性が高まり、計算が完了するまで連続して計算できるようになります。

必要なものを収集して戦略を選択したら、スポットインスタンスをリクエストできます。このチュートリアルでは、デフォルトの最大スポットインスタンス料金をオンデマンド料金 (このチュートリアルでは 0.003 USD) と同額に設定します。このように料金を設定すると、リクエストが達成される可能性が最大になります。

スポットインスタンスリクエストを作成する

次のスニペットは、前に収集した要素を使用してスポットインスタンスリクエストを作成する方法を示しています。

例から学ぶことができますこのトピックの最後にあるに、このスニペットが使用中であることを示します。

// // Method to create a Spot Instance request private static async Task<SpotInstanceRequest> CreateSpotInstanceRequest( IAmazonEC2 ec2Client, string amiId, string securityGroupName, InstanceType instanceType, string spotPrice, int instanceCount) { var launchSpecification = new LaunchSpecification{ ImageId = amiId, InstanceType = instanceType }; launchSpecification.SecurityGroups.Add(securityGroupName); var request = new RequestSpotInstancesRequest{ SpotPrice = spotPrice, InstanceCount = instanceCount, LaunchSpecification = launchSpecification }; RequestSpotInstancesResponse result = await ec2Client.RequestSpotInstancesAsync(request); return result.SpotInstanceRequests[0]; }

このメソッドから返される重要な値は、スポットインスタンスリクエスト ID で、SpotInstanceRequestId返されたのメンバーSpotInstanceRequestオブジェクト。

注記

起動されたスポットインスタンスに対して課金されます。不必要なコストを回避するには、リクエストをキャンセルするそしてインスタンスを終了します。

スポットインスタンスリクエストの状態を特定する

次のスニペットは、スポットインスタンスリクエストに関する情報を取得する方法を示します。この情報を使用して、スポットインスタンスリクエストが満たされるのを待つかどうかなど、コード内で特定の決定を下すことができます。

例から学ぶことができますこのトピックの最後にあるに、このスニペットが使用中であることを示します。

// // Method to get information about a Spot Instance request, including the status, // instance ID, etc. // It gets the information for a specific request (as opposed to all requests). private static async Task<SpotInstanceRequest> GetSpotInstanceRequestInfo( IAmazonEC2 ec2Client, string requestId) { var describeRequest = new DescribeSpotInstanceRequestsRequest(); describeRequest.SpotInstanceRequestIds.Add(requestId); DescribeSpotInstanceRequestsResponse describeResponse = await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest); return describeResponse.SpotInstanceRequests[0]; }

このメソッドは、インスタンス ID、状態、ステータスコードなど、スポットインスタンスリクエストに関する情報を返します。スポットインスタンスリクエストのステータスコードは、Linux インスタンス用 Amazon EC2 ユーザーガイドまたはWindows インスタンス用 Amazon EC2 ユーザーガイド

スポットインスタンスリクエストのクリーンアップ

スポットインスタンスをリクエストする必要がなくなった場合は、未処理のリクエストをキャンセルして、それらのリクエストが再実行されないようにすることが重要です。次のスニペットは、スポットインスタンスリクエストをキャンセルする方法を示しています。

例から学ぶことができますこのトピックの最後にあるに、このスニペットが使用中であることを示します。

// // Method to cancel a Spot Instance request private static async Task CancelSpotInstanceRequest( IAmazonEC2 ec2Client, string requestId) { var cancelRequest = new CancelSpotInstanceRequestsRequest(); cancelRequest.SpotInstanceRequestIds.Add(requestId); await ec2Client.CancelSpotInstanceRequestsAsync(cancelRequest); }

スポットインスタンスのクリーンアップ

不要なコストを回避するには、スポットインスタンスリクエストから開始されたインスタンスを削除することが重要です。単にスポットインスタンスリクエストをキャンセルしてもインスタンスリクエストは終了しないので、引き続きお客様への課金が発生することになります。次のスニペットは、アクティブなスポットインスタンスのインスタンス ID を取得した後にインスタンスを削除する方法を示します。

例から学ぶことができますこのトピックの最後にあるに、このスニペットが使用中であることを示します。

// // Method to terminate a Spot Instance private static async Task TerminateSpotInstance( IAmazonEC2 ec2Client, string requestId) { var describeRequest = new DescribeSpotInstanceRequestsRequest(); describeRequest.SpotInstanceRequestIds.Add(requestId); // Retrieve the Spot Instance request to check for running instances. DescribeSpotInstanceRequestsResponse describeResponse = await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest); // If there are any running instances, terminate them if( (describeResponse.SpotInstanceRequests[0].Status.Code == "request-canceled-and-instance-running") || (describeResponse.SpotInstanceRequests[0].State == SpotInstanceState.Active)) { TerminateInstancesResponse response = await ec2Client.TerminateInstancesAsync(new TerminateInstancesRequest{ InstanceIds = new List<string>(){ describeResponse.SpotInstanceRequests[0].InstanceId } }); foreach (InstanceStateChange item in response.TerminatingInstances) { Console.WriteLine($"\n Terminated instance: {item.InstanceId}"); Console.WriteLine($" Instance state: {item.CurrentState.Name}\n"); } } }

コードの完了

次のコード例では、前述のメソッドを呼び出して、スポットインスタンスリクエストを作成およびキャンセルし、スポットインスタンスを終了します。

using System; using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; using Amazon.EC2; using Amazon.EC2.Model; namespace EC2SpotInstanceRequests { class Program { static async Task Main(string[] args) { // Some default values. // These could be made into command-line arguments instead. var instanceType = InstanceType.T1Micro; string securityGroupName = "default"; string spotPrice = "0.003"; int instanceCount = 1; // Parse the command line arguments if((args.Length != 1) || (!args[0].StartsWith("ami-"))) { Console.WriteLine("\nUsage: EC2SpotInstanceRequests ami"); Console.WriteLine(" ami: the Amazon Machine Image to use for the Spot Instances."); return; } // Create the Amazon EC2 client. var ec2Client = new AmazonEC2Client(); // Create the Spot Instance request and record its ID Console.WriteLine("\nCreating spot instance request..."); var req = await CreateSpotInstanceRequest( ec2Client, args[0], securityGroupName, instanceType, spotPrice, instanceCount); string requestId = req.SpotInstanceRequestId; // Wait for an EC2 Spot Instance to become active Console.WriteLine( $"Waiting for Spot Instance request with ID {requestId} to become active..."); int wait = 1; var start = DateTime.Now; while(true) { Console.Write("."); // Get and check the status to see if the request has been fulfilled. var requestInfo = await GetSpotInstanceRequestInfo(ec2Client, requestId); if(requestInfo.Status.Code == "fulfilled") { Console.WriteLine($"\nSpot Instance request {requestId} " + $"has been fulfilled by instance {requestInfo.InstanceId}.\n"); break; } // Wait a bit and try again, longer each time (1, 2, 4, ...) Thread.Sleep(wait); wait = wait * 2; } // Show the user how long it took to fulfill the Spot Instance request. TimeSpan span = DateTime.Now.Subtract(start); Console.WriteLine($"That took {span.TotalMilliseconds} milliseconds"); // Perform actions here as needed. // For this example, simply wait for the user to hit a key. // That gives them a chance to look at the EC2 console to see // the running instance if they want to. Console.WriteLine("Press any key to start the cleanup..."); Console.ReadKey(true); // Cancel the request. // Do this first to make sure that the request can't be re-fulfilled // once the Spot Instance has been terminated. Console.WriteLine("Canceling Spot Instance request..."); await CancelSpotInstanceRequest(ec2Client, requestId); // Terminate the Spot Instance that's running. Console.WriteLine("Terminating the running Spot Instance..."); await TerminateSpotInstance(ec2Client, requestId); Console.WriteLine("Done. Press any key to exit..."); Console.ReadKey(true); } // // Method to create a Spot Instance request private static async Task<SpotInstanceRequest> CreateSpotInstanceRequest( IAmazonEC2 ec2Client, string amiId, string securityGroupName, InstanceType instanceType, string spotPrice, int instanceCount) { var launchSpecification = new LaunchSpecification{ ImageId = amiId, InstanceType = instanceType }; launchSpecification.SecurityGroups.Add(securityGroupName); var request = new RequestSpotInstancesRequest{ SpotPrice = spotPrice, InstanceCount = instanceCount, LaunchSpecification = launchSpecification }; RequestSpotInstancesResponse result = await ec2Client.RequestSpotInstancesAsync(request); return result.SpotInstanceRequests[0]; } // // Method to get information about a Spot Instance request, including the status, // instance ID, etc. // It gets the information for a specific request (as opposed to all requests). private static async Task<SpotInstanceRequest> GetSpotInstanceRequestInfo( IAmazonEC2 ec2Client, string requestId) { var describeRequest = new DescribeSpotInstanceRequestsRequest(); describeRequest.SpotInstanceRequestIds.Add(requestId); DescribeSpotInstanceRequestsResponse describeResponse = await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest); return describeResponse.SpotInstanceRequests[0]; } // // Method to cancel a Spot Instance request private static async Task CancelSpotInstanceRequest( IAmazonEC2 ec2Client, string requestId) { var cancelRequest = new CancelSpotInstanceRequestsRequest(); cancelRequest.SpotInstanceRequestIds.Add(requestId); await ec2Client.CancelSpotInstanceRequestsAsync(cancelRequest); } // // Method to terminate a Spot Instance private static async Task TerminateSpotInstance( IAmazonEC2 ec2Client, string requestId) { var describeRequest = new DescribeSpotInstanceRequestsRequest(); describeRequest.SpotInstanceRequestIds.Add(requestId); // Retrieve the Spot Instance request to check for running instances. DescribeSpotInstanceRequestsResponse describeResponse = await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest); // If there are any running instances, terminate them if( (describeResponse.SpotInstanceRequests[0].Status.Code == "request-canceled-and-instance-running") || (describeResponse.SpotInstanceRequests[0].State == SpotInstanceState.Active)) { TerminateInstancesResponse response = await ec2Client.TerminateInstancesAsync(new TerminateInstancesRequest{ InstanceIds = new List<string>(){ describeResponse.SpotInstanceRequests[0].InstanceId } }); foreach (InstanceStateChange item in response.TerminatingInstances) { Console.WriteLine($"\n Terminated instance: {item.InstanceId}"); Console.WriteLine($" Instance state: {item.CurrentState.Name}\n"); } } } } }

追加の考慮事項