チュートリアル: Amazon EC2 スポットリクエストの高度な管理 - AWS SDK for Java 1.x

AWS SDK for Java (v1) の近日発表 end-of-support しました。AWS SDK for Java v2 に移行することをお勧めします。日付、その他の詳細、移行方法については、リンク先の発表内容を参照してください。

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

チュートリアル: Amazon EC2 スポットリクエストの高度な管理

Amazon EC2 スポットインスタンスとは、Amazon EC2 の未使用キャパシティに対してお客様から価格を提示していただき、入札値段がその時点のスポット料金を上回っている限り、お客様がインスタンスを実行できるというシステムです。Amazon EC2 のスポット料金は、需要と供給に応じて定期的に変動します。スポットインスタンスの詳細については、Amazon EC2 Linux インスタンス用ユーザーガイドのスポットインスタンスを参照してください。

前提条件

このチュートリアルを使用するには、AWS SDK for Java がインストールされており、基本インストール前提条件を満たしている必要があります。詳細については、「Set up the AWS SDK for Java」を参照してください。

認証情報のセットアップ

このサンプルコードの使用を開始するには、AWS 認証情報を設定する必要があります。その方法については、開発用の AWS 認証情報とリージョンのセットアップを参照してください。

注記

IAM ユーザーの認証情報を使用してこれらの値を指定することをお勧めします。詳細については、AWS にサインアップし、IAM ユーザーを作成するを参照してください。

これで設定が完了したので、例に示すコードを使用できるようになります。

セキュリティグループのセットアップ

セキュリティグループとは、ファイアウォールとしての役割を果たすものであり、インスタンスのグループに対してどのトラフィックの送受信を許可するかを制御します。デフォルトでは、インスタンスの起動時にセキュリティグループは何も設定されていません。つまり、着信 IP トラフィックは、どの TCP ポートであってもすべて拒否されます。したがって、ここでは、スポットリクエストを提出する前に、必要なネットワークトラフィックを許可するセキュリティグループをセットアップすることにします。このチュートリアルの目的に合わせて、ここでは新しいセキュリティグループを「GettingStarted」という名前で作成します。このグループでは、自分のアプリケーションを実行する IP アドレスからの Secure Shell (SSH) トラフィックを許可します。新しいセキュリティグループをセットアップするには、次に示すコードサンプルをインクルードするか実行する必要があります。このコードは、セキュリティグループをプログラムからセットアップするためのものです。

AmazonEC2 クライアントオブジェクトを作成した後で、CreateSecurityGroupRequest オブジェクトを作成し、「GettingStarted」という名前と、セキュリティグループの説明を指定します。その後で、ec2.createSecurityGroup API を呼び出してグループを作成します。

このグループにアクセスできるようにするために、ipPermission オブジェクトを作成します。IP アドレス範囲は、ローカルコンピュータのサブネット (CIDR 表現) で設定します。IP アドレスの「/10」というサフィックスが、指定した IP アドレスのサブネットを示します。また、ipPermission オブジェクトを設定して TCP プロトコルとポート 22 (SSH) を指定します。最後のステップは、ec2 .authorizeSecurityGroupIngress を呼び出すことです。このときに、作成したセキュリティグループの名前と ipPermission オブジェクトを指定します。

(次に示すコードは、最初のチュートリアルで使用したのと同じものです)

// Create the AmazonEC2Client object so we can call various APIs. AmazonEC2 ec2 = AmazonEC2ClientBuilder.standard() .withCredentials(credentials) .build(); // Create a new security group. try { CreateSecurityGroupRequest securityGroupRequest = new CreateSecurityGroupRequest("GettingStartedGroup", "Getting Started Security Group"); ec2.createSecurityGroup(securityGroupRequest); } catch (AmazonServiceException ase) { // Likely this means that the group is already created, so ignore. System.out.println(ase.getMessage()); } String ipAddr = "0.0.0.0/0"; // Get the IP of the current host, so that we can limit the Security Group // by default to the ip range associated with your subnet. try { // Get IP Address InetAddress addr = InetAddress.getLocalHost(); ipAddr = addr.getHostAddress()+"/10"; } catch (UnknownHostException e) { // Fail here... } // Create a range that you would like to populate. ArrayList<String> ipRanges = new ArrayList<String>(); ipRanges.add(ipAddr); // Open up port 22 for TCP traffic to the associated IP from // above (e.g. ssh traffic). ArrayList<IpPermission> ipPermissions = new ArrayList<IpPermission> (); IpPermission ipPermission = new IpPermission(); ipPermission.setIpProtocol("tcp"); ipPermission.setFromPort(new Integer(22)); ipPermission.setToPort(new Integer(22)); ipPermission.setIpRanges(ipRanges); ipPermissions.add(ipPermission); try { // Authorize the ports to the used. AuthorizeSecurityGroupIngressRequest ingressRequest = new AuthorizeSecurityGroupIngressRequest( "GettingStartedGroup",ipPermissions); ec2.authorizeSecurityGroupIngress(ingressRequest); } catch (AmazonServiceException ase) { // Ignore because this likely means the zone has already // been authorized. System.out.println(ase.getMessage()); }

このコードサンプル全体を見るには、advanced.CreateSecurityGroupApp.java コードサンプルを参照してください。このアプリケーションを実行して新しいセキュリティグループを作成する必要があるのは 1 回のみです。

注記

また、AWS Toolkit for Eclipse を使用してセキュリティグループを作成することもできます。詳細については、「AWS Toolkit for Eclipse ユーザーガイド」の「Managing Security Groups from AWS Cost Explorer」を参照してください。

スポットインスタンスリクエスト作成の詳細なオプション

チュートリアル: Amazon EC2 スポットインスタンスで説明したように、リクエストを作成してインスタンスタイプ、Amazon Machine Image (AMI)、および最高入札価格を指定する必要があります。

初めに、RequestSpotInstanceRequest オブジェクトを作成します。このリクエストオブジェクトには、必要なインスタンスの数と入札価格が必要です。さらに、リクエストの LaunchSpecification も設定する必要があります。この内容は、インスタンスタイプ、AMI ID、および使用するセキュリティグループです。リクエストの内容が入力されたら、requestSpotInstances オブジェクトの AmazonEC2Client メソッドを呼び出します。スポットインスタンスをリクエストする方法の例を次に示します。

(次に示すコードは、最初のチュートリアルで使用したのと同じものです)

// Create the AmazonEC2 client so we can call various APIs. AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient(); // Initializes a Spot Instance Request RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest(); // Request 1 x t1.micro instance with a bid price of $0.03. requestRequest.setSpotPrice("0.03"); requestRequest.setInstanceCount(Integer.valueOf(1)); // Set up the specifications of the launch. This includes the // instance type (e.g. t1.micro) and the latest Amazon Linux // AMI id available. Note, you should always use the latest // Amazon Linux AMI id or another of your choosing. LaunchSpecification launchSpecification = new LaunchSpecification(); launchSpecification.setImageId("ami-a9d09ed1"); launchSpecification.setInstanceType(InstanceType.T1Micro); // Add the security group to the request. ArrayList<String> securityGroups = new ArrayList<String>(); securityGroups.add("GettingStartedGroup"); launchSpecification.setSecurityGroups(securityGroups); // Add the launch specification. requestRequest.setLaunchSpecification(launchSpecification); // Call the RequestSpotInstance API. RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest);

永続リクエストと 1 回限りのリクエスト

スポットリクエストを作成するときは、複数の任意パラメータを指定できます。最初のパラメータは、そのリクエストが 1 回限りか持続的なものかを指定するためのものです。デフォルトでは、リクエストは 1 回限りとなります。1 回限りのリクエストが受理されるのは 1 回だけであり、リクエストしたインスタンスが終了すると、そのリクエストはクローズ済みとなります。永続リクエストは、同じリクエストで実行されているスポットインスタンスがない限り、常に受理の対象となります。リクエストのタイプを指定するには、スポットリクエストの Type を設定します。このことを行うコードを次に示します。

// Retrieves the credentials from an AWSCredentials.properties file. AWSCredentials credentials = null; try { credentials = new PropertiesCredentials( GettingStartedApp.class.getResourceAsStream("AwsCredentials.properties")); } catch (IOException e1) { System.out.println( "Credentials were not properly entered into AwsCredentials.properties."); System.out.println(e1.getMessage()); System.exit(-1); } // Create the AmazonEC2 client so we can call various APIs. AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient(); // Initializes a Spot Instance Request RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest(); // Request 1 x t1.micro instance with a bid price of $0.03. requestRequest.setSpotPrice("0.03"); requestRequest.setInstanceCount(Integer.valueOf(1)); // Set the type of the bid to persistent. requestRequest.setType("persistent"); // Set up the specifications of the launch. This includes the // instance type (e.g. t1.micro) and the latest Amazon Linux // AMI id available. Note, you should always use the latest // Amazon Linux AMI id or another of your choosing. LaunchSpecification launchSpecification = new LaunchSpecification(); launchSpecification.setImageId("ami-a9d09ed1"); launchSpecification.setInstanceType(InstanceType.T1Micro); // Add the security group to the request. ArrayList<String> securityGroups = new ArrayList<String>(); securityGroups.add("GettingStartedGroup"); launchSpecification.setSecurityGroups(securityGroups); // Add the launch specification. requestRequest.setLaunchSpecification(launchSpecification); // Call the RequestSpotInstance API. RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest);

リクエストの期間の制限

また、リクエストの有効期間もオプションで指定できます。その期間の開始時点と終了時点の両方を指定できます。デフォルトでは、スポットリクエストが受理の対象とみなされるのは、作成された時点から、そのリクエストが受理されるか作成者によってキャンセルされるまでの間となります。ただし、必要であれば、作成時に有効期間を指定できます。この期間を指定する方法の例を次のコードに示します。

// Create the AmazonEC2 client so we can call various APIs. AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient(); // Initializes a Spot Instance Request RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest(); // Request 1 x t1.micro instance with a bid price of $0.03. requestRequest.setSpotPrice("0.03"); requestRequest.setInstanceCount(Integer.valueOf(1)); // Set the valid start time to be two minutes from now. Calendar cal = Calendar.getInstance(); cal.add(Calendar.MINUTE, 2); requestRequest.setValidFrom(cal.getTime()); // Set the valid end time to be two minutes and two hours from now. cal.add(Calendar.HOUR, 2); requestRequest.setValidUntil(cal.getTime()); // Set up the specifications of the launch. This includes // the instance type (e.g. t1.micro) // and the latest Amazon Linux AMI id available. // Note, you should always use the latest Amazon // Linux AMI id or another of your choosing. LaunchSpecification launchSpecification = new LaunchSpecification(); launchSpecification.setImageId("ami-a9d09ed1"); launchSpecification.setInstanceType("t1.micro"); // Add the security group to the request. ArrayList<String> securityGroups = new ArrayList<String>(); securityGroups.add("GettingStartedGroup"); launchSpecification.setSecurityGroups(securityGroups); // Add the launch specification. requestRequest.setLaunchSpecification(launchSpecification); // Call the RequestSpotInstance API. RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest);

Amazon EC2 スポットインスタンスリクエストのグループ化

スポットインスタンスリクエストには、いくつか異なる方法でグループ化するオプションがあります。ここでは、起動グループ、アベイラビリティーゾーングループ、およびプレイスメントグループの利点について説明します。

リクエストしたスポットインスタンスがすべて同時に起動され、同時に終了するようにしたい場合は、起動グループを利用します。起動グループとは、1 つにまとめる入札のグループに付けられるラベルです。同じ起動グループ内のインスタンスはすべて、同時に起動されて同時に終了します。なお、起動グループ内のインスタンスが受理済みの場合に、その同じ起動グループで起動される新しいインスタンスも受理されるという保証はありません。起動グループを設定する方法の例を次のコードサンプルで示します。

// Create the AmazonEC2 client so we can call various APIs. AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient(); // Initializes a Spot Instance Request RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest(); // Request 5 x t1.micro instance with a bid price of $0.03. requestRequest.setSpotPrice("0.03"); requestRequest.setInstanceCount(Integer.valueOf(5)); // Set the launch group. requestRequest.setLaunchGroup("ADVANCED-DEMO-LAUNCH-GROUP"); // Set up the specifications of the launch. This includes // the instance type (e.g. t1.micro) and the latest Amazon Linux // AMI id available. Note, you should always use the latest // Amazon Linux AMI id or another of your choosing. LaunchSpecification launchSpecification = new LaunchSpecification(); launchSpecification.setImageId("ami-a9d09ed1"); launchSpecification.setInstanceType(InstanceType.T1Micro); // Add the security group to the request. ArrayList<String> securityGroups = new ArrayList<String>(); securityGroups.add("GettingStartedGroup"); launchSpecification.setSecurityGroups(securityGroups); // Add the launch specification. requestRequest.setLaunchSpecification(launchSpecification); // Call the RequestSpotInstance API. RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest);

1 つのリクエスト内のすべてのインスタンスが同じアベイラビリティーゾーン内で起動されるようにする必要があるが、どのアベイラビリティーゾーンでもかまわない場合は、アベイラビリティーゾーングループを利用します。アベイラビリティーゾーングループとは、同じアベイラビリティーゾーンにまとめるインスタンスのグループに付けられるラベルです。同じアベイラビリティーゾーングループに属し、同時に受理されたインスタンスはすべて、同じアベイラビリティーゾーンで起動されます。アベイラビリティーゾーングループを設定する方法の例を次に示します。

// Create the AmazonEC2 client so we can call various APIs. AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient(); // Initializes a Spot Instance Request RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest(); // Request 5 x t1.micro instance with a bid price of $0.03. requestRequest.setSpotPrice("0.03"); requestRequest.setInstanceCount(Integer.valueOf(5)); // Set the availability zone group. requestRequest.setAvailabilityZoneGroup("ADVANCED-DEMO-AZ-GROUP"); // Set up the specifications of the launch. This includes the instance // type (e.g. t1.micro) and the latest Amazon Linux AMI id available. // Note, you should always use the latest Amazon Linux AMI id or another // of your choosing. LaunchSpecification launchSpecification = new LaunchSpecification(); launchSpecification.setImageId("ami-a9d09ed1"); launchSpecification.setInstanceType(InstanceType.T1Micro); // Add the security group to the request. ArrayList<String> securityGroups = new ArrayList<String>(); securityGroups.add("GettingStartedGroup"); launchSpecification.setSecurityGroups(securityGroups); // Add the launch specification. requestRequest.setLaunchSpecification(launchSpecification); // Call the RequestSpotInstance API. RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest);

リクエストするスポットインスタンスをどのアベイラビリティーゾーンで起動したいかを指定できます。次のコードサンプルでは、アベイラビリティーゾーンの設定方法を示します。

// Create the AmazonEC2 client so we can call various APIs. AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient(); // Initializes a Spot Instance Request RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest(); // Request 1 x t1.micro instance with a bid price of $0.03. requestRequest.setSpotPrice("0.03"); requestRequest.setInstanceCount(Integer.valueOf(1)); // Set up the specifications of the launch. This includes the instance // type (e.g. t1.micro) and the latest Amazon Linux AMI id available. // Note, you should always use the latest Amazon Linux AMI id or another // of your choosing. LaunchSpecification launchSpecification = new LaunchSpecification(); launchSpecification.setImageId("ami-a9d09ed1"); launchSpecification.setInstanceType(InstanceType.T1Micro); // Add the security group to the request. ArrayList<String> securityGroups = new ArrayList<String>(); securityGroups.add("GettingStartedGroup"); launchSpecification.setSecurityGroups(securityGroups); // Set up the availability zone to use. Note we could retrieve the // availability zones using the ec2.describeAvailabilityZones() API. For // this demo we will just use us-east-1a. SpotPlacement placement = new SpotPlacement("us-east-1b"); launchSpecification.setPlacement(placement); // Add the launch specification. requestRequest.setLaunchSpecification(launchSpecification); // Call the RequestSpotInstance API. RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest);

最後のプレイスメントグループは、ハイパフォーマンスコンピューティング (HPC) スポットインスタンス (クラスターコンピュートインスタンスやクラスター GPU インスタンスなど) を使用する場合に指定できます。プレイスメントグループを利用すると、低レイテンシー、高帯域幅でインスタンス間を接続できます。プレイスメントグループを設定する方法の例を次に示します。

// Create the AmazonEC2 client so we can call various APIs. AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient(); // Initializes a Spot Instance Request RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest(); // Request 1 x t1.micro instance with a bid price of $0.03. requestRequest.setSpotPrice("0.03"); requestRequest.setInstanceCount(Integer.valueOf(1)); // Set up the specifications of the launch. This includes the instance // type (e.g. t1.micro) and the latest Amazon Linux AMI id available. // Note, you should always use the latest Amazon Linux AMI id or another // of your choosing. LaunchSpecification launchSpecification = new LaunchSpecification(); launchSpecification.setImageId("ami-a9d09ed1"); launchSpecification.setInstanceType(InstanceType.T1Micro); // Add the security group to the request. ArrayList<String> securityGroups = new ArrayList<String>(); securityGroups.add("GettingStartedGroup"); launchSpecification.setSecurityGroups(securityGroups); // Set up the placement group to use with whatever name you desire. // For this demo we will just use "ADVANCED-DEMO-PLACEMENT-GROUP". SpotPlacement placement = new SpotPlacement(); placement.setGroupName("ADVANCED-DEMO-PLACEMENT-GROUP"); launchSpecification.setPlacement(placement); // Add the launch specification. requestRequest.setLaunchSpecification(launchSpecification); // Call the RequestSpotInstance API. RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest);

このセクションで示したパラメータはいずれも、省略可能です。また、これらのパラメータのほとんど (入札が 1 回限りであるか永続的であるかを除く) により、入札が履行される可能性を低減できることを理解することも重要です。したがって、これらのオプションは、そのオプションが必要な場合に限って使用することが重要です。これまでに示したコード例すべてを 1 つにまとめたものが com.amazonaws.codesamples.advanced.InlineGettingStartedCodeSampleApp.java クラスの中にあります。

中断または終了の後もルートパーティションを永続化する方法

スポットインスタンスの中断を管理する最も簡単な方法は、データのチェックポイントを作成して Amazon Elastic Block Store (Amazon Amazon EBS) ボリュームに保存するという処理を定期的に行うことです。チェックポイントを定期的に作成しておくと、中断が発生したときでも、データが失われるのは最後のチェックポイント以降に作成された分だけになります(その間に他の非べき等アクションが実行されていないことを前提とします)。このプロセスを容易にするには、スポットリクエストを設定するときに、中断時や終了時にルートパーティションを削除しないことを指定します。このシナリオを実現する方法を示す新しいコードが、次の例に挿入されています。

追加されたコードの中では、BlockDeviceMapping オブジェクトを作成し、対応する Amazon Elastic Block Store (Amazon EBS) を Amazon EBS オブジェクトに設定しています (このオブジェクトは、スポットインスタンスが終了しても削除しない (not) よう設定済みです)。その後で、この BlockDeviceMapping をマッピングの ArrayList に追加し、起動指定の中でこのマッピングを指定します。

// Retrieves the credentials from an AWSCredentials.properties file. AWSCredentials credentials = null; try { credentials = new PropertiesCredentials( GettingStartedApp.class.getResourceAsStream("AwsCredentials.properties")); } catch (IOException e1) { System.out.println( "Credentials were not properly entered into AwsCredentials.properties."); System.out.println(e1.getMessage()); System.exit(-1); } // Create the AmazonEC2 client so we can call various APIs. AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient(); // Initializes a Spot Instance Request RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest(); // Request 1 x t1.micro instance with a bid price of $0.03. requestRequest.setSpotPrice("0.03"); requestRequest.setInstanceCount(Integer.valueOf(1)); // Set up the specifications of the launch. This includes the instance // type (e.g. t1.micro) and the latest Amazon Linux AMI id available. // Note, you should always use the latest Amazon Linux AMI id or another // of your choosing. LaunchSpecification launchSpecification = new LaunchSpecification(); launchSpecification.setImageId("ami-a9d09ed1"); launchSpecification.setInstanceType(InstanceType.T1Micro); // Add the security group to the request. ArrayList<String> securityGroups = new ArrayList<String>(); securityGroups.add("GettingStartedGroup"); launchSpecification.setSecurityGroups(securityGroups); // Create the block device mapping to describe the root partition. BlockDeviceMapping blockDeviceMapping = new BlockDeviceMapping(); blockDeviceMapping.setDeviceName("/dev/sda1"); // Set the delete on termination flag to false. EbsBlockDevice ebs = new EbsBlockDevice(); ebs.setDeleteOnTermination(Boolean.FALSE); blockDeviceMapping.setEbs(ebs); // Add the block device mapping to the block list. ArrayList<BlockDeviceMapping> blockList = new ArrayList<BlockDeviceMapping>(); blockList.add(blockDeviceMapping); // Set the block device mapping configuration in the launch specifications. launchSpecification.setBlockDeviceMappings(blockList); // Add the launch specification. requestRequest.setLaunchSpecification(launchSpecification); // Call the RequestSpotInstance API. RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest);

このボリュームがインスタンスの起動時に再度接続されるようにしたい場合は、ブロックデバイスマッピング設定を使用することもできます。別の方法としては、ルート以外のパーティションを接続する場合に、どの Amazon Amazon EBS ボリュームをスポットインスタンス再開後にインスタンスに接続するかを指定できます。このようにするには、スナップショット ID を EbsBlockDevice オブジェクトで指定し、代替デバイス名を BlockDeviceMapping オブジェクトで指定します。ブロックデバイスマッピングを利用すると、インスタンスのブートストラップが容易になります。

ルートパーティションを使用して重要なデータのチェックポイントを作成しておくと、インスタンスの中断の可能性を管理するうえで大いに役立ちます。中断の可能性を管理するその他の方法については、中断の管理についての動画をご覧ください。

スポットリクエストとインスタンスにタグを付加する方法

Amazon EC2 リソースにタグを追加すると、クラウドインフラストラクチャの管理を簡略化できます。タグとは、メタデータの形を取るものであり、わかりやすい名前を付けるのに使用できます。また、検索がしやすくなり、複数ユーザー間での共同作業にも役立ちます。タグは、プロセスのスクリプトや各部分の自動化にも使用できます。Amazon EC2 リソースのタグ付けの詳細については、Amazon EC2 Linux インスタンス用ユーザーガイドのタグの使用を参照してください。

リクエストのタグ付け

使用するスポットリクエストにタグを追加するには、リソースをリクエストした後でタグを付ける必要があります。requestSpotInstances() からの戻り値によって、タグ付けのためのスポットリクエスト ID を取得する際に使用できる RequestSpotInstancesResult オブジェクトが提供されます。

// Call the RequestSpotInstance API. RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest); List<SpotInstanceRequest> requestResponses = requestResult.getSpotInstanceRequests(); // A list of request IDs to tag ArrayList<String> spotInstanceRequestIds = new ArrayList<String>(); // Add the request ids to the hashset, so we can determine when they hit the // active state. for (SpotInstanceRequest requestResponse : requestResponses) { System.out.println("Created Spot Request: "+requestResponse.getSpotInstanceRequestId()); spotInstanceRequestIds.add(requestResponse.getSpotInstanceRequestId()); }

ID を取得したら、CreateTagsRequest に ID を追加し、Amazon EC2 クライアントの createTags() メソッドを呼び出してリクエストにタグを追加できます。

// The list of tags to create ArrayList<Tag> requestTags = new ArrayList<Tag>(); requestTags.add(new Tag("keyname1","value1")); // Create the tag request CreateTagsRequest createTagsRequest_requests = new CreateTagsRequest(); createTagsRequest_requests.setResources(spotInstanceRequestIds); createTagsRequest_requests.setTags(requestTags); // Tag the spot request try { ec2.createTags(createTagsRequest_requests); } catch (AmazonServiceException e) { System.out.println("Error terminating instances"); System.out.println("Caught Exception: " + e.getMessage()); System.out.println("Reponse Status Code: " + e.getStatusCode()); System.out.println("Error Code: " + e.getErrorCode()); System.out.println("Request ID: " + e.getRequestId()); }

インスタンスにタグを付ける

同様に、スポットリクエスト自体に対し、インスタンスの作成後 1 つのインスタンスのみにタグを追加でき、またそのタグはスポットリクエストに一致する場合のみ追加されます (オープン状態ではなくなります)。

Amazon EC2 クライアントの describeSpotInstanceRequests()メソッドを DescribeSpotInstanceRequestsRequest オブジェクトとともに呼び出し、リクエストのステータスを確認できます。返される DescribeSpotInstanceRequestsResult オブジェクトには、スポットリクエストのステータスをクエリし、open 状態でなくなったときにインスタンス ID を取得するために使用できる SpotInstanceRequest オブジェクトのリストが含まれています。

スポットリクエストがオープン状態でなくなると、getInstanceId() メソッドを呼び出すことで、そのインスタンス ID を SpotInstanceRequest オブジェクトから取得できます。

boolean anyOpen; // tracks whether any requests are still open // a list of instances to tag. ArrayList<String> instanceIds = new ArrayList<String>(); do { DescribeSpotInstanceRequestsRequest describeRequest = new DescribeSpotInstanceRequestsRequest(); describeRequest.setSpotInstanceRequestIds(spotInstanceRequestIds); anyOpen=false; // assume no requests are still open try { // Get the requests to monitor DescribeSpotInstanceRequestsResult describeResult = ec2.describeSpotInstanceRequests(describeRequest); List<SpotInstanceRequest> describeResponses = describeResult.getSpotInstanceRequests(); // are any requests open? for (SpotInstanceRequest describeResponse : describeResponses) { if (describeResponse.getState().equals("open")) { anyOpen = true; break; } // get the corresponding instance ID of the spot request instanceIds.add(describeResponse.getInstanceId()); } } catch (AmazonServiceException e) { // Don't break the loop due to an exception (it may be a temporary issue) anyOpen = true; } try { Thread.sleep(60*1000); // sleep 60s. } catch (Exception e) { // Do nothing if the thread woke up early. } } while (anyOpen);

ここで、返されるインスタンスにタグを追加できます。

// Create a list of tags to create ArrayList<Tag> instanceTags = new ArrayList<Tag>(); instanceTags.add(new Tag("keyname1","value1")); // Create the tag request CreateTagsRequest createTagsRequest_instances = new CreateTagsRequest(); createTagsRequest_instances.setResources(instanceIds); createTagsRequest_instances.setTags(instanceTags); // Tag the instance try { ec2.createTags(createTagsRequest_instances); } catch (AmazonServiceException e) { // Write out any exceptions that may have occurred. System.out.println("Error terminating instances"); System.out.println("Caught Exception: " + e.getMessage()); System.out.println("Reponse Status Code: " + e.getStatusCode()); System.out.println("Error Code: " + e.getErrorCode()); System.out.println("Request ID: " + e.getRequestId()); }

スポットリクエストのキャンセルとインスタンスの削除

スポットリクエストのキャンセル

スポットインスタンスリクエストをキャンセルするには、Amazon EC2 クライアントの cancelSpotInstanceRequestsCancelSpotInstanceRequestsRequest オブジェクトとともに呼び出します。

try { CancelSpotInstanceRequestsRequest cancelRequest = new CancelSpotInstanceRequestsRequest(spotInstanceRequestIds); ec2.cancelSpotInstanceRequests(cancelRequest); } catch (AmazonServiceException e) { System.out.println("Error cancelling instances"); System.out.println("Caught Exception: " + e.getMessage()); System.out.println("Reponse Status Code: " + e.getStatusCode()); System.out.println("Error Code: " + e.getErrorCode()); System.out.println("Request ID: " + e.getRequestId()); }

スポットインスタンスの削除

Amazon EC2 クライアントの terminateInstances() メソッドに ID を渡すことで、実行中のすべてのスポットインスタンスを終了できます。

try { TerminateInstancesRequest terminateRequest = new TerminateInstancesRequest(instanceIds); ec2.terminateInstances(terminateRequest); } catch (AmazonServiceException e) { System.out.println("Error terminating instances"); System.out.println("Caught Exception: " + e.getMessage()); System.out.println("Reponse Status Code: " + e.getStatusCode()); System.out.println("Error Code: " + e.getErrorCode()); System.out.println("Request ID: " + e.getRequestId()); }

ステップの集約

これまでに説明したステップは、よりオブジェクト指向的なアプローチをとって 1 つのクラスに集約し、利便性を高めることができます。Requests という名前のクラスをインスタンス化すると、これらのアクションを実行できます。さらに、GettingStartedApp というクラスも作成します。ここにメインメソッドがあり、ここで高レベルの関数呼び出しを実行します。

この例の完全なソースコードは、GitHub で確認またはダウンロードできます。

お疲れ様でした。これで、AWS SDK for Java を使用してスポットインスタンスソフトウェアを開発するための、高度なリクエスト機能のチュートリアルは終了です。