启动 Amazon EC2 实例 - Amazon SDK for .NET
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 Amazon Web Services 服务入门

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

启动 Amazon EC2 实例

此示例向您演示如何使用Amazon SDK for .NET从同一个 Amazon 系统映像 (AMI) 启动一个或多个具有相同配置的 Amazon EC2 实例。使用几个输入,应用程序将启动 EC2 实例,然后监控该实例,直到它处于 “挂起” 状态。

当 EC2 实例正在运行时,您可以远程连接到该实例,如(可选)Connect 到实例

您可以在 VPC 或 EC2-Classic 中启动 EC2 实例(如果您的Amazon帐户支持此操作)。有关 VPC 中的 EC2 与 EC2-Classic 的更多信息,请参阅Linux 的 EC2 用户指南适用于 Windows 的 EC2 用户指南

以下部分提供了本示例的代码片段和其他信息。这些区域有:示例的完整代码显示在片段后面,并且可以按原样构建和运行。

收集您需要的内容

要启动 EC2 实例,您需要几个操作。

  • AVPC实例将在其中启动。如果它将是一个 Windows 实例,并且您将通过 RDP 连接到它,则 VPC 很可能需要连接一个 Internet 网关,并在路由表中为互联网网关添加一个条目。有关更多信息,请参阅 。Internet 网关中的Amazon VPC 用户指南

  • 将在其中启动实例的 VPC 中现有子网的 ID。找到或创建此信息的简单方法是登录Amazon VPC 控制台,但您也可以通过使用创建子网异步描述外联网异步方法。

    注意

    如果您的Amazon帐户支持 EC2-Classic,这是您要启动的实例类型,此参数不是必需的。但是,如果您的账户不支持 EC2-Classic 并且您不提供此参数,则新实例将在您账户的默认 VPC 中启动。

  • 如果要连接到新实例,则前面提到的安全组必须具有适当的入站规则,该规则允许端口 22 上的 SSH 流量(Linux 实例)或端口 3389 上的 RDP 流量(Windows 实例)。有关如何执行此操作的信息,请参阅更新安全组,包括其他注意事项接近该主题的末尾。

  • PEM 文件的名称,该文件包含前面提到的 EC2 key pair 的私有密钥。PEM 文件用于远程连接添加到实例。

启动 实例

以下代码段启动 EC2 实例。

示例接近本主题末尾显示了这个正在使用的代码片段。

// // Method to launch the instances // Returns a list with the launched instance IDs private static async Task<List<string>> LaunchInstances( IAmazonEC2 ec2Client, RunInstancesRequest requestLaunch) { var instanceIds = new List<string>(); RunInstancesResponse responseLaunch = await ec2Client.RunInstancesAsync(requestLaunch); Console.WriteLine("\nNew instances have been created."); foreach (Instance item in responseLaunch.Reservation.Instances) { instanceIds.Add(item.InstanceId); Console.WriteLine($" New instance: {item.InstanceId}"); } return instanceIds; }

监控实例

以下代码段监视实例,直到实例处于 “挂起” 状态。

示例接近本主题末尾显示了这个正在使用的代码片段。

请参阅实例状态类的有效值Instance.State.Code属性。

// // Method to wait until the instances are running (or at least not pending) private static async Task CheckState(IAmazonEC2 ec2Client, List<string> instanceIds) { Console.WriteLine( "\nWaiting for the instances to start." + "\nPress any key to stop waiting. (Response might be slightly delayed.)"); int numberRunning; DescribeInstancesResponse responseDescribe; var requestDescribe = new DescribeInstancesRequest{ InstanceIds = instanceIds}; // Check every couple of seconds int wait = 2000; while(true) { // Get and check the status for each of the instances to see if it's past pending. // Once all instances are past pending, break out. // (For this example, we are assuming that there is only one reservation.) Console.Write("."); numberRunning = 0; responseDescribe = await ec2Client.DescribeInstancesAsync(requestDescribe); foreach(Instance i in responseDescribe.Reservations[0].Instances) { // Check the lower byte of State.Code property // Code == 0 is the pending state if((i.State.Code & 255) > 0) numberRunning++; } if(numberRunning == responseDescribe.Reservations[0].Instances.Count) break; // Wait a bit and try again (unless the user wants to stop waiting) Thread.Sleep(wait); if(Console.KeyAvailable) break; } Console.WriteLine("\nNo more instances are pending."); foreach(Instance i in responseDescribe.Reservations[0].Instances) { Console.WriteLine($"For {i.InstanceId}:"); Console.WriteLine($" VPC ID: {i.VpcId}"); Console.WriteLine($" Instance state: {i.State.Name}"); Console.WriteLine($" Public IP address: {i.PublicIpAddress}"); Console.WriteLine($" Public DNS name: {i.PublicDnsName}"); Console.WriteLine($" Key pair name: {i.KeyName}"); } }

代码完成

本节显示了此示例的相关参考和完整代码。

using System; using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; using Amazon.EC2; using Amazon.EC2.Model; namespace EC2LaunchInstance { // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // Class to launch an EC2 instance class Program { static async Task Main(string[] args) { // Parse the command line and show help if necessary var parsedArgs = CommandLine.Parse(args); if(parsedArgs.Count == 0) { PrintHelp(); return; } // Get the application parameters from the parsed arguments string groupID = CommandLine.GetParameter(parsedArgs, null, "-g", "--group-id"); string ami = CommandLine.GetParameter(parsedArgs, null, "-a", "--ami-id"); string keyPairName = CommandLine.GetParameter(parsedArgs, null, "-k", "--keypair-name"); string subnetID = CommandLine.GetParameter(parsedArgs, null, "-s", "--subnet-id"); if( (string.IsNullOrEmpty(groupID) || !groupID.StartsWith("sg-")) || (string.IsNullOrEmpty(ami) || !ami.StartsWith("ami-")) || (string.IsNullOrEmpty(keyPairName)) || (!string.IsNullOrEmpty(subnetID) && !subnetID.StartsWith("subnet-"))) CommandLine.ErrorExit( "\nOne or more of the required arguments is missing or incorrect." + "\nRun the command with no arguments to see help."); // Create an EC2 client var ec2Client = new AmazonEC2Client(); // Create an object with the necessary properties RunInstancesRequest request = GetRequestData(groupID, ami, keyPairName, subnetID); // Launch the instances and wait for them to start running var instanceIds = await LaunchInstances(ec2Client, request); await CheckState(ec2Client, instanceIds); } // // Method to put together the properties needed to launch the instance. private static RunInstancesRequest GetRequestData( string groupID, string ami, string keyPairName, string subnetID) { // Common properties var groupIDs = new List<string>() { groupID }; var request = new RunInstancesRequest() { // The first three of these would be additional command-line arguments or similar. InstanceType = InstanceType.T1Micro, MinCount = 1, MaxCount = 1, ImageId = ami, KeyName = keyPairName }; // Properties specifically for EC2 in a VPC. if(!string.IsNullOrEmpty(subnetID)) { request.NetworkInterfaces = new List<InstanceNetworkInterfaceSpecification>() { new InstanceNetworkInterfaceSpecification() { DeviceIndex = 0, SubnetId = subnetID, Groups = groupIDs, AssociatePublicIpAddress = true } }; } // Properties specifically for EC2-Classic else { request.SecurityGroupIds = groupIDs; } return request; } // // Method to launch the instances // Returns a list with the launched instance IDs private static async Task<List<string>> LaunchInstances( IAmazonEC2 ec2Client, RunInstancesRequest requestLaunch) { var instanceIds = new List<string>(); RunInstancesResponse responseLaunch = await ec2Client.RunInstancesAsync(requestLaunch); Console.WriteLine("\nNew instances have been created."); foreach (Instance item in responseLaunch.Reservation.Instances) { instanceIds.Add(item.InstanceId); Console.WriteLine($" New instance: {item.InstanceId}"); } return instanceIds; } // // Method to wait until the instances are running (or at least not pending) private static async Task CheckState(IAmazonEC2 ec2Client, List<string> instanceIds) { Console.WriteLine( "\nWaiting for the instances to start." + "\nPress any key to stop waiting. (Response might be slightly delayed.)"); int numberRunning; DescribeInstancesResponse responseDescribe; var requestDescribe = new DescribeInstancesRequest{ InstanceIds = instanceIds}; // Check every couple of seconds int wait = 2000; while(true) { // Get and check the status for each of the instances to see if it's past pending. // Once all instances are past pending, break out. // (For this example, we are assuming that there is only one reservation.) Console.Write("."); numberRunning = 0; responseDescribe = await ec2Client.DescribeInstancesAsync(requestDescribe); foreach(Instance i in responseDescribe.Reservations[0].Instances) { // Check the lower byte of State.Code property // Code == 0 is the pending state if((i.State.Code & 255) > 0) numberRunning++; } if(numberRunning == responseDescribe.Reservations[0].Instances.Count) break; // Wait a bit and try again (unless the user wants to stop waiting) Thread.Sleep(wait); if(Console.KeyAvailable) break; } Console.WriteLine("\nNo more instances are pending."); foreach(Instance i in responseDescribe.Reservations[0].Instances) { Console.WriteLine($"For {i.InstanceId}:"); Console.WriteLine($" VPC ID: {i.VpcId}"); Console.WriteLine($" Instance state: {i.State.Name}"); Console.WriteLine($" Public IP address: {i.PublicIpAddress}"); Console.WriteLine($" Public DNS name: {i.PublicDnsName}"); Console.WriteLine($" Key pair name: {i.KeyName}"); } } // // Command-line help private static void PrintHelp() { Console.WriteLine( "\nUsage: EC2LaunchInstance -g <group-id> -a <ami-id> -k <keypair-name> [-s <subnet-id>]" + "\n -g, --group-id: The ID of the security group." + "\n -a, --ami-id: The ID of an Amazon Machine Image." + "\n -k, --keypair-name - The name of a key pair." + "\n -s, --subnet-id: The ID of a subnet. Required only for EC2 in a VPC."); } } // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // Class that represents a command line on the console or terminal. // (This is the same for all examples. When you have seen it once, you can ignore it.) static class CommandLine { // Method to parse a command line of the form: "--param value" or "-p value". // If "param" is found without a matching "value", Dictionary.Value is an empty string. // If "value" is found without a matching "param", Dictionary.Key is "--NoKeyN" // where "N" represents sequential numbers. public static Dictionary<string,string> Parse(string[] args) { var parsedArgs = new Dictionary<string,string>(); int i = 0, n = 0; while(i < args.Length) { // If the first argument in this iteration starts with a dash it's an option. if(args[i].StartsWith("-")) { var key = args[i++]; var value = string.Empty; // Is there a value that goes with this option? if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++]; parsedArgs.Add(key, value); } // If the first argument in this iteration doesn't start with a dash, it's a value else { parsedArgs.Add("--NoKey" + n.ToString(), args[i++]); n++; } } return parsedArgs; } // // Method to get a parameter from the parsed command-line arguments public static string GetParameter( Dictionary<string,string> parsedArgs, string def, params string[] keys) { string retval = null; foreach(var key in keys) if(parsedArgs.TryGetValue(key, out retval)) break; return retval ?? def; } // // Exit with an error. public static void ErrorExit(string msg, int code=1) { Console.WriteLine("\nError"); Console.WriteLine(msg); Environment.Exit(code); } } }

其他注意事项

  • 检查 EC2 实例的状态时,您可以将筛选器添加到Filter属性DescribeInstancesRequest对象。使用此方法,您可将请求限制于某些实例,例如具有特定用户指定标签的实例。

  • 为了简洁起见,一些属性被赋予了典型值。可以通过编程方式或用户输入来确定这些属性中的任何或所有属性。

(可选)Connect 到实例

在实例运行之后,您可以通过使用相应的远程客户端远程连接到该实例。对于 Linux 和 Windows 实例,您需要实例的公有 IP 地址或公有 DNS 名称。您还需要以下内容。

对于 Linux 实例

您可以使用 SSH 客户端连接到 Linux 实例。确保您在启动实例时使用的安全组允许端口 22 上的 SSH 流量,如更新安全组

您还需要启动实例所用 key pair 的私有部分,即 PEM 文件。

有关更多信息,请参阅 。连接到您的 Linux 实例适用于 Linux 实例的 Amazon EC2 用户指南中的。

对于 Windows 实例

您可以使用 RDP 客户端连接到实例。确保您在启动实例时使用的安全组允许端口 3389 上的 RDP 流量,如更新安全组

您还需要管理员密码。您可以通过使用以下示例代码获取此项,该代码需要实例 ID 和启动实例所用 key pair 的私有部分,即 PEM 文件。

有关更多信息,请参阅 。连接到 Windows 实例适用于 Windows 实例的 Amazon EC2 用户指南中的。

警告

此示例代码返回实例的明文管理员密码。

using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Amazon.EC2; using Amazon.EC2.Model; namespace EC2GetWindowsPassword { // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // Class to get the Administrator password of a Windows EC2 instance class Program { static async Task Main(string[] args) { // Parse the command line and show help if necessary var parsedArgs = CommandLine.Parse(args); if(parsedArgs.Count == 0) { PrintHelp(); return; } // Get the application parameters from the parsed arguments string instanceID = CommandLine.GetParameter(parsedArgs, null, "-i", "--instance-id"); string pemFileName = CommandLine.GetParameter(parsedArgs, null, "-p", "--pem-filename"); if( (string.IsNullOrEmpty(instanceID) || !instanceID.StartsWith("i-")) || (string.IsNullOrEmpty(pemFileName) || !pemFileName.EndsWith(".pem"))) CommandLine.ErrorExit( "\nOne or more of the required arguments is missing or incorrect." + "\nRun the command with no arguments to see help."); // Create the EC2 client var ec2Client = new AmazonEC2Client(); // Get and display the password string password = await GetPassword(ec2Client, instanceID, pemFileName); Console.WriteLine($"\nPassword: {password}"); } // // Method to get the administrator password of a Windows EC2 instance private static async Task<string> GetPassword( IAmazonEC2 ec2Client, string instanceID, string pemFilename) { string password = string.Empty; GetPasswordDataResponse response = await ec2Client.GetPasswordDataAsync(new GetPasswordDataRequest{ InstanceId = instanceID}); if(response.PasswordData != null) { password = response.GetDecryptedPassword(File.ReadAllText(pemFilename)); } else { Console.WriteLine($"\nThe password is not available for instance {instanceID}."); Console.WriteLine($"If this is a Windows instance, the password might not be ready."); } return password; } // // Command-line help private static void PrintHelp() { Console.WriteLine( "\nUsage: EC2CreateKeyPair -i <instance-id> -p pem-filename" + "\n -i, --instance-id: The name of the EC2 instance." + "\n -p, --pem-filename: The name of the PEM file with the private key."); } } // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // Class that represents a command line on the console or terminal. // (This is the same for all examples. When you have seen it once, you can ignore it.) static class CommandLine { // Method to parse a command line of the form: "--param value" or "-p value". // If "param" is found without a matching "value", Dictionary.Value is an empty string. // If "value" is found without a matching "param", Dictionary.Key is "--NoKeyN" // where "N" represents sequential numbers. public static Dictionary<string,string> Parse(string[] args) { var parsedArgs = new Dictionary<string,string>(); int i = 0, n = 0; while(i < args.Length) { // If the first argument in this iteration starts with a dash it's an option. if(args[i].StartsWith("-")) { var key = args[i++]; var value = string.Empty; // Is there a value that goes with this option? if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++]; parsedArgs.Add(key, value); } // If the first argument in this iteration doesn't start with a dash, it's a value else { parsedArgs.Add("--NoKey" + n.ToString(), args[i++]); n++; } } return parsedArgs; } // // Method to get a parameter from the parsed command-line arguments public static string GetParameter( Dictionary<string,string> parsedArgs, string def, params string[] keys) { string retval = null; foreach(var key in keys) if(parsedArgs.TryGetValue(key, out retval)) break; return retval ?? def; } // // Exit with an error. public static void ErrorExit(string msg, int code=1) { Console.WriteLine("\nError"); Console.WriteLine(msg); Environment.Exit(code); } } }

清除

如果您不再需要 EC2 实例,请确保终止该实例,如终止 Amazon EC2 实例