使用适用于 JavaScript (v3) 的软件开发工具包的 Amazon EC2 示例 - Amazon SDK for JavaScript
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

Amazon SDK for JavaScript V3 API 参考指南详细描述了 Amazon SDK for JavaScript 版本 3 (V3) 的所有 API 操作。

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

使用适用于 JavaScript (v3) 的软件开发工具包的 Amazon EC2 示例

以下代码示例向您展示了如何在 Amazon EC2 中使用 Amazon SDK for JavaScript (v3) 来执行操作和实现常见场景。

操作是大型程序的代码摘录,必须在上下文中运行。您可以通过操作了解如何调用单个服务函数,还可以通过函数相关场景和跨服务示例的上下文查看操作。

场景 是展示如何通过在同一服务中调用多个函数来完成特定任务的代码示例。

每个示例都包含一个指向的链接 GitHub,您可以在其中找到有关如何在上下文中设置和运行代码的说明。

开始使用

以下代码示例展示了如何开始使用 Amazon EC2。

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { DescribeSecurityGroupsCommand } from "@aws-sdk/client-ec2"; import { client } from "./libs/client.js"; // Call DescribeSecurityGroups and display the result. export const main = async () => { try { const { SecurityGroups } = await client.send( new DescribeSecurityGroupsCommand({}), ); const securityGroupList = SecurityGroups.slice(0, 9) .map((sg) => ` • ${sg.GroupId}: ${sg.GroupName}`) .join("\n"); console.log( "Hello, Amazon EC2! Let's list up to 10 of your security groups:", ); console.log(securityGroupList); } catch (err) { console.error(err); } };

操作

以下代码示例演示了如何使用 AllocateAddress

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { AllocateAddressCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { const command = new AllocateAddressCommand({}); try { const { AllocationId, PublicIp } = await client.send(command); console.log("A new IP address has been allocated to your account:"); console.log(`ID: ${AllocationId} Public IP: ${PublicIp}`); console.log( "You can view your IP addresses in the AWS Management Console for Amazon EC2. Look under Network & Security > Elastic IPs", ); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考AllocateAddress中的。

以下代码示例演示了如何使用 AssociateAddress

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { AssociateAddressCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { // You need to allocate an Elastic IP address before associating it with an instance. // You can do that with the AllocateAddressCommand. const allocationId = "ALLOCATION_ID"; // You need to create an EC2 instance before an IP address can be associated with it. // You can do that with the RunInstancesCommand. const instanceId = "INSTANCE_ID"; const command = new AssociateAddressCommand({ AllocationId: allocationId, InstanceId: instanceId, }); try { const { AssociationId } = await client.send(command); console.log( `Address with allocation ID ${allocationId} is now associated with instance ${instanceId}.`, `The association ID is ${AssociationId}.`, ); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考AssociateAddress中的。

以下代码示例演示了如何使用 AuthorizeSecurityGroupIngress

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { AuthorizeSecurityGroupIngressCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; // Grant permissions for a single IP address to ssh into instances // within the provided security group. export const main = async () => { const command = new AuthorizeSecurityGroupIngressCommand({ // Replace with a security group ID from the AWS console or // the DescribeSecurityGroupsCommand. GroupId: "SECURITY_GROUP_ID", IpPermissions: [ { IpProtocol: "tcp", FromPort: 22, ToPort: 22, // Replace 0.0.0.0 with the IP address to authorize. // For more information on this notation, see // https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation IpRanges: [{ CidrIp: "0.0.0.0/32" }], }, ], }); try { const { SecurityGroupRules } = await client.send(command); console.log(JSON.stringify(SecurityGroupRules, null, 2)); } catch (err) { console.error(err); } };

以下代码示例演示了如何使用 CreateKeyPair

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { CreateKeyPairCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { try { // Create a key pair in Amazon EC2. const { KeyMaterial, KeyName } = await client.send( // A unique name for the key pair. Up to 255 ASCII characters. new CreateKeyPairCommand({ KeyName: "KEY_PAIR_NAME" }), ); // This logs your private key. Be sure to save it. console.log(KeyName); console.log(KeyMaterial); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考中的CreateKey配对

以下代码示例演示了如何使用 CreateLaunchTemplate

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

const ssmClient = new SSMClient({}); const { Parameter } = await ssmClient.send( new GetParameterCommand({ Name: "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2", }), ); const ec2Client = new EC2Client({}); await ec2Client.send( new CreateLaunchTemplateCommand({ LaunchTemplateName: NAMES.launchTemplateName, LaunchTemplateData: { InstanceType: "t3.micro", ImageId: Parameter.Value, IamInstanceProfile: { Name: NAMES.instanceProfileName }, UserData: readFileSync( join(RESOURCES_PATH, "server_startup_script.sh"), ).toString("base64"), KeyName: NAMES.keyPairName, }, }),
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考中的CreateLaunch模板

以下代码示例演示了如何使用 CreateSecurityGroup

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { CreateSecurityGroupCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { const command = new CreateSecurityGroupCommand({ // Up to 255 characters in length. Cannot start with sg-. GroupName: "SECURITY_GROUP_NAME", // Up to 255 characters in length. Description: "DESCRIPTION", }); try { const { GroupId } = await client.send(command); console.log(GroupId); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考中的CreateSecurity群组

以下代码示例演示了如何使用 DeleteKeyPair

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { DeleteKeyPairCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { const command = new DeleteKeyPairCommand({ KeyName: "KEY_PAIR_NAME", }); try { await client.send(command); console.log("Successfully deleted key pair."); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考中的DeleteKey配对

以下代码示例演示了如何使用 DeleteLaunchTemplate

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

await client.send( new DeleteLaunchTemplateCommand({ LaunchTemplateName: NAMES.launchTemplateName, }), );
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考中的DeleteLaunch模板

以下代码示例演示了如何使用 DeleteSecurityGroup

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { DeleteSecurityGroupCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { const command = new DeleteSecurityGroupCommand({ GroupId: "GROUP_ID", }); try { await client.send(command); console.log("Security group deleted successfully."); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考中的DeleteSecurity群组

以下代码示例演示了如何使用 DescribeAddresses

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { DescribeAddressesCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { const command = new DescribeAddressesCommand({ // You can omit this property to show all addresses. AllocationIds: ["ALLOCATION_ID"], }); try { const { Addresses } = await client.send(command); const addressList = Addresses.map((address) => ` • ${address.PublicIp}`); console.log("Elastic IP addresses:"); console.log(addressList.join("\n")); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考DescribeAddresses中的。

以下代码示例演示了如何使用 DescribeIamInstanceProfileAssociations

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

const ec2Client = new EC2Client({}); const { IamInstanceProfileAssociations } = await ec2Client.send( new DescribeIamInstanceProfileAssociationsCommand({ Filters: [ { Name: "instance-id", Values: [state.targetInstance.InstanceId] }, ], }), );

以下代码示例演示了如何使用 DescribeImages

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { paginateDescribeImages } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; // List at least the first i386 image available for EC2 instances. export const main = async () => { // The paginate function is a wrapper around the base command. const paginator = paginateDescribeImages( // Without limiting the page size, this call can take a long time. pageSize is just sugar for // the MaxResults property in the base command. { client, pageSize: 25 }, { // There are almost 70,000 images available. Be specific with your filtering // to increase efficiency. // See https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ec2/interfaces/describeimagescommandinput.html#filters Filters: [{ Name: "architecture", Values: ["x86_64"] }], }, ); try { const arm64Images = []; for await (const page of paginator) { if (page.Images.length) { arm64Images.push(...page.Images); // Once we have at least 1 result, we can stop. if (arm64Images.length >= 1) { break; } } } console.log(arm64Images); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考DescribeImages中的。

以下代码示例演示了如何使用 DescribeInstanceTypes

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { paginateDescribeInstanceTypes, DescribeInstanceTypesCommand, } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; // List at least the first arm64 EC2 instance type available. export const main = async () => { // The paginate function is a wrapper around the underlying command. const paginator = paginateDescribeInstanceTypes( // Without limiting the page size, this call can take a long time. pageSize is just sugar for // the MaxResults property in the underlying command. { client, pageSize: 25 }, { Filters: [ { Name: "processor-info.supported-architecture", Values: ["x86_64"] }, { Name: "free-tier-eligible", Values: ["true"] }, ], } ); try { const instanceTypes = []; for await (const page of paginator) { if (page.InstanceTypes.length) { instanceTypes.push(...page.InstanceTypes); // When we have at least 1 result, we can stop. if (instanceTypes.length >= 1) { break; } } } console.log(instanceTypes); } catch (err) { console.error(err); } };

以下代码示例演示了如何使用 DescribeInstances

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { DescribeInstancesCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; // List all of your EC2 instances running with x86_64 architecture that were // launched this month. export const main = async () => { const d = new Date(); const year = d.getFullYear(); const month = `0${d.getMonth() + 1}`.slice(-2); const launchTimePattern = `${year}-${month}-*`; const command = new DescribeInstancesCommand({ Filters: [ { Name: "architecture", Values: ["x86_64"] }, { Name: "instance-state-name", Values: ["running"] }, { Name: "launch-time", Values: [launchTimePattern], }, ], }); try { const { Reservations } = await client.send(command); const instanceList = Reservations.reduce((prev, current) => { return prev.concat(current.Instances); }, []); console.log(instanceList); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考DescribeInstances中的。

以下代码示例演示了如何使用 DescribeKeyPairs

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { DescribeKeyPairsCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { const command = new DescribeKeyPairsCommand({}); try { const { KeyPairs } = await client.send(command); const keyPairList = KeyPairs.map( (kp) => ` • ${kp.KeyPairId}: ${kp.KeyName}`, ).join("\n"); console.log("The following key pairs were found in your account:"); console.log(keyPairList); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考中的DescribeKey配对

以下代码示例演示了如何使用 DescribeRegions

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { DescribeRegionsCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { const command = new DescribeRegionsCommand({ // By default this command will not show regions that require you to opt-in. // When AllRegions true even the regions that require opt-in will be returned. AllRegions: true, // You can omit the Filters property if you want to get all regions. Filters: [ { Name: "region-name", // You can specify multiple values for a filter. // You can also use '*' as a wildcard. This will return all // of the regions that start with `us-east-`. Values: ["ap-southeast-4"], }, ], }); try { const { Regions } = await client.send(command); const regionsList = Regions.map((reg) => ` • ${reg.RegionName}`); console.log("Found regions:"); console.log(regionsList.join("\n")); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考DescribeRegions中的。

以下代码示例演示了如何使用 DescribeSecurityGroups

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { DescribeSecurityGroupsCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; // Log the details of a specific security group. export const main = async () => { const command = new DescribeSecurityGroupsCommand({ GroupIds: ["SECURITY_GROUP_ID"], }); try { const { SecurityGroups } = await client.send(command); console.log(JSON.stringify(SecurityGroups, null, 2)); } catch (err) { console.error(err); } };

以下代码示例演示了如何使用 DescribeSubnets

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

const client = new EC2Client({}); const { Subnets } = await client.send( new DescribeSubnetsCommand({ Filters: [ { Name: "vpc-id", Values: [state.defaultVpc] }, { Name: "availability-zone", Values: state.availabilityZoneNames }, { Name: "default-for-az", Values: ["true"] }, ], }), );
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考DescribeSubnets中的。

以下代码示例演示了如何使用 DescribeVpcs

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

const client = new EC2Client({}); const { Vpcs } = await client.send( new DescribeVpcsCommand({ Filters: [{ Name: "is-default", Values: ["true"] }], }), );
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考DescribeVpcs中的。

以下代码示例演示了如何使用 DisassociateAddress

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { DisassociateAddressCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; // Disassociate an Elastic IP address from an instance. export const main = async () => { const command = new DisassociateAddressCommand({ // You can also use PublicIp, but that is for EC2 classic which is being retired. AssociationId: "ASSOCIATION_ID", }); try { await client.send(command); console.log("Successfully disassociated address"); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考DisassociateAddress中的。

以下代码示例演示了如何使用 MonitorInstances

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { MonitorInstancesCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; // Turn on detailed monitoring for the selected instance. // By default, metrics are sent to Amazon CloudWatch every 5 minutes. // For a cost you can enable detailed monitoring which sends metrics every minute. export const main = async () => { const command = new MonitorInstancesCommand({ InstanceIds: ["INSTANCE_ID"], }); try { const { InstanceMonitorings } = await client.send(command); const instancesBeingMonitored = InstanceMonitorings.map( (im) => ` • Detailed monitoring state for ${im.InstanceId} is ${im.Monitoring.State}.`, ); console.log("Monitoring status:"); console.log(instancesBeingMonitored.join("\n")); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考MonitorInstances中的。

以下代码示例演示了如何使用 RebootInstances

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { RebootInstancesCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { const command = new RebootInstancesCommand({ InstanceIds: ["INSTANCE_ID"], }); try { await client.send(command); console.log("Instance rebooted successfully."); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考RebootInstances中的。

以下代码示例演示了如何使用 ReleaseAddress

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { ReleaseAddressCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { const command = new ReleaseAddressCommand({ // You can also use PublicIp, but that is for EC2 classic which is being retired. AllocationId: "ALLOCATION_ID", }); try { await client.send(command); console.log("Successfully released address."); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考ReleaseAddress中的。

以下代码示例演示了如何使用 ReplaceIamInstanceProfileAssociation

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

await retry({ intervalInMs: 1000, maxRetries: 30 }, () => ec2Client.send( new ReplaceIamInstanceProfileAssociationCommand({ AssociationId: state.instanceProfileAssociationId, IamInstanceProfile: { Name: NAMES.ssmOnlyInstanceProfileName }, }), ), );

以下代码示例演示了如何使用 RunInstances

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { RunInstancesCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; // Create a new EC2 instance. export const main = async () => { const command = new RunInstancesCommand({ // Your key pair name. KeyName: "KEY_PAIR_NAME", // Your security group. SecurityGroupIds: ["SECURITY_GROUP_ID"], // An x86_64 compatible image. ImageId: "ami-0001a0d1a04bfcc30", // An x86_64 compatible free-tier instance type. InstanceType: "t1.micro", // Ensure only 1 instance launches. MinCount: 1, MaxCount: 1, }); try { const response = await client.send(command); console.log(response); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考RunInstances中的。

以下代码示例演示了如何使用 StartInstances

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { StartInstancesCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { const command = new StartInstancesCommand({ // Use DescribeInstancesCommand to find InstanceIds InstanceIds: ["INSTANCE_ID"], }); try { const { StartingInstances } = await client.send(command); const instanceIdList = StartingInstances.map( (instance) => ` • ${instance.InstanceId}`, ); console.log("Starting instances:"); console.log(instanceIdList.join("\n")); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考StartInstances中的。

以下代码示例演示了如何使用 StopInstances

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { StopInstancesCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { const command = new StopInstancesCommand({ // Use DescribeInstancesCommand to find InstanceIds InstanceIds: ["INSTANCE_ID"], }); try { const { StoppingInstances } = await client.send(command); const instanceIdList = StoppingInstances.map( (instance) => ` • ${instance.InstanceId}`, ); console.log("Stopping instances:"); console.log(instanceIdList.join("\n")); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考StopInstances中的。

以下代码示例演示了如何使用 TerminateInstances

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { TerminateInstancesCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { const command = new TerminateInstancesCommand({ InstanceIds: ["INSTANCE_ID"], }); try { const { TerminatingInstances } = await client.send(command); const instanceList = TerminatingInstances.map( (instance) => ` • ${instance.InstanceId}`, ); console.log("Terminating instances:"); console.log(instanceList.join("\n")); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考TerminateInstances中的。

以下代码示例演示了如何使用 UnmonitorInstances

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

import { UnmonitorInstancesCommand } from "@aws-sdk/client-ec2"; import { client } from "../libs/client.js"; export const main = async () => { const command = new UnmonitorInstancesCommand({ InstanceIds: ["i-09a3dfe7ae00e853f"], }); try { const { InstanceMonitorings } = await client.send(command); const instanceMonitoringsList = InstanceMonitorings.map( (im) => ` • Detailed monitoring state for ${im.InstanceId} is ${im.Monitoring.State}.`, ); console.log("Monitoring status:"); console.log(instanceMonitoringsList.join("\n")); } catch (err) { console.error(err); } };
  • 有关 API 的详细信息,请参阅 Amazon SDK for JavaScript API 参考UnmonitorInstances中的。

场景

以下代码示例演示了如何创建可返回书籍、电影和歌曲推荐的负载均衡的 Web 服务。该示例演示服务如何响应故障,以及如何重组服务以提高故障发生时的弹性。

  • 使用 Amazon EC2 Auto Scaling 组根据启动模板创建 Amazon Elastic Compute Cloud(Amazon EC2)实例,并将实例数量保持在指定范围内。

  • 使用弹性负载均衡处理和分发 HTTP 请求。

  • 监控自动扩缩组中实例的运行状况,并仅将请求转发到运行状况良好的实例。

  • 在每个 EC2 实例上运行 Python Web 服务器以处理 HTTP 请求。Web 服务器以建议和运行状况检查作为响应。

  • 使用 Amazon DynamoDB 表模拟推荐服务。

  • 通过更新 Amazon Systems Manager 参数来控制 Web 服务器对请求和运行状况检查的响应。

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

在命令提示符中运行交互式场景。

#!/usr/bin/env node // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { Scenario, parseScenarioArgs, } from "@aws-doc-sdk-examples/lib/scenario/index.js"; /** * The workflow steps are split into three stages: * - deploy * - demo * - destroy * * Each of these stages has a corresponding file prefixed with steps-*. */ import { deploySteps } from "./steps-deploy.js"; import { demoSteps } from "./steps-demo.js"; import { destroySteps } from "./steps-destroy.js"; /** * The context is passed to every scenario. Scenario steps * will modify the context. */ const context = {}; /** * Three Scenarios are created for the workflow. A Scenario is an orchestration class * that simplifies running a series of steps. */ export const scenarios = { // Deploys all resources necessary for the workflow. deploy: new Scenario("Resilient Workflow - Deploy", deploySteps, context), // Demonstrates how a fragile web service can be made more resilient. demo: new Scenario("Resilient Workflow - Demo", demoSteps, context), // Destroys the resources created for the workflow. destroy: new Scenario("Resilient Workflow - Destroy", destroySteps, context), }; // Call function if run directly import { fileURLToPath } from "url"; if (process.argv[1] === fileURLToPath(import.meta.url)) { parseScenarioArgs(scenarios); }

创建部署所有资源的步骤。

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { join } from "node:path"; import { readFileSync, writeFileSync } from "node:fs"; import axios from "axios"; import { BatchWriteItemCommand, CreateTableCommand, DynamoDBClient, waitUntilTableExists, } from "@aws-sdk/client-dynamodb"; import { EC2Client, CreateKeyPairCommand, CreateLaunchTemplateCommand, DescribeAvailabilityZonesCommand, DescribeVpcsCommand, DescribeSubnetsCommand, DescribeSecurityGroupsCommand, AuthorizeSecurityGroupIngressCommand, } from "@aws-sdk/client-ec2"; import { IAMClient, CreatePolicyCommand, CreateRoleCommand, CreateInstanceProfileCommand, AddRoleToInstanceProfileCommand, AttachRolePolicyCommand, waitUntilInstanceProfileExists, } from "@aws-sdk/client-iam"; import { SSMClient, GetParameterCommand } from "@aws-sdk/client-ssm"; import { CreateAutoScalingGroupCommand, AutoScalingClient, AttachLoadBalancerTargetGroupsCommand, } from "@aws-sdk/client-auto-scaling"; import { CreateListenerCommand, CreateLoadBalancerCommand, CreateTargetGroupCommand, ElasticLoadBalancingV2Client, waitUntilLoadBalancerAvailable, } from "@aws-sdk/client-elastic-load-balancing-v2"; import { ScenarioOutput, ScenarioInput, ScenarioAction, } from "@aws-doc-sdk-examples/lib/scenario/index.js"; import { retry } from "@aws-doc-sdk-examples/lib/utils/util-timers.js"; import { MESSAGES, NAMES, RESOURCES_PATH, ROOT } from "./constants.js"; import { initParamsSteps } from "./steps-reset-params.js"; /** * @type {import('@aws-doc-sdk-examples/lib/scenario.js').Step[]} */ export const deploySteps = [ new ScenarioOutput("introduction", MESSAGES.introduction, { header: true }), new ScenarioInput("confirmDeployment", MESSAGES.confirmDeployment, { type: "confirm", }), new ScenarioAction( "handleConfirmDeployment", (c) => c.confirmDeployment === false && process.exit(), ), new ScenarioOutput( "creatingTable", MESSAGES.creatingTable.replace("${TABLE_NAME}", NAMES.tableName), ), new ScenarioAction("createTable", async () => { const client = new DynamoDBClient({}); await client.send( new CreateTableCommand({ TableName: NAMES.tableName, ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5, }, AttributeDefinitions: [ { AttributeName: "MediaType", AttributeType: "S", }, { AttributeName: "ItemId", AttributeType: "N", }, ], KeySchema: [ { AttributeName: "MediaType", KeyType: "HASH", }, { AttributeName: "ItemId", KeyType: "RANGE", }, ], }), ); await waitUntilTableExists({ client }, { TableName: NAMES.tableName }); }), new ScenarioOutput( "createdTable", MESSAGES.createdTable.replace("${TABLE_NAME}", NAMES.tableName), ), new ScenarioOutput( "populatingTable", MESSAGES.populatingTable.replace("${TABLE_NAME}", NAMES.tableName), ), new ScenarioAction("populateTable", () => { const client = new DynamoDBClient({}); /** * @type {{ default: import("@aws-sdk/client-dynamodb").PutRequest['Item'][] }} */ const recommendations = JSON.parse( readFileSync(join(RESOURCES_PATH, "recommendations.json")), ); return client.send( new BatchWriteItemCommand({ RequestItems: { [NAMES.tableName]: recommendations.map((item) => ({ PutRequest: { Item: item }, })), }, }), ); }), new ScenarioOutput( "populatedTable", MESSAGES.populatedTable.replace("${TABLE_NAME}", NAMES.tableName), ), new ScenarioOutput( "creatingKeyPair", MESSAGES.creatingKeyPair.replace("${KEY_PAIR_NAME}", NAMES.keyPairName), ), new ScenarioAction("createKeyPair", async () => { const client = new EC2Client({}); const { KeyMaterial } = await client.send( new CreateKeyPairCommand({ KeyName: NAMES.keyPairName, }), ); writeFileSync(`${NAMES.keyPairName}.pem`, KeyMaterial, { mode: 0o600 }); }), new ScenarioOutput( "createdKeyPair", MESSAGES.createdKeyPair.replace("${KEY_PAIR_NAME}", NAMES.keyPairName), ), new ScenarioOutput( "creatingInstancePolicy", MESSAGES.creatingInstancePolicy.replace( "${INSTANCE_POLICY_NAME}", NAMES.instancePolicyName, ), ), new ScenarioAction("createInstancePolicy", async (state) => { const client = new IAMClient({}); const { Policy: { Arn }, } = await client.send( new CreatePolicyCommand({ PolicyName: NAMES.instancePolicyName, PolicyDocument: readFileSync( join(RESOURCES_PATH, "instance_policy.json"), ), }), ); state.instancePolicyArn = Arn; }), new ScenarioOutput("createdInstancePolicy", (state) => MESSAGES.createdInstancePolicy .replace("${INSTANCE_POLICY_NAME}", NAMES.instancePolicyName) .replace("${INSTANCE_POLICY_ARN}", state.instancePolicyArn), ), new ScenarioOutput( "creatingInstanceRole", MESSAGES.creatingInstanceRole.replace( "${INSTANCE_ROLE_NAME}", NAMES.instanceRoleName, ), ), new ScenarioAction("createInstanceRole", () => { const client = new IAMClient({}); return client.send( new CreateRoleCommand({ RoleName: NAMES.instanceRoleName, AssumeRolePolicyDocument: readFileSync( join(ROOT, "assume-role-policy.json"), ), }), ); }), new ScenarioOutput( "createdInstanceRole", MESSAGES.createdInstanceRole.replace( "${INSTANCE_ROLE_NAME}", NAMES.instanceRoleName, ), ), new ScenarioOutput( "attachingPolicyToRole", MESSAGES.attachingPolicyToRole .replace("${INSTANCE_ROLE_NAME}", NAMES.instanceRoleName) .replace("${INSTANCE_POLICY_NAME}", NAMES.instancePolicyName), ), new ScenarioAction("attachPolicyToRole", async (state) => { const client = new IAMClient({}); await client.send( new AttachRolePolicyCommand({ RoleName: NAMES.instanceRoleName, PolicyArn: state.instancePolicyArn, }), ); }), new ScenarioOutput( "attachedPolicyToRole", MESSAGES.attachedPolicyToRole .replace("${INSTANCE_POLICY_NAME}", NAMES.instancePolicyName) .replace("${INSTANCE_ROLE_NAME}", NAMES.instanceRoleName), ), new ScenarioOutput( "creatingInstanceProfile", MESSAGES.creatingInstanceProfile.replace( "${INSTANCE_PROFILE_NAME}", NAMES.instanceProfileName, ), ), new ScenarioAction("createInstanceProfile", async (state) => { const client = new IAMClient({}); const { InstanceProfile: { Arn }, } = await client.send( new CreateInstanceProfileCommand({ InstanceProfileName: NAMES.instanceProfileName, }), ); state.instanceProfileArn = Arn; await waitUntilInstanceProfileExists( { client }, { InstanceProfileName: NAMES.instanceProfileName }, ); }), new ScenarioOutput("createdInstanceProfile", (state) => MESSAGES.createdInstanceProfile .replace("${INSTANCE_PROFILE_NAME}", NAMES.instanceProfileName) .replace("${INSTANCE_PROFILE_ARN}", state.instanceProfileArn), ), new ScenarioOutput( "addingRoleToInstanceProfile", MESSAGES.addingRoleToInstanceProfile .replace("${INSTANCE_PROFILE_NAME}", NAMES.instanceProfileName) .replace("${INSTANCE_ROLE_NAME}", NAMES.instanceRoleName), ), new ScenarioAction("addRoleToInstanceProfile", () => { const client = new IAMClient({}); return client.send( new AddRoleToInstanceProfileCommand({ RoleName: NAMES.instanceRoleName, InstanceProfileName: NAMES.instanceProfileName, }), ); }), new ScenarioOutput( "addedRoleToInstanceProfile", MESSAGES.addedRoleToInstanceProfile .replace("${INSTANCE_PROFILE_NAME}", NAMES.instanceProfileName) .replace("${INSTANCE_ROLE_NAME}", NAMES.instanceRoleName), ), ...initParamsSteps, new ScenarioOutput("creatingLaunchTemplate", MESSAGES.creatingLaunchTemplate), new ScenarioAction("createLaunchTemplate", async () => { // snippet-start:[javascript.v3.wkflw.resilient.CreateLaunchTemplate] const ssmClient = new SSMClient({}); const { Parameter } = await ssmClient.send( new GetParameterCommand({ Name: "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2", }), ); const ec2Client = new EC2Client({}); await ec2Client.send( new CreateLaunchTemplateCommand({ LaunchTemplateName: NAMES.launchTemplateName, LaunchTemplateData: { InstanceType: "t3.micro", ImageId: Parameter.Value, IamInstanceProfile: { Name: NAMES.instanceProfileName }, UserData: readFileSync( join(RESOURCES_PATH, "server_startup_script.sh"), ).toString("base64"), KeyName: NAMES.keyPairName, }, }), // snippet-end:[javascript.v3.wkflw.resilient.CreateLaunchTemplate] ); }), new ScenarioOutput( "createdLaunchTemplate", MESSAGES.createdLaunchTemplate.replace( "${LAUNCH_TEMPLATE_NAME}", NAMES.launchTemplateName, ), ), new ScenarioOutput( "creatingAutoScalingGroup", MESSAGES.creatingAutoScalingGroup.replace( "${AUTO_SCALING_GROUP_NAME}", NAMES.autoScalingGroupName, ), ), new ScenarioAction("createAutoScalingGroup", async (state) => { const ec2Client = new EC2Client({}); const { AvailabilityZones } = await ec2Client.send( new DescribeAvailabilityZonesCommand({}), ); state.availabilityZoneNames = AvailabilityZones.map((az) => az.ZoneName); const autoScalingClient = new AutoScalingClient({}); await retry({ intervalInMs: 1000, maxRetries: 30 }, () => autoScalingClient.send( new CreateAutoScalingGroupCommand({ AvailabilityZones: state.availabilityZoneNames, AutoScalingGroupName: NAMES.autoScalingGroupName, LaunchTemplate: { LaunchTemplateName: NAMES.launchTemplateName, Version: "$Default", }, MinSize: 3, MaxSize: 3, }), ), ); }), new ScenarioOutput( "createdAutoScalingGroup", /** * @param {{ availabilityZoneNames: string[] }} state */ (state) => MESSAGES.createdAutoScalingGroup .replace("${AUTO_SCALING_GROUP_NAME}", NAMES.autoScalingGroupName) .replace( "${AVAILABILITY_ZONE_NAMES}", state.availabilityZoneNames.join(", "), ), ), new ScenarioInput("confirmContinue", MESSAGES.confirmContinue, { type: "confirm", }), new ScenarioOutput("loadBalancer", MESSAGES.loadBalancer), new ScenarioOutput("gettingVpc", MESSAGES.gettingVpc), new ScenarioAction("getVpc", async (state) => { // snippet-start:[javascript.v3.wkflw.resilient.DescribeVpcs] const client = new EC2Client({}); const { Vpcs } = await client.send( new DescribeVpcsCommand({ Filters: [{ Name: "is-default", Values: ["true"] }], }), ); // snippet-end:[javascript.v3.wkflw.resilient.DescribeVpcs] state.defaultVpc = Vpcs[0].VpcId; }), new ScenarioOutput("gotVpc", (state) => MESSAGES.gotVpc.replace("${VPC_ID}", state.defaultVpc), ), new ScenarioOutput("gettingSubnets", MESSAGES.gettingSubnets), new ScenarioAction("getSubnets", async (state) => { // snippet-start:[javascript.v3.wkflw.resilient.DescribeSubnets] const client = new EC2Client({}); const { Subnets } = await client.send( new DescribeSubnetsCommand({ Filters: [ { Name: "vpc-id", Values: [state.defaultVpc] }, { Name: "availability-zone", Values: state.availabilityZoneNames }, { Name: "default-for-az", Values: ["true"] }, ], }), ); // snippet-end:[javascript.v3.wkflw.resilient.DescribeSubnets] state.subnets = Subnets.map((subnet) => subnet.SubnetId); }), new ScenarioOutput( "gotSubnets", /** * @param {{ subnets: string[] }} state */ (state) => MESSAGES.gotSubnets.replace("${SUBNETS}", state.subnets.join(", ")), ), new ScenarioOutput( "creatingLoadBalancerTargetGroup", MESSAGES.creatingLoadBalancerTargetGroup.replace( "${TARGET_GROUP_NAME}", NAMES.loadBalancerTargetGroupName, ), ), new ScenarioAction("createLoadBalancerTargetGroup", async (state) => { // snippet-start:[javascript.v3.wkflw.resilient.CreateTargetGroup] const client = new ElasticLoadBalancingV2Client({}); const { TargetGroups } = await client.send( new CreateTargetGroupCommand({ Name: NAMES.loadBalancerTargetGroupName, Protocol: "HTTP", Port: 80, HealthCheckPath: "/healthcheck", HealthCheckIntervalSeconds: 10, HealthCheckTimeoutSeconds: 5, HealthyThresholdCount: 2, UnhealthyThresholdCount: 2, VpcId: state.defaultVpc, }), ); // snippet-end:[javascript.v3.wkflw.resilient.CreateTargetGroup] const targetGroup = TargetGroups[0]; state.targetGroupArn = targetGroup.TargetGroupArn; state.targetGroupProtocol = targetGroup.Protocol; state.targetGroupPort = targetGroup.Port; }), new ScenarioOutput( "createdLoadBalancerTargetGroup", MESSAGES.createdLoadBalancerTargetGroup.replace( "${TARGET_GROUP_NAME}", NAMES.loadBalancerTargetGroupName, ), ), new ScenarioOutput( "creatingLoadBalancer", MESSAGES.creatingLoadBalancer.replace("${LB_NAME}", NAMES.loadBalancerName), ), new ScenarioAction("createLoadBalancer", async (state) => { // snippet-start:[javascript.v3.wkflw.resilient.CreateLoadBalancer] const client = new ElasticLoadBalancingV2Client({}); const { LoadBalancers } = await client.send( new CreateLoadBalancerCommand({ Name: NAMES.loadBalancerName, Subnets: state.subnets, }), ); state.loadBalancerDns = LoadBalancers[0].DNSName; state.loadBalancerArn = LoadBalancers[0].LoadBalancerArn; await waitUntilLoadBalancerAvailable( { client }, { Names: [NAMES.loadBalancerName] }, ); // snippet-end:[javascript.v3.wkflw.resilient.CreateLoadBalancer] }), new ScenarioOutput("createdLoadBalancer", (state) => MESSAGES.createdLoadBalancer .replace("${LB_NAME}", NAMES.loadBalancerName) .replace("${DNS_NAME}", state.loadBalancerDns), ), new ScenarioOutput( "creatingListener", MESSAGES.creatingLoadBalancerListener .replace("${LB_NAME}", NAMES.loadBalancerName) .replace("${TARGET_GROUP_NAME}", NAMES.loadBalancerTargetGroupName), ), new ScenarioAction("createListener", async (state) => { // snippet-start:[javascript.v3.wkflw.resilient.CreateListener] const client = new ElasticLoadBalancingV2Client({}); const { Listeners } = await client.send( new CreateListenerCommand({ LoadBalancerArn: state.loadBalancerArn, Protocol: state.targetGroupProtocol, Port: state.targetGroupPort, DefaultActions: [ { Type: "forward", TargetGroupArn: state.targetGroupArn }, ], }), ); // snippet-end:[javascript.v3.wkflw.resilient.CreateListener] const listener = Listeners[0]; state.loadBalancerListenerArn = listener.ListenerArn; }), new ScenarioOutput("createdListener", (state) => MESSAGES.createdLoadBalancerListener.replace( "${LB_LISTENER_ARN}", state.loadBalancerListenerArn, ), ), new ScenarioOutput( "attachingLoadBalancerTargetGroup", MESSAGES.attachingLoadBalancerTargetGroup .replace("${TARGET_GROUP_NAME}", NAMES.loadBalancerTargetGroupName) .replace("${AUTO_SCALING_GROUP_NAME}", NAMES.autoScalingGroupName), ), new ScenarioAction("attachLoadBalancerTargetGroup", async (state) => { // snippet-start:[javascript.v3.wkflw.resilient.AttachTargetGroup] const client = new AutoScalingClient({}); await client.send( new AttachLoadBalancerTargetGroupsCommand({ AutoScalingGroupName: NAMES.autoScalingGroupName, TargetGroupARNs: [state.targetGroupArn], }), ); // snippet-end:[javascript.v3.wkflw.resilient.AttachTargetGroup] }), new ScenarioOutput( "attachedLoadBalancerTargetGroup", MESSAGES.attachedLoadBalancerTargetGroup, ), new ScenarioOutput("verifyingInboundPort", MESSAGES.verifyingInboundPort), new ScenarioAction( "verifyInboundPort", /** * * @param {{ defaultSecurityGroup: import('@aws-sdk/client-ec2').SecurityGroup}} state */ async (state) => { const client = new EC2Client({}); const { SecurityGroups } = await client.send( new DescribeSecurityGroupsCommand({ Filters: [{ Name: "group-name", Values: ["default"] }], }), ); if (!SecurityGroups) { state.verifyInboundPortError = new Error(MESSAGES.noSecurityGroups); } state.defaultSecurityGroup = SecurityGroups[0]; /** * @type {string} */ const ipResponse = (await axios.get("http://checkip.amazonaws.com")).data; state.myIp = ipResponse.trim(); const myIpRules = state.defaultSecurityGroup.IpPermissions.filter( ({ IpRanges }) => IpRanges.some( ({ CidrIp }) => CidrIp.startsWith(state.myIp) || CidrIp === "0.0.0.0/0", ), ) .filter(({ IpProtocol }) => IpProtocol === "tcp") .filter(({ FromPort }) => FromPort === 80); state.myIpRules = myIpRules; }, ), new ScenarioOutput( "verifiedInboundPort", /** * @param {{ myIpRules: any[] }} state */ (state) => { if (state.myIpRules.length > 0) { return MESSAGES.foundIpRules.replace( "${IP_RULES}", JSON.stringify(state.myIpRules, null, 2), ); } else { return MESSAGES.noIpRules; } }, ), new ScenarioInput( "shouldAddInboundRule", /** * @param {{ myIpRules: any[] }} state */ (state) => { if (state.myIpRules.length > 0) { return false; } else { return MESSAGES.noIpRules; } }, { type: "confirm" }, ), new ScenarioAction( "addInboundRule", /** * @param {{ defaultSecurityGroup: import('@aws-sdk/client-ec2').SecurityGroup }} state */ async (state) => { if (!state.shouldAddInboundRule) { return; } const client = new EC2Client({}); await client.send( new AuthorizeSecurityGroupIngressCommand({ GroupId: state.defaultSecurityGroup.GroupId, CidrIp: `${state.myIp}/32`, FromPort: 80, ToPort: 80, IpProtocol: "tcp", }), ); }, ), new ScenarioOutput("addedInboundRule", (state) => { if (state.shouldAddInboundRule) { return MESSAGES.addedInboundRule.replace("${IP_ADDRESS}", state.myIp); } else { return false; } }), new ScenarioOutput("verifyingEndpoint", (state) => MESSAGES.verifyingEndpoint.replace("${DNS_NAME}", state.loadBalancerDns), ), new ScenarioAction("verifyEndpoint", async (state) => { try { const response = await retry({ intervalInMs: 2000, maxRetries: 30 }, () => axios.get(`http://${state.loadBalancerDns}`), ); state.endpointResponse = JSON.stringify(response.data, null, 2); } catch (e) { state.verifyEndpointError = e; } }), new ScenarioOutput("verifiedEndpoint", (state) => { if (state.verifyEndpointError) { console.error(state.verifyEndpointError); } else { return MESSAGES.verifiedEndpoint.replace( "${ENDPOINT_RESPONSE}", state.endpointResponse, ); } }), ];

创建运行演示的步骤。

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { readFileSync } from "node:fs"; import { join } from "node:path"; import axios from "axios"; import { DescribeTargetGroupsCommand, DescribeTargetHealthCommand, ElasticLoadBalancingV2Client, } from "@aws-sdk/client-elastic-load-balancing-v2"; import { DescribeInstanceInformationCommand, PutParameterCommand, SSMClient, SendCommandCommand, } from "@aws-sdk/client-ssm"; import { IAMClient, CreatePolicyCommand, CreateRoleCommand, AttachRolePolicyCommand, CreateInstanceProfileCommand, AddRoleToInstanceProfileCommand, waitUntilInstanceProfileExists, } from "@aws-sdk/client-iam"; import { AutoScalingClient, DescribeAutoScalingGroupsCommand, TerminateInstanceInAutoScalingGroupCommand, } from "@aws-sdk/client-auto-scaling"; import { DescribeIamInstanceProfileAssociationsCommand, EC2Client, RebootInstancesCommand, ReplaceIamInstanceProfileAssociationCommand, } from "@aws-sdk/client-ec2"; import { ScenarioAction, ScenarioInput, ScenarioOutput, } from "@aws-doc-sdk-examples/lib/scenario/scenario.js"; import { retry } from "@aws-doc-sdk-examples/lib/utils/util-timers.js"; import { MESSAGES, NAMES, RESOURCES_PATH } from "./constants.js"; import { findLoadBalancer } from "./shared.js"; const getRecommendation = new ScenarioAction( "getRecommendation", async (state) => { const loadBalancer = await findLoadBalancer(NAMES.loadBalancerName); if (loadBalancer) { state.loadBalancerDnsName = loadBalancer.DNSName; try { state.recommendation = ( await axios.get(`http://${state.loadBalancerDnsName}`) ).data; } catch (e) { state.recommendation = e instanceof Error ? e.message : e; } } else { throw new Error(MESSAGES.demoFindLoadBalancerError); } }, ); const getRecommendationResult = new ScenarioOutput( "getRecommendationResult", (state) => `Recommendation:\n${JSON.stringify(state.recommendation, null, 2)}`, { preformatted: true }, ); const getHealthCheck = new ScenarioAction("getHealthCheck", async (state) => { // snippet-start:[javascript.v3.wkflw.resilient.DescribeTargetGroups] const client = new ElasticLoadBalancingV2Client({}); const { TargetGroups } = await client.send( new DescribeTargetGroupsCommand({ Names: [NAMES.loadBalancerTargetGroupName], }), ); // snippet-end:[javascript.v3.wkflw.resilient.DescribeTargetGroups] // snippet-start:[javascript.v3.wkflw.resilient.DescribeTargetHealth] const { TargetHealthDescriptions } = await client.send( new DescribeTargetHealthCommand({ TargetGroupArn: TargetGroups[0].TargetGroupArn, }), ); // snippet-end:[javascript.v3.wkflw.resilient.DescribeTargetHealth] state.targetHealthDescriptions = TargetHealthDescriptions; }); const getHealthCheckResult = new ScenarioOutput( "getHealthCheckResult", /** * @param {{ targetHealthDescriptions: import('@aws-sdk/client-elastic-load-balancing-v2').TargetHealthDescription[]}} state */ (state) => { const status = state.targetHealthDescriptions .map((th) => `${th.Target.Id}: ${th.TargetHealth.State}`) .join("\n"); return `Health check:\n${status}`; }, { preformatted: true }, ); const loadBalancerLoop = new ScenarioAction( "loadBalancerLoop", getRecommendation.action, { whileConfig: { whileFn: ({ loadBalancerCheck }) => loadBalancerCheck, input: new ScenarioInput( "loadBalancerCheck", MESSAGES.demoLoadBalancerCheck, { type: "confirm", }, ), output: getRecommendationResult, }, }, ); const healthCheckLoop = new ScenarioAction( "healthCheckLoop", getHealthCheck.action, { whileConfig: { whileFn: ({ healthCheck }) => healthCheck, input: new ScenarioInput("healthCheck", MESSAGES.demoHealthCheck, { type: "confirm", }), output: getHealthCheckResult, }, }, ); const statusSteps = [ getRecommendation, getRecommendationResult, getHealthCheck, getHealthCheckResult, ]; /** * @type {import('@aws-doc-sdk-examples/lib/scenario.js').Step[]} */ export const demoSteps = [ new ScenarioOutput("header", MESSAGES.demoHeader, { header: true }), new ScenarioOutput("sanityCheck", MESSAGES.demoSanityCheck), ...statusSteps, new ScenarioInput( "brokenDependencyConfirmation", MESSAGES.demoBrokenDependencyConfirmation, { type: "confirm" }, ), new ScenarioAction("brokenDependency", async (state) => { if (!state.brokenDependencyConfirmation) { process.exit(); } else { const client = new SSMClient({}); state.badTableName = `fake-table-${Date.now()}`; await client.send( new PutParameterCommand({ Name: NAMES.ssmTableNameKey, Value: state.badTableName, Overwrite: true, Type: "String", }), ); } }), new ScenarioOutput("testBrokenDependency", (state) => MESSAGES.demoTestBrokenDependency.replace( "${TABLE_NAME}", state.badTableName, ), ), ...statusSteps, new ScenarioInput( "staticResponseConfirmation", MESSAGES.demoStaticResponseConfirmation, { type: "confirm" }, ), new ScenarioAction("staticResponse", async (state) => { if (!state.staticResponseConfirmation) { process.exit(); } else { const client = new SSMClient({}); await client.send( new PutParameterCommand({ Name: NAMES.ssmFailureResponseKey, Value: "static", Overwrite: true, Type: "String", }), ); } }), new ScenarioOutput("testStaticResponse", MESSAGES.demoTestStaticResponse), ...statusSteps, new ScenarioInput( "badCredentialsConfirmation", MESSAGES.demoBadCredentialsConfirmation, { type: "confirm" }, ), new ScenarioAction("badCredentialsExit", (state) => { if (!state.badCredentialsConfirmation) { process.exit(); } }), new ScenarioAction("fixDynamoDBName", async () => { const client = new SSMClient({}); await client.send( new PutParameterCommand({ Name: NAMES.ssmTableNameKey, Value: NAMES.tableName, Overwrite: true, Type: "String", }), ); }), new ScenarioAction( "badCredentials", /** * @param {{ targetInstance: import('@aws-sdk/client-auto-scaling').Instance }} state */ async (state) => { await createSsmOnlyInstanceProfile(); const autoScalingClient = new AutoScalingClient({}); const { AutoScalingGroups } = await autoScalingClient.send( new DescribeAutoScalingGroupsCommand({ AutoScalingGroupNames: [NAMES.autoScalingGroupName], }), ); state.targetInstance = AutoScalingGroups[0].Instances[0]; // snippet-start:[javascript.v3.wkflw.resilient.DescribeIamInstanceProfileAssociations] const ec2Client = new EC2Client({}); const { IamInstanceProfileAssociations } = await ec2Client.send( new DescribeIamInstanceProfileAssociationsCommand({ Filters: [ { Name: "instance-id", Values: [state.targetInstance.InstanceId] }, ], }), ); // snippet-end:[javascript.v3.wkflw.resilient.DescribeIamInstanceProfileAssociations] state.instanceProfileAssociationId = IamInstanceProfileAssociations[0].AssociationId; // snippet-start:[javascript.v3.wkflw.resilient.ReplaceIamInstanceProfileAssociation] await retry({ intervalInMs: 1000, maxRetries: 30 }, () => ec2Client.send( new ReplaceIamInstanceProfileAssociationCommand({ AssociationId: state.instanceProfileAssociationId, IamInstanceProfile: { Name: NAMES.ssmOnlyInstanceProfileName }, }), ), ); // snippet-end:[javascript.v3.wkflw.resilient.ReplaceIamInstanceProfileAssociation] await ec2Client.send( new RebootInstancesCommand({ InstanceIds: [state.targetInstance.InstanceId], }), ); const ssmClient = new SSMClient({}); await retry({ intervalInMs: 20000, maxRetries: 15 }, async () => { const { InstanceInformationList } = await ssmClient.send( new DescribeInstanceInformationCommand({}), ); const instance = InstanceInformationList.find( (info) => info.InstanceId === state.targetInstance.InstanceId, ); if (!instance) { throw new Error("Instance not found."); } }); await ssmClient.send( new SendCommandCommand({ InstanceIds: [state.targetInstance.InstanceId], DocumentName: "AWS-RunShellScript", Parameters: { commands: ["cd / && sudo python3 server.py 80"] }, }), ); }, ), new ScenarioOutput( "testBadCredentials", /** * @param {{ targetInstance: import('@aws-sdk/client-ssm').InstanceInformation}} state */ (state) => MESSAGES.demoTestBadCredentials.replace( "${INSTANCE_ID}", state.targetInstance.InstanceId, ), ), loadBalancerLoop, new ScenarioInput( "deepHealthCheckConfirmation", MESSAGES.demoDeepHealthCheckConfirmation, { type: "confirm" }, ), new ScenarioAction("deepHealthCheckExit", (state) => { if (!state.deepHealthCheckConfirmation) { process.exit(); } }), new ScenarioAction("deepHealthCheck", async () => { const client = new SSMClient({}); await client.send( new PutParameterCommand({ Name: NAMES.ssmHealthCheckKey, Value: "deep", Overwrite: true, Type: "String", }), ); }), new ScenarioOutput("testDeepHealthCheck", MESSAGES.demoTestDeepHealthCheck), healthCheckLoop, loadBalancerLoop, new ScenarioInput( "killInstanceConfirmation", /** * @param {{ targetInstance: import('@aws-sdk/client-ssm').InstanceInformation }} state */ (state) => MESSAGES.demoKillInstanceConfirmation.replace( "${INSTANCE_ID}", state.targetInstance.InstanceId, ), { type: "confirm" }, ), new ScenarioAction("killInstanceExit", (state) => { if (!state.killInstanceConfirmation) { process.exit(); } }), new ScenarioAction( "killInstance", /** * @param {{ targetInstance: import('@aws-sdk/client-ssm').InstanceInformation }} state */ async (state) => { const client = new AutoScalingClient({}); await client.send( new TerminateInstanceInAutoScalingGroupCommand({ InstanceId: state.targetInstance.InstanceId, ShouldDecrementDesiredCapacity: false, }), ); }, ), new ScenarioOutput("testKillInstance", MESSAGES.demoTestKillInstance), healthCheckLoop, loadBalancerLoop, new ScenarioInput("failOpenConfirmation", MESSAGES.demoFailOpenConfirmation, { type: "confirm", }), new ScenarioAction("failOpenExit", (state) => { if (!state.failOpenConfirmation) { process.exit(); } }), new ScenarioAction("failOpen", () => { const client = new SSMClient({}); return client.send( new PutParameterCommand({ Name: NAMES.ssmTableNameKey, Value: `fake-table-${Date.now()}`, Overwrite: true, Type: "String", }), ); }), new ScenarioOutput("testFailOpen", MESSAGES.demoFailOpenTest), healthCheckLoop, loadBalancerLoop, new ScenarioInput( "resetTableConfirmation", MESSAGES.demoResetTableConfirmation, { type: "confirm" }, ), new ScenarioAction("resetTableExit", (state) => { if (!state.resetTableConfirmation) { process.exit(); } }), new ScenarioAction("resetTable", async () => { const client = new SSMClient({}); await client.send( new PutParameterCommand({ Name: NAMES.ssmTableNameKey, Value: NAMES.tableName, Overwrite: true, Type: "String", }), ); }), new ScenarioOutput("testResetTable", MESSAGES.demoTestResetTable), healthCheckLoop, loadBalancerLoop, ]; async function createSsmOnlyInstanceProfile() { const iamClient = new IAMClient({}); const { Policy } = await iamClient.send( new CreatePolicyCommand({ PolicyName: NAMES.ssmOnlyPolicyName, PolicyDocument: readFileSync( join(RESOURCES_PATH, "ssm_only_policy.json"), ), }), ); await iamClient.send( new CreateRoleCommand({ RoleName: NAMES.ssmOnlyRoleName, AssumeRolePolicyDocument: JSON.stringify({ Version: "2012-10-17", Statement: [ { Effect: "Allow", Principal: { Service: "ec2.amazonaws.com" }, Action: "sts:AssumeRole", }, ], }), }), ); await iamClient.send( new AttachRolePolicyCommand({ RoleName: NAMES.ssmOnlyRoleName, PolicyArn: Policy.Arn, }), ); await iamClient.send( new AttachRolePolicyCommand({ RoleName: NAMES.ssmOnlyRoleName, PolicyArn: "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore", }), ); // snippet-start:[javascript.v3.wkflw.resilient.CreateInstanceProfile] const { InstanceProfile } = await iamClient.send( new CreateInstanceProfileCommand({ InstanceProfileName: NAMES.ssmOnlyInstanceProfileName, }), ); await waitUntilInstanceProfileExists( { client: iamClient }, { InstanceProfileName: NAMES.ssmOnlyInstanceProfileName }, ); // snippet-end:[javascript.v3.wkflw.resilient.CreateInstanceProfile] await iamClient.send( new AddRoleToInstanceProfileCommand({ InstanceProfileName: NAMES.ssmOnlyInstanceProfileName, RoleName: NAMES.ssmOnlyRoleName, }), ); return InstanceProfile; }

创建销毁所有资源的步骤。

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { unlinkSync } from "node:fs"; import { DynamoDBClient, DeleteTableCommand } from "@aws-sdk/client-dynamodb"; import { EC2Client, DeleteKeyPairCommand, DeleteLaunchTemplateCommand, } from "@aws-sdk/client-ec2"; import { IAMClient, DeleteInstanceProfileCommand, RemoveRoleFromInstanceProfileCommand, DeletePolicyCommand, DeleteRoleCommand, DetachRolePolicyCommand, paginateListPolicies, } from "@aws-sdk/client-iam"; import { AutoScalingClient, DeleteAutoScalingGroupCommand, TerminateInstanceInAutoScalingGroupCommand, UpdateAutoScalingGroupCommand, paginateDescribeAutoScalingGroups, } from "@aws-sdk/client-auto-scaling"; import { DeleteLoadBalancerCommand, DeleteTargetGroupCommand, DescribeTargetGroupsCommand, ElasticLoadBalancingV2Client, } from "@aws-sdk/client-elastic-load-balancing-v2"; import { ScenarioOutput, ScenarioInput, ScenarioAction, } from "@aws-doc-sdk-examples/lib/scenario/index.js"; import { retry } from "@aws-doc-sdk-examples/lib/utils/util-timers.js"; import { MESSAGES, NAMES } from "./constants.js"; import { findLoadBalancer } from "./shared.js"; /** * @type {import('@aws-doc-sdk-examples/lib/scenario.js').Step[]} */ export const destroySteps = [ new ScenarioInput("destroy", MESSAGES.destroy, { type: "confirm" }), new ScenarioAction( "abort", (state) => state.destroy === false && process.exit(), ), new ScenarioAction("deleteTable", async (c) => { try { const client = new DynamoDBClient({}); await client.send(new DeleteTableCommand({ TableName: NAMES.tableName })); } catch (e) { c.deleteTableError = e; } }), new ScenarioOutput("deleteTableResult", (state) => { if (state.deleteTableError) { console.error(state.deleteTableError); return MESSAGES.deleteTableError.replace( "${TABLE_NAME}", NAMES.tableName, ); } else { return MESSAGES.deletedTable.replace("${TABLE_NAME}", NAMES.tableName); } }), new ScenarioAction("deleteKeyPair", async (state) => { try { const client = new EC2Client({}); await client.send( new DeleteKeyPairCommand({ KeyName: NAMES.keyPairName }), ); unlinkSync(`${NAMES.keyPairName}.pem`); } catch (e) { state.deleteKeyPairError = e; } }), new ScenarioOutput("deleteKeyPairResult", (state) => { if (state.deleteKeyPairError) { console.error(state.deleteKeyPairError); return MESSAGES.deleteKeyPairError.replace( "${KEY_PAIR_NAME}", NAMES.keyPairName, ); } else { return MESSAGES.deletedKeyPair.replace( "${KEY_PAIR_NAME}", NAMES.keyPairName, ); } }), new ScenarioAction("detachPolicyFromRole", async (state) => { try { const client = new IAMClient({}); const policy = await findPolicy(NAMES.instancePolicyName); if (!policy) { state.detachPolicyFromRoleError = new Error( `Policy ${NAMES.instancePolicyName} not found.`, ); } else { await client.send( new DetachRolePolicyCommand({ RoleName: NAMES.instanceRoleName, PolicyArn: policy.Arn, }), ); } } catch (e) { state.detachPolicyFromRoleError = e; } }), new ScenarioOutput("detachedPolicyFromRole", (state) => { if (state.detachPolicyFromRoleError) { console.error(state.detachPolicyFromRoleError); return MESSAGES.detachPolicyFromRoleError .replace("${INSTANCE_POLICY_NAME}", NAMES.instancePolicyName) .replace("${INSTANCE_ROLE_NAME}", NAMES.instanceRoleName); } else { return MESSAGES.detachedPolicyFromRole .replace("${INSTANCE_POLICY_NAME}", NAMES.instancePolicyName) .replace("${INSTANCE_ROLE_NAME}", NAMES.instanceRoleName); } }), new ScenarioAction("deleteInstancePolicy", async (state) => { const client = new IAMClient({}); const policy = await findPolicy(NAMES.instancePolicyName); if (!policy) { state.deletePolicyError = new Error( `Policy ${NAMES.instancePolicyName} not found.`, ); } else { return client.send( new DeletePolicyCommand({ PolicyArn: policy.Arn, }), ); } }), new ScenarioOutput("deletePolicyResult", (state) => { if (state.deletePolicyError) { console.error(state.deletePolicyError); return MESSAGES.deletePolicyError.replace( "${INSTANCE_POLICY_NAME}", NAMES.instancePolicyName, ); } else { return MESSAGES.deletedPolicy.replace( "${INSTANCE_POLICY_NAME}", NAMES.instancePolicyName, ); } }), new ScenarioAction("removeRoleFromInstanceProfile", async (state) => { try { const client = new IAMClient({}); await client.send( new RemoveRoleFromInstanceProfileCommand({ RoleName: NAMES.instanceRoleName, InstanceProfileName: NAMES.instanceProfileName, }), ); } catch (e) { state.removeRoleFromInstanceProfileError = e; } }), new ScenarioOutput("removeRoleFromInstanceProfileResult", (state) => { if (state.removeRoleFromInstanceProfile) { console.error(state.removeRoleFromInstanceProfileError); return MESSAGES.removeRoleFromInstanceProfileError .replace("${INSTANCE_PROFILE_NAME}", NAMES.instanceProfileName) .replace("${INSTANCE_ROLE_NAME}", NAMES.instanceRoleName); } else { return MESSAGES.removedRoleFromInstanceProfile .replace("${INSTANCE_PROFILE_NAME}", NAMES.instanceProfileName) .replace("${INSTANCE_ROLE_NAME}", NAMES.instanceRoleName); } }), new ScenarioAction("deleteInstanceRole", async (state) => { try { const client = new IAMClient({}); await client.send( new DeleteRoleCommand({ RoleName: NAMES.instanceRoleName, }), ); } catch (e) { state.deleteInstanceRoleError = e; } }), new ScenarioOutput("deleteInstanceRoleResult", (state) => { if (state.deleteInstanceRoleError) { console.error(state.deleteInstanceRoleError); return MESSAGES.deleteInstanceRoleError.replace( "${INSTANCE_ROLE_NAME}", NAMES.instanceRoleName, ); } else { return MESSAGES.deletedInstanceRole.replace( "${INSTANCE_ROLE_NAME}", NAMES.instanceRoleName, ); } }), new ScenarioAction("deleteInstanceProfile", async (state) => { try { // snippet-start:[javascript.v3.wkflw.resilient.DeleteInstanceProfile] const client = new IAMClient({}); await client.send( new DeleteInstanceProfileCommand({ InstanceProfileName: NAMES.instanceProfileName, }), ); // snippet-end:[javascript.v3.wkflw.resilient.DeleteInstanceProfile] } catch (e) { state.deleteInstanceProfileError = e; } }), new ScenarioOutput("deleteInstanceProfileResult", (state) => { if (state.deleteInstanceProfileError) { console.error(state.deleteInstanceProfileError); return MESSAGES.deleteInstanceProfileError.replace( "${INSTANCE_PROFILE_NAME}", NAMES.instanceProfileName, ); } else { return MESSAGES.deletedInstanceProfile.replace( "${INSTANCE_PROFILE_NAME}", NAMES.instanceProfileName, ); } }), new ScenarioAction("deleteAutoScalingGroup", async (state) => { try { await terminateGroupInstances(NAMES.autoScalingGroupName); await retry({ intervalInMs: 60000, maxRetries: 60 }, async () => { await deleteAutoScalingGroup(NAMES.autoScalingGroupName); }); } catch (e) { state.deleteAutoScalingGroupError = e; } }), new ScenarioOutput("deleteAutoScalingGroupResult", (state) => { if (state.deleteAutoScalingGroupError) { console.error(state.deleteAutoScalingGroupError); return MESSAGES.deleteAutoScalingGroupError.replace( "${AUTO_SCALING_GROUP_NAME}", NAMES.autoScalingGroupName, ); } else { return MESSAGES.deletedAutoScalingGroup.replace( "${AUTO_SCALING_GROUP_NAME}", NAMES.autoScalingGroupName, ); } }), new ScenarioAction("deleteLaunchTemplate", async (state) => { const client = new EC2Client({}); try { // snippet-start:[javascript.v3.wkflw.resilient.DeleteLaunchTemplate] await client.send( new DeleteLaunchTemplateCommand({ LaunchTemplateName: NAMES.launchTemplateName, }), ); // snippet-end:[javascript.v3.wkflw.resilient.DeleteLaunchTemplate] } catch (e) { state.deleteLaunchTemplateError = e; } }), new ScenarioOutput("deleteLaunchTemplateResult", (state) => { if (state.deleteLaunchTemplateError) { console.error(state.deleteLaunchTemplateError); return MESSAGES.deleteLaunchTemplateError.replace( "${LAUNCH_TEMPLATE_NAME}", NAMES.launchTemplateName, ); } else { return MESSAGES.deletedLaunchTemplate.replace( "${LAUNCH_TEMPLATE_NAME}", NAMES.launchTemplateName, ); } }), new ScenarioAction("deleteLoadBalancer", async (state) => { try { // snippet-start:[javascript.v3.wkflw.resilient.DeleteLoadBalancer] const client = new ElasticLoadBalancingV2Client({}); const loadBalancer = await findLoadBalancer(NAMES.loadBalancerName); await client.send( new DeleteLoadBalancerCommand({ LoadBalancerArn: loadBalancer.LoadBalancerArn, }), ); await retry({ intervalInMs: 1000, maxRetries: 60 }, async () => { const lb = await findLoadBalancer(NAMES.loadBalancerName); if (lb) { throw new Error("Load balancer still exists."); } }); // snippet-end:[javascript.v3.wkflw.resilient.DeleteLoadBalancer] } catch (e) { state.deleteLoadBalancerError = e; } }), new ScenarioOutput("deleteLoadBalancerResult", (state) => { if (state.deleteLoadBalancerError) { console.error(state.deleteLoadBalancerError); return MESSAGES.deleteLoadBalancerError.replace( "${LB_NAME}", NAMES.loadBalancerName, ); } else { return MESSAGES.deletedLoadBalancer.replace( "${LB_NAME}", NAMES.loadBalancerName, ); } }), new ScenarioAction("deleteLoadBalancerTargetGroup", async (state) => { // snippet-start:[javascript.v3.wkflw.resilient.DeleteTargetGroup] const client = new ElasticLoadBalancingV2Client({}); try { const { TargetGroups } = await client.send( new DescribeTargetGroupsCommand({ Names: [NAMES.loadBalancerTargetGroupName], }), ); await retry({ intervalInMs: 1000, maxRetries: 30 }, () => client.send( new DeleteTargetGroupCommand({ TargetGroupArn: TargetGroups[0].TargetGroupArn, }), ), ); } catch (e) { state.deleteLoadBalancerTargetGroupError = e; } // snippet-end:[javascript.v3.wkflw.resilient.DeleteTargetGroup] }), new ScenarioOutput("deleteLoadBalancerTargetGroupResult", (state) => { if (state.deleteLoadBalancerTargetGroupError) { console.error(state.deleteLoadBalancerTargetGroupError); return MESSAGES.deleteLoadBalancerTargetGroupError.replace( "${TARGET_GROUP_NAME}", NAMES.loadBalancerTargetGroupName, ); } else { return MESSAGES.deletedLoadBalancerTargetGroup.replace( "${TARGET_GROUP_NAME}", NAMES.loadBalancerTargetGroupName, ); } }), new ScenarioAction("detachSsmOnlyRoleFromProfile", async (state) => { try { const client = new IAMClient({}); await client.send( new RemoveRoleFromInstanceProfileCommand({ InstanceProfileName: NAMES.ssmOnlyInstanceProfileName, RoleName: NAMES.ssmOnlyRoleName, }), ); } catch (e) { state.detachSsmOnlyRoleFromProfileError = e; } }), new ScenarioOutput("detachSsmOnlyRoleFromProfileResult", (state) => { if (state.detachSsmOnlyRoleFromProfileError) { console.error(state.detachSsmOnlyRoleFromProfileError); return MESSAGES.detachSsmOnlyRoleFromProfileError .replace("${ROLE_NAME}", NAMES.ssmOnlyRoleName) .replace("${PROFILE_NAME}", NAMES.ssmOnlyInstanceProfileName); } else { return MESSAGES.detachedSsmOnlyRoleFromProfile .replace("${ROLE_NAME}", NAMES.ssmOnlyRoleName) .replace("${PROFILE_NAME}", NAMES.ssmOnlyInstanceProfileName); } }), new ScenarioAction("detachSsmOnlyCustomRolePolicy", async (state) => { try { const iamClient = new IAMClient({}); const ssmOnlyPolicy = await findPolicy(NAMES.ssmOnlyPolicyName); await iamClient.send( new DetachRolePolicyCommand({ RoleName: NAMES.ssmOnlyRoleName, PolicyArn: ssmOnlyPolicy.Arn, }), ); } catch (e) { state.detachSsmOnlyCustomRolePolicyError = e; } }), new ScenarioOutput("detachSsmOnlyCustomRolePolicyResult", (state) => { if (state.detachSsmOnlyCustomRolePolicyError) { console.error(state.detachSsmOnlyCustomRolePolicyError); return MESSAGES.detachSsmOnlyCustomRolePolicyError .replace("${ROLE_NAME}", NAMES.ssmOnlyRoleName) .replace("${POLICY_NAME}", NAMES.ssmOnlyPolicyName); } else { return MESSAGES.detachedSsmOnlyCustomRolePolicy .replace("${ROLE_NAME}", NAMES.ssmOnlyRoleName) .replace("${POLICY_NAME}", NAMES.ssmOnlyPolicyName); } }), new ScenarioAction("detachSsmOnlyAWSRolePolicy", async (state) => { try { const iamClient = new IAMClient({}); await iamClient.send( new DetachRolePolicyCommand({ RoleName: NAMES.ssmOnlyRoleName, PolicyArn: "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore", }), ); } catch (e) { state.detachSsmOnlyAWSRolePolicyError = e; } }), new ScenarioOutput("detachSsmOnlyAWSRolePolicyResult", (state) => { if (state.detachSsmOnlyAWSRolePolicyError) { console.error(state.detachSsmOnlyAWSRolePolicyError); return MESSAGES.detachSsmOnlyAWSRolePolicyError .replace("${ROLE_NAME}", NAMES.ssmOnlyRoleName) .replace("${POLICY_NAME}", "AmazonSSMManagedInstanceCore"); } else { return MESSAGES.detachedSsmOnlyAWSRolePolicy .replace("${ROLE_NAME}", NAMES.ssmOnlyRoleName) .replace("${POLICY_NAME}", "AmazonSSMManagedInstanceCore"); } }), new ScenarioAction("deleteSsmOnlyInstanceProfile", async (state) => { try { const iamClient = new IAMClient({}); await iamClient.send( new DeleteInstanceProfileCommand({ InstanceProfileName: NAMES.ssmOnlyInstanceProfileName, }), ); } catch (e) { state.deleteSsmOnlyInstanceProfileError = e; } }), new ScenarioOutput("deleteSsmOnlyInstanceProfileResult", (state) => { if (state.deleteSsmOnlyInstanceProfileError) { console.error(state.deleteSsmOnlyInstanceProfileError); return MESSAGES.deleteSsmOnlyInstanceProfileError.replace( "${INSTANCE_PROFILE_NAME}", NAMES.ssmOnlyInstanceProfileName, ); } else { return MESSAGES.deletedSsmOnlyInstanceProfile.replace( "${INSTANCE_PROFILE_NAME}", NAMES.ssmOnlyInstanceProfileName, ); } }), new ScenarioAction("deleteSsmOnlyPolicy", async (state) => { try { const iamClient = new IAMClient({}); const ssmOnlyPolicy = await findPolicy(NAMES.ssmOnlyPolicyName); await iamClient.send( new DeletePolicyCommand({ PolicyArn: ssmOnlyPolicy.Arn, }), ); } catch (e) { state.deleteSsmOnlyPolicyError = e; } }), new ScenarioOutput("deleteSsmOnlyPolicyResult", (state) => { if (state.deleteSsmOnlyPolicyError) { console.error(state.deleteSsmOnlyPolicyError); return MESSAGES.deleteSsmOnlyPolicyError.replace( "${POLICY_NAME}", NAMES.ssmOnlyPolicyName, ); } else { return MESSAGES.deletedSsmOnlyPolicy.replace( "${POLICY_NAME}", NAMES.ssmOnlyPolicyName, ); } }), new ScenarioAction("deleteSsmOnlyRole", async (state) => { try { const iamClient = new IAMClient({}); await iamClient.send( new DeleteRoleCommand({ RoleName: NAMES.ssmOnlyRoleName, }), ); } catch (e) { state.deleteSsmOnlyRoleError = e; } }), new ScenarioOutput("deleteSsmOnlyRoleResult", (state) => { if (state.deleteSsmOnlyRoleError) { console.error(state.deleteSsmOnlyRoleError); return MESSAGES.deleteSsmOnlyRoleError.replace( "${ROLE_NAME}", NAMES.ssmOnlyRoleName, ); } else { return MESSAGES.deletedSsmOnlyRole.replace( "${ROLE_NAME}", NAMES.ssmOnlyRoleName, ); } }), ]; /** * @param {string} policyName */ async function findPolicy(policyName) { const client = new IAMClient({}); const paginatedPolicies = paginateListPolicies({ client }, {}); for await (const page of paginatedPolicies) { const policy = page.Policies.find((p) => p.PolicyName === policyName); if (policy) { return policy; } } } /** * @param {string} groupName */ async function deleteAutoScalingGroup(groupName) { const client = new AutoScalingClient({}); try { await client.send( new DeleteAutoScalingGroupCommand({ AutoScalingGroupName: groupName, }), ); } catch (err) { if (!(err instanceof Error)) { throw err; } else { console.log(err.name); throw err; } } } /** * @param {string} groupName */ async function terminateGroupInstances(groupName) { const autoScalingClient = new AutoScalingClient({}); const group = await findAutoScalingGroup(groupName); await autoScalingClient.send( new UpdateAutoScalingGroupCommand({ AutoScalingGroupName: group.AutoScalingGroupName, MinSize: 0, }), ); for (const i of group.Instances) { await retry({ intervalInMs: 1000, maxRetries: 30 }, () => autoScalingClient.send( new TerminateInstanceInAutoScalingGroupCommand({ InstanceId: i.InstanceId, ShouldDecrementDesiredCapacity: true, }), ), ); } } async function findAutoScalingGroup(groupName) { const client = new AutoScalingClient({}); const paginatedGroups = paginateDescribeAutoScalingGroups({ client }, {}); for await (const page of paginatedGroups) { const group = page.AutoScalingGroups.find( (g) => g.AutoScalingGroupName === groupName, ); if (group) { return group; } } throw new Error(`Auto scaling group ${groupName} not found.`); }

以下代码示例演示了操作流程:

  • 创建密钥对和安全组。

  • 选择 Amazon 机器映像 (AMI) 和兼容的实例类型,然后创建实例。

  • 停止实例,然后再重启。

  • 将弹性 IP 地址与您的实例相关联。

  • 使用 SSH 连接到您的实例,然后清理资源。

适用于 JavaScript (v3) 的软件开发工具包
注意

还有更多相关信息 GitHub。在 Amazon 代码示例存储库中查找完整示例,了解如何进行设置和运行。

在命令提示符中运行交互式场景。

import { mkdtempSync, writeFileSync, rmSync } from "fs"; import { tmpdir } from "os"; import { join } from "path"; import { get } from "http"; import { AllocateAddressCommand, AssociateAddressCommand, AuthorizeSecurityGroupIngressCommand, CreateKeyPairCommand, CreateSecurityGroupCommand, DeleteKeyPairCommand, DeleteSecurityGroupCommand, DescribeInstancesCommand, DescribeKeyPairsCommand, DescribeSecurityGroupsCommand, DisassociateAddressCommand, EC2Client, paginateDescribeImages, paginateDescribeInstanceTypes, ReleaseAddressCommand, RunInstancesCommand, StartInstancesCommand, StopInstancesCommand, TerminateInstancesCommand, waitUntilInstanceStatusOk, waitUntilInstanceStopped, waitUntilInstanceTerminated, } from "@aws-sdk/client-ec2"; import { paginateGetParametersByPath, SSMClient } from "@aws-sdk/client-ssm"; import { wrapText } from "@aws-doc-sdk-examples/lib/utils/util-string.js"; import { Prompter } from "@aws-doc-sdk-examples/lib/prompter.js"; const ec2Client = new EC2Client(); const ssmClient = new SSMClient(); const prompter = new Prompter(); const confirmMessage = "Continue?"; const tmpDirectory = mkdtempSync(join(tmpdir(), "ec2-scenario-tmp")); const createKeyPair = async (keyPairName) => { // Create a key pair in Amazon EC2. const { KeyMaterial, KeyPairId } = await ec2Client.send( // A unique name for the key pair. Up to 255 ASCII characters. new CreateKeyPairCommand({ KeyName: keyPairName }), ); // Save the private key in a temporary location. writeFileSync(`${tmpDirectory}/${keyPairName}.pem`, KeyMaterial, { mode: 0o400, }); return KeyPairId; }; const describeKeyPair = async (keyPairName) => { const command = new DescribeKeyPairsCommand({ KeyNames: [keyPairName], }); const { KeyPairs } = await ec2Client.send(command); return KeyPairs[0]; }; const createSecurityGroup = async (securityGroupName) => { const command = new CreateSecurityGroupCommand({ GroupName: securityGroupName, Description: "A security group for the Amazon EC2 example.", }); const { GroupId } = await ec2Client.send(command); return GroupId; }; const allocateIpAddress = async () => { const command = new AllocateAddressCommand({}); const { PublicIp, AllocationId } = await ec2Client.send(command); return { PublicIp, AllocationId }; }; const getLocalIpAddress = () => { return new Promise((res, rej) => { get("http://checkip.amazonaws.com", (response) => { let data = ""; response.on("data", (chunk) => (data += chunk)); response.on("end", () => res(data.trim())); }).on("error", (err) => { rej(err); }); }); }; const authorizeSecurityGroupIngress = async (securityGroupId) => { const ipAddress = await getLocalIpAddress(); const command = new AuthorizeSecurityGroupIngressCommand({ GroupId: securityGroupId, IpPermissions: [ { IpProtocol: "tcp", FromPort: 22, ToPort: 22, IpRanges: [{ CidrIp: `${ipAddress}/32` }], }, ], }); await ec2Client.send(command); return ipAddress; }; const describeSecurityGroup = async (securityGroupName) => { const command = new DescribeSecurityGroupsCommand({ GroupNames: [securityGroupName], }); const { SecurityGroups } = await ec2Client.send(command); return SecurityGroups[0]; }; const getAmznLinux2AMIs = async () => { const AMIs = []; for await (const page of paginateGetParametersByPath( { client: ssmClient, }, { Path: "/aws/service/ami-amazon-linux-latest" }, )) { page.Parameters.forEach((param) => { if (param.Name.includes("amzn2")) { AMIs.push(param.Value); } }); } const imageDetails = []; for await (const page of paginateDescribeImages( { client: ec2Client }, { ImageIds: AMIs }, )) { imageDetails.push(...(page.Images || [])); } const choices = imageDetails.map((image, index) => ({ name: `${image.ImageId} - ${image.Description}`, value: index, })); /** * @type {number} */ const selectedIndex = await prompter.select({ message: "Select an image.", choices, }); return imageDetails[selectedIndex]; }; /** * @param {import('@aws-sdk/client-ec2').Image} imageDetails */ const getCompatibleInstanceTypes = async (imageDetails) => { const paginator = paginateDescribeInstanceTypes( { client: ec2Client, pageSize: 25 }, { Filters: [ { Name: "processor-info.supported-architecture", Values: [imageDetails.Architecture], }, { Name: "instance-type", Values: ["*.micro", "*.small"] }, ], }, ); const instanceTypes = []; for await (const page of paginator) { if (page.InstanceTypes.length) { instanceTypes.push(...(page.InstanceTypes || [])); } } const choices = instanceTypes.map((type, index) => ({ name: `${type.InstanceType} - Memory:${type.MemoryInfo.SizeInMiB}`, value: index, })); /** * @type {number} */ const selectedIndex = await prompter.select({ message: "Select an instance type.", choices, }); return instanceTypes[selectedIndex]; }; const runInstance = async ({ keyPairName, securityGroupId, imageId, instanceType, }) => { const command = new RunInstancesCommand({ KeyName: keyPairName, SecurityGroupIds: [securityGroupId], ImageId: imageId, InstanceType: instanceType, MinCount: 1, MaxCount: 1, }); const { Instances } = await ec2Client.send(command); await waitUntilInstanceStatusOk( { client: ec2Client }, { InstanceIds: [Instances[0].InstanceId] }, ); return Instances[0].InstanceId; }; const describeInstance = async (instanceId) => { const command = new DescribeInstancesCommand({ InstanceIds: [instanceId], }); const { Reservations } = await ec2Client.send(command); return Reservations[0].Instances[0]; }; const displaySSHConnectionInfo = ({ publicIp, keyPairName }) => { return `ssh -i ${tmpDirectory}/${keyPairName}.pem ec2-user@${publicIp}`; }; const stopInstance = async (instanceId) => { const command = new StopInstancesCommand({ InstanceIds: [instanceId] }); await ec2Client.send(command); await waitUntilInstanceStopped( { client: ec2Client }, { InstanceIds: [instanceId] }, ); }; const startInstance = async (instanceId) => { const startCommand = new StartInstancesCommand({ InstanceIds: [instanceId] }); await ec2Client.send(startCommand); await waitUntilInstanceStatusOk( { client: ec2Client }, { InstanceIds: [instanceId] }, ); return await describeInstance(instanceId); }; const associateAddress = async ({ allocationId, instanceId }) => { const command = new AssociateAddressCommand({ AllocationId: allocationId, InstanceId: instanceId, }); const { AssociationId } = await ec2Client.send(command); return AssociationId; }; const disassociateAddress = async (associationId) => { const command = new DisassociateAddressCommand({ AssociationId: associationId, }); try { await ec2Client.send(command); } catch (err) { console.warn( `Failed to disassociated address with association id: ${associationId}`, err, ); } }; const releaseAddress = async (allocationId) => { const command = new ReleaseAddressCommand({ AllocationId: allocationId, }); try { await ec2Client.send(command); console.log(`Address with allocation ID ${allocationId} released.\n`); } catch (err) { console.log( `Failed to release address with allocation id: ${allocationId}.`, err, ); } }; const restartInstance = async (instanceId) => { console.log("Stopping instance."); await stopInstance(instanceId); console.log("Instance stopped."); console.log("Starting instance."); const { PublicIpAddress } = await startInstance(instanceId); return PublicIpAddress; }; const terminateInstance = async (instanceId) => { const command = new TerminateInstancesCommand({ InstanceIds: [instanceId], }); try { await ec2Client.send(command); await waitUntilInstanceTerminated( { client: ec2Client }, { InstanceIds: [instanceId] }, ); console.log(`Instance with ID ${instanceId} terminated.\n`); } catch (err) { console.warn(`Failed to terminate instance ${instanceId}.`, err); } }; const deleteSecurityGroup = async (securityGroupId) => { const command = new DeleteSecurityGroupCommand({ GroupId: securityGroupId, }); try { await ec2Client.send(command); console.log(`Security group ${securityGroupId} deleted.\n`); } catch (err) { console.warn(`Failed to delete security group ${securityGroupId}.`, err); } }; const deleteKeyPair = async (keyPairName) => { const command = new DeleteKeyPairCommand({ KeyName: keyPairName, }); try { await ec2Client.send(command); console.log(`Key pair ${keyPairName} deleted.\n`); } catch (err) { console.warn(`Failed to delete key pair ${keyPairName}.`, err); } }; const deleteTemporaryDirectory = () => { try { rmSync(tmpDirectory, { recursive: true }); console.log(`Temporary directory ${tmpDirectory} deleted.\n`); } catch (err) { console.warn(`Failed to delete temporary directory ${tmpDirectory}.`, err); } }; export const main = async () => { const keyPairName = "ec2-scenario-key-pair"; const securityGroupName = "ec2-scenario-security-group"; let securityGroupId, ipAllocationId, publicIp, instanceId, associationId; console.log(wrapText("Welcome to the Amazon EC2 basic usage scenario.")); try { // Prerequisites console.log( "Before you launch an instance, you'll need a few things:", "\n - A Key Pair", "\n - A Security Group", "\n - An IP Address", "\n - An AMI", "\n - A compatible instance type", "\n\n I'll go ahead and take care of the first three, but I'll need your help for the rest.", ); await prompter.confirm({ message: confirmMessage }); await createKeyPair(keyPairName); securityGroupId = await createSecurityGroup(securityGroupName); const { PublicIp, AllocationId } = await allocateIpAddress(); ipAllocationId = AllocationId; publicIp = PublicIp; const ipAddress = await authorizeSecurityGroupIngress(securityGroupId); const { KeyName } = await describeKeyPair(keyPairName); const { GroupName } = await describeSecurityGroup(securityGroupName); console.log(`✅ created the key pair ${KeyName}.\n`); console.log( `✅ created the security group ${GroupName}`, `and allowed SSH access from ${ipAddress} (your IP).\n`, ); console.log(`✅ allocated ${publicIp} to be used for your EC2 instance.\n`); await prompter.confirm({ message: confirmMessage }); // Creating the instance console.log(wrapText("Create the instance.")); console.log( "You get to choose which image you want. Select an amazon-linux-2 image from the following:", ); const imageDetails = await getAmznLinux2AMIs(); const instanceTypeDetails = await getCompatibleInstanceTypes(imageDetails); console.log("Creating your instance. This can take a few seconds."); instanceId = await runInstance({ keyPairName, securityGroupId, imageId: imageDetails.ImageId, instanceType: instanceTypeDetails.InstanceType, }); const instanceDetails = await describeInstance(instanceId); console.log(`✅ instance ${instanceId}.\n`); console.log(instanceDetails); console.log( `\nYou should now be able to SSH into your instance from another terminal:`, `\n${displaySSHConnectionInfo({ publicIp: instanceDetails.PublicIpAddress, keyPairName, })}`, ); await prompter.confirm({ message: confirmMessage }); // Understanding the IP address. console.log(wrapText("Understanding the IP address.")); console.log( "When you stop and start an instance, the IP address will change. I'll restart your", "instance for you. Notice how the IP address changes.", ); const ipAddressAfterRestart = await restartInstance(instanceId); console.log( `\n Instance started. The IP address changed from ${instanceDetails.PublicIpAddress} to ${ipAddressAfterRestart}`, `\n${displaySSHConnectionInfo({ publicIp: ipAddressAfterRestart, keyPairName, })}`, ); await prompter.confirm({ message: confirmMessage }); console.log( `If you want to the IP address to be static, you can associate an allocated`, `IP address to your instance. I allocated ${publicIp} for you earlier, and now I'll associate it to your instance.`, ); associationId = await associateAddress({ allocationId: ipAllocationId, instanceId, }); console.log( "Done. Now you should be able to SSH using the new IP.\n", `${displaySSHConnectionInfo({ publicIp, keyPairName })}`, ); await prompter.confirm({ message: confirmMessage }); console.log( "I'll restart the server again so you can see the IP address remains the same.", ); const ipAddressAfterAssociated = await restartInstance(instanceId); console.log( `Done. Here's your SSH info. Notice the IP address hasn't changed.`, `\n${displaySSHConnectionInfo({ publicIp: ipAddressAfterAssociated, keyPairName, })}`, ); await prompter.confirm({ message: confirmMessage }); } catch (err) { console.error(err); } finally { // Clean up. console.log(wrapText("Clean up.")); console.log("Now I'll clean up all of the stuff I created."); await prompter.confirm({ message: confirmMessage }); console.log("Cleaning up. Some of these steps can take a bit of time."); await disassociateAddress(associationId); await terminateInstance(instanceId); await releaseAddress(ipAllocationId); await deleteSecurityGroup(securityGroupId); deleteTemporaryDirectory(); await deleteKeyPair(keyPairName); console.log( "Done cleaning up. Thanks for staying until the end!", "If you have any feedback please use the feedback button in the docs", "or create an issue on GitHub.", ); } };