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

是否要将 .NET 应用程序部署到Amazon通过几个简单点击即可? 尝试我们的新.NET CLI 工具为了简化部署体验!

阅读我们的原创博客文章以及更新帖子发布部署项目. 在上提交反馈GitHub!有关更多信息,请参阅部署工具

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

启动 Amazon EC2 实例

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

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

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

警告

我们将于 2022 年 8 月 15 日停用 EC2-Classic。我们建议您从 EC2-Classic 迁移到 VPC。有关更多信息,请参阅 。从 EC2-Classic 迁移到 VPC中的适用于 Linux 实例的 Amazon EC2 用户指南或者Windows 实例的 Amazon EC2 用户指南. 另请参阅博客帖子EC2-Classic 联网正在停用 — 下面介绍如何准备。.

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

收集你需要的东西

要启动 EC2 实例,您需要几件东西。

  • 一个VPC将在哪里启动实例。如果它是 Windows 实例,并且您将通过 RDP 连接到它,那么 VPC 很可能需要连接到它的互联网网关,以及路由表中互联网网关的条目。有关更多信息,请参阅 。Internet 网关中的Amazon VPC User Guide.

  • VPC 中将在其中启动实例的现有子网的 ID。要找到或创建此项目的简单方法是登录Amazon VPC 控制台,但是你也可以通过使用创建 UBnetAsync描述 ubnetsSync方法。

    注意

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

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

  • 包含上述 EC2 key pair 的私有密钥的 PEM 文件的名称。当你使用 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; }

监控实例

以下代码段将监视实例,直到实例进入 “待处理” 状态。

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

请参阅InstanceState类表示的有效值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 arguments from the parsed list string groupID = CommandLine.GetArgument(parsedArgs, null, "-g", "--group-id"); string ami = CommandLine.GetArgument(parsedArgs, null, "-a", "--ami-id"); string keyPairName = CommandLine.GetArgument(parsedArgs, null, "-k", "--keypair-name"); string subnetID = CommandLine.GetArgument(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: "--key value" or "-k value". // // Parameters: // - args: The command-line arguments passed into the application by the system. // // Returns: // A Dictionary with string Keys and Values. // // If a key is found without a matching value, Dictionary.Value is set to the key // (including the dashes). // If a value is found without a matching key, Dictionary.Key is set to "--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 = key; // Check to see if there's 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 an argument from the parsed command-line arguments // // Parameters: // - parsedArgs: The Dictionary object returned from the Parse() method (shown above). // - defaultValue: The default string to return if the specified key isn't in parsedArgs. // - keys: An array of keys to look for in parsedArgs. public static string GetArgument( Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys) { string retval = null; foreach(var key in keys) if(parsedArgs.TryGetValue(key, out retval)) break; return retval ?? defaultReturn; } // // Method to exit the application 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 用户指南中。

警告

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

NuGet 软件包:

编程元素:

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 arguments from the parsed list string instanceID = CommandLine.GetArgument(parsedArgs, null, "-i", "--instance-id"); string pemFileName = CommandLine.GetArgument(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: EC2GetWindowsPassword -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: "--key value" or "-k value". // // Parameters: // - args: The command-line arguments passed into the application by the system. // // Returns: // A Dictionary with string Keys and Values. // // If a key is found without a matching value, Dictionary.Value is set to the key // (including the dashes). // If a value is found without a matching key, Dictionary.Key is set to "--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 = key; // Check to see if there's 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 an argument from the parsed command-line arguments // // Parameters: // - parsedArgs: The Dictionary object returned from the Parse() method (shown above). // - defaultValue: The default string to return if the specified key isn't in parsedArgs. // - keys: An array of keys to look for in parsedArgs. public static string GetArgument( Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys) { string retval = null; foreach(var key in keys) if(parsedArgs.TryGetValue(key, out retval)) break; return retval ?? defaultReturn; } // // Method to exit the application with an error. public static void ErrorExit(string msg, int code=1) { Console.WriteLine("\nError"); Console.WriteLine(msg); Environment.Exit(code); } } }

清除

当您不再需要 EC2 实例时,请务必终止该实例,如中所述。终止 Amazon EC2 实例.