本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
啟動 Amazon EC2 執行個體
此範例示範如何使用 AWS SDK for .NET ,從相同的 Amazon Machine Image (EC2) 啟動一或多個相同設定的 Amazon AMI 執行個體。使用您提供的數個輸入,應用程式會啟動 EC2 執行個體,然後監控執行個體,直到其處於「待定」狀態為止。
當您的 EC2 執行個體執行時,您可以遠端連線到它,如 中所述(選用) 連線至執行個體。
警告
EC2-Classic 已於 2022 年 8 月 15 日淘汰。建議您從 EC2-Classic 遷移至 VPC。如需詳細資訊,請參閱部落格文章 EC2-Classic Networking 正在淘汰 – 以下是準備方法
下列各節提供此範例的程式碼片段和其他資訊。範例的完整程式碼會顯示在程式碼片段之後,並且可以像原樣建置和執行。
收集您需要的內容
若要啟動 EC2 執行個體,您需要幾件事。
-
將啟動執行個體的 VPC 中現有子網路的 ID。尋找或建立此項目的簡單方法是登入 Amazon VPC 主控台
,但您也可以使用 CreateSubnetAsync 和 DescribeSubnetsAsync 方法以程式設計方式取得。 注意
如果您不提供此參數,新的執行個體會在您帳戶的預設 VPC 中啟動。
-
將啟動執行個體的 VPC 所屬現有安全群組的 ID。如需詳細資訊,請參閱在 Amazon EC2 中使用安全群組。
-
將用於建立執行個體的 Amazon Machine Image (AMI)。如需 AMIs 的相關資訊,請參閱 Amazon AMIs 使用者指南中的 Amazon Machine Images (Word)。 EC2 特別是,請參閱尋找 AMI 和共用 AMIs。
-
現有 EC2 金鑰對的名稱,用於連線至新執行個體。如需詳細資訊,請參閱使用 Amazon EC2 金鑰對。
-
包含上述 PEM 金鑰對私有金鑰的 EC2 檔案名稱。當您遠端連線至執行個體時,會使用 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
屬性的有效值,請參閱 InstanceState 類別。
// // 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}"); } }
完成程式碼
本節顯示此範例的相關參考和完整程式碼。
NuGet 套件:
程式設計元素:
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 執行個體的狀態時,您可以將篩選條件新增至 DescribeInstancesRequest 物件的
Filter
屬性。使用此技術,您可以將請求限制為特定執行個體,例如具有特定使用者指定標籤的執行個體。
-
為了簡潔起見,某些屬性會得到典型值。任何或所有這些屬性都可以透過程式設計或使用者輸入來決定。
-
您可以用於 RunInstancesRequest 物件的
MinCount
和MaxCount
屬性的值取決於目標可用區域,以及執行個體類型允許的執行個體數量上限。如需詳細資訊,請參閱 Amazon EC2 一般 Word 中的可在 Amazon Word 中執行多少執行個體。 EC2 FAQ
-
如果您想要使用與此範例不同的執行個體類型,有數種執行個體類型可供選擇。如需詳細資訊,請參閱 Amazon EC2 使用者指南中的 Amazon Word 執行個體類型。 EC2 另請參閱執行個體類型詳細資訊
和執行個體類型瀏覽器 。
-
您也可以在啟動 IAM 角色時將其連接至執行個體。若要這麼做,請建立
Name
屬性設定為 IamInstanceProfileSpecification 角色名稱的 IAM 物件。然後將該物件新增至 RunInstancesRequest 物件的IamInstanceProfile
屬性。注意
若要啟動已連接 IAM 角色的 Word EC2執行個體,IAM 使用者的組態必須包含特定許可。如需所需許可的詳細資訊,請參閱 Amazon IAM 使用者指南中的授予使用者將 Word 角色傳遞至執行個體的許可。 EC2
(選用) 連線至執行個體
執行個體執行後,您可以使用適當的遠端用戶端從遠端連線至它。對於 Linux 和 Windows 執行個體,您需要執行個體的公有 IP 地址或公有 DNS 名稱。您也需要下列項目。
對於 Linux 執行個體
您可以使用 SSH 用戶端連線到 Linux 執行個體。請確定您在啟動執行個體時使用的安全群組允許連接埠 22 上的 SSH 流量,如 中所述更新安全群組。
您也需要用來啟動執行個體之金鑰對的私有部分;亦即 PEM 檔案。
如需詳細資訊,請參閱 Amazon EC2 使用者指南中的連線至 Linux 執行個體。
對於 Windows 執行個體
您可以使用 RDP 用戶端連線到執行個體。請確定您在啟動執行個體時使用的安全群組允許連接埠 3389 上的 RDP 流量,如 中所述更新安全群組。
您也需要管理員密碼。您可以使用下列範例程式碼來取得此程式碼,該程式碼需要執行個體 ID 和用來啟動執行個體之金鑰對的私有部分;亦即 PEM 檔案。
如需詳細資訊,請參閱 Amazon EC2 使用者指南中的連線至 Windows 執行個體。
警告
此範例程式碼會傳回執行個體的純文字管理員密碼。
NuGet 套件:
程式設計元素:
-
命名空間 Amazon.EC2
-
命名空間 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 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 執行個體。