演练:创建已扩展且负载均衡的应用程序 - Amazon CloudFormation
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

演练:创建已扩展且负载均衡的应用程序

在本演练中,您将创建一个堆栈,该堆栈可帮助您设置已扩展且负载平衡的应用程序。此演练为您提供将用于创建堆栈的示例模板。此示例模板预置了自动扩缩组、应用程序负载均衡器、控制负载均衡器和自动扩缩组流量的安全组,以及用于发布有关扩展活动的通知的 Amazon SNS 通知配置。

本模板将创建一个或多个 Amazon EC2 实例和一个应用程序负载均衡器。如果您通过本模板创建堆栈,则需为使用的 Amazon 资源支付相应费用。

完整堆栈模板

我们从使用模板开始。

YAML

AWSTemplateFormatVersion: 2010-09-09 Parameters: InstanceType: Description: The EC2 instance type Type: String Default: t3.micro AllowedValues: - t3.micro - t3.small - t3.medium KeyName: Description: Name of an existing EC2 key pair to allow SSH access to the instances Type: 'AWS::EC2::KeyPair::KeyName' LatestAmiId: Description: The latest Amazon Linux 2 AMI from the Parameter Store Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>' Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' OperatorEmail: Description: The email address to notify when there are any scaling activities Type: String SSHLocation: Description: The IP address range that can be used to SSH to the EC2 instances Type: String MinLength: 9 MaxLength: 18 Default: 0.0.0.0/0 ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. Subnets: Type: 'List<AWS::EC2::Subnet::Id>' Description: At least two public subnets in different Availability Zones in the selected VPC VPC: Type: 'AWS::EC2::VPC::Id' Description: A virtual private cloud (VPC) that enables resources in public subnets to connect to the internet Resources: ELBSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: ELB Security Group VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 EC2SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: EC2 Security Group VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: Fn::GetAtt: - ELBSecurityGroup - GroupId - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: !Ref SSHLocation EC2TargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 30 HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 15 HealthyThresholdCount: 5 Matcher: HttpCode: '200' Name: EC2TargetGroup Port: 80 Protocol: HTTP TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: '20' UnhealthyThresholdCount: 3 VpcId: !Ref VPC ALBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref EC2TargetGroup LoadBalancerArn: !Ref ApplicationLoadBalancer Port: 80 Protocol: HTTP ApplicationLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internet-facing Subnets: !Ref Subnets SecurityGroups: - !GetAtt ELBSecurityGroup.GroupId LaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateName: !Sub ${AWS::StackName}-launch-template LaunchTemplateData: ImageId: !Ref LatestAmiId InstanceType: !Ref InstanceType KeyName: !Ref KeyName SecurityGroupIds: - !Ref EC2SecurityGroup UserData: Fn::Base64: !Sub | #!/bin/bash yum update -y yum install -y httpd systemctl start httpd systemctl enable httpd echo "<h1>Hello World!</h1>" > /var/www/html/index.html NotificationTopic: Type: AWS::SNS::Topic Properties: Subscription: - Endpoint: !Ref OperatorEmail Protocol: email WebServerGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: LaunchTemplate: LaunchTemplateId: !Ref LaunchTemplate Version: !GetAtt LaunchTemplate.LatestVersionNumber MaxSize: '3' MinSize: '1' NotificationConfigurations: - TopicARN: !Ref NotificationTopic NotificationTypes: ['autoscaling:EC2_INSTANCE_LAUNCH', 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR', 'autoscaling:EC2_INSTANCE_TERMINATE', 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR'] TargetGroupARNs: - !Ref EC2TargetGroup VPCZoneIdentifier: !Ref Subnets

JSON

{ "AWSTemplateFormatVersion":"2010-09-09", "Parameters":{ "InstanceType":{ "Description":"The EC2 instance type", "Type":"String", "Default":"t3.micro", "AllowedValues":[ "t3.micro", "t3.small", "t3.medium" ] }, "KeyName":{ "Description":"Name of an existing EC2 key pair to allow SSH access to the instances", "Type":"AWS::EC2::KeyPair::KeyName" }, "LatestAmiId":{ "Description":"The latest Amazon Linux 2 AMI from the Parameter Store", "Type":"AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>", "Default":"/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" }, "OperatorEmail":{ "Description":"The email address to notify when there are any scaling activities", "Type":"String" }, "SSHLocation":{ "Description":"The IP address range that can be used to SSH to the EC2 instances", "Type":"String", "MinLength":9, "MaxLength":18, "Default":"0.0.0.0/0", "ConstraintDescription":"Must be a valid IP CIDR range of the form x.x.x.x/x." }, "Subnets":{ "Type":"List<AWS::EC2::Subnet::Id>", "Description":"At least two public subnets in different Availability Zones in the selected VPC" }, "VPC":{ "Type":"AWS::EC2::VPC::Id", "Description":"A virtual private cloud (VPC) that enables resources in public subnets to connect to the internet" } }, "Resources":{ "ELBSecurityGroup":{ "Type":"AWS::EC2::SecurityGroup", "Properties":{ "GroupDescription":"ELB Security Group", "VpcId":{ "Ref":"VPC" }, "SecurityGroupIngress":[ { "IpProtocol":"tcp", "FromPort":80, "ToPort":80, "CidrIp":"0.0.0.0/0" } ] } }, "EC2SecurityGroup":{ "Type":"AWS::EC2::SecurityGroup", "Properties":{ "GroupDescription":"EC2 Security Group", "VpcId":{ "Ref":"VPC" }, "SecurityGroupIngress":[ { "IpProtocol":"tcp", "FromPort":80, "ToPort":80, "SourceSecurityGroupId":{ "Fn::GetAtt":[ "ELBSecurityGroup", "GroupId" ] } }, { "IpProtocol":"tcp", "FromPort":22, "ToPort":22, "CidrIp":{ "Ref":"SSHLocation" } } ] } }, "EC2TargetGroup":{ "Type":"AWS::ElasticLoadBalancingV2::TargetGroup", "Properties":{ "HealthCheckIntervalSeconds":30, "HealthCheckProtocol":"HTTP", "HealthCheckTimeoutSeconds":15, "HealthyThresholdCount":5, "Matcher":{ "HttpCode":"200" }, "Name":"EC2TargetGroup", "Port":80, "Protocol":"HTTP", "TargetGroupAttributes":[ { "Key":"deregistration_delay.timeout_seconds", "Value":"20" } ], "UnhealthyThresholdCount":3, "VpcId":{ "Ref":"VPC" } } }, "ALBListener":{ "Type":"AWS::ElasticLoadBalancingV2::Listener", "Properties":{ "DefaultActions":[ { "Type":"forward", "TargetGroupArn":{ "Ref":"EC2TargetGroup" } } ], "LoadBalancerArn":{ "Ref":"ApplicationLoadBalancer" }, "Port":80, "Protocol":"HTTP" } }, "ApplicationLoadBalancer":{ "Type":"AWS::ElasticLoadBalancingV2::LoadBalancer", "Properties":{ "Scheme":"internet-facing", "Subnets":{ "Ref":"Subnets" }, "SecurityGroups":[ { "Fn::GetAtt":[ "ELBSecurityGroup", "GroupId" ] } ] } }, "LaunchTemplate":{ "Type":"AWS::EC2::LaunchTemplate", "Properties":{ "LaunchTemplateName":{ "Fn::Sub":"${AWS::StackName}-launch-template" }, "LaunchTemplateData":{ "ImageId":{ "Ref":"LatestAmiId" }, "InstanceType":{ "Ref":"InstanceType" }, "KeyName":{ "Ref":"KeyName" }, "SecurityGroupIds":[ { "Ref":"EC2SecurityGroup" } ], "UserData":{ "Fn::Base64":{ "Fn::Join":[ "", [ "#!/bin/bash\n", "yum update -y\n", "yum install -y httpd\n", "systemctl start httpd\n", "systemctl enable httpd\n", "echo \"<h1>Hello World!</h1>\" > /var/www/html/index.html" ] ] } } } } }, "NotificationTopic":{ "Type":"AWS::SNS::Topic", "Properties":{ "Subscription":[ { "Endpoint":{ "Ref":"OperatorEmail" }, "Protocol":"email" } ] } }, "WebServerGroup":{ "Type":"AWS::AutoScaling::AutoScalingGroup", "Properties":{ "LaunchTemplate":{ "LaunchTemplateId":{ "Ref":"LaunchTemplate" }, "Version":{ "Fn::GetAtt":[ "LaunchTemplate", "LatestVersionNumber" ] } }, "MaxSize":"3", "MinSize":"1", "NotificationConfigurations":[ { "TopicARN":{ "Ref":"NotificationTopic" }, "NotificationTypes":[ "autoscaling:EC2_INSTANCE_LAUNCH", "autoscaling:EC2_INSTANCE_LAUNCH_ERROR", "autoscaling:EC2_INSTANCE_TERMINATE", "autoscaling:EC2_INSTANCE_TERMINATE_ERROR" ] } ], "TargetGroupARNs":[ { "Ref":"EC2TargetGroup" } ], "VPCZoneIdentifier":{ "Ref":"Subnets" } } } } }

模板演练

此模板的第一部分指定了 Parameters。必须向每个参数分配一个运行时的值,使 Amazon CloudFormation 能够成功预置堆栈。稍后在模板中指定的资源会引用这些值并使用这些数据。

  • InstanceType:Amazon EC2 Auto Scaling 预置的 EC2 实例类型。如果未指定,则默认使用 t3.micro

  • KeyName:用于允许 SSH 访问实例的现有 EC2 密钥对。

  • LatestAmiId:实例的亚马逊机器映像(AMI)。如果未指定,则您的实例将使用由 Amazon 维护的 Amazon Systems Manager 公有参数,通过 Amazon Linux 2 AMI 启动。有关更多信息,请参阅 Amazon Systems Manager User Guide 中的 Finding public parameters

  • OperatorEmail:您要发送扩展活动通知的电子邮件地址。

  • SSHLocation:可用于通过 SSH 连接到实例的 IP 地址范围。

  • Subnets:位于不同可用区的至少两个公有子网。

  • VPC:您账户中的虚拟私有云(VPC),其允许公有子网中的资源连接到互联网。

    注意

    您可以使用默认 VPC 和默认子网来允许实例访问互联网。如果使用您自己的 VPC,请确保它拥有映射到您工作时所在区域的每个可用区的子网。您至少必须具有两个公有子网,且这些子网可用于创建负载均衡器。

此模板的下一个部分指定了 Resources。本部分指定堆栈资源及其属性。

AWS::EC2::SecurityGroup 资源 ELBSecurityGroup

  • SecurityGroupIngress 包含一个 TCP 入口规则,该规则允许来自端口 80 上的所有 IP 地址("CidrIp" : "0.0.0.0/0")的访问。

AWS::EC2::SecurityGroup 资源 EC2SecurityGroup

  • SecurityGroupIngress 包含两个入口规则:1) 允许来自您为 SSHLocation 输入参数提供的 IP 地址范围内的 SSH 访问(端口 22)的 TCP 入口规则;2) 允许通过指定负载均衡器的安全组实现的来自负载均衡器的访问的 TCP 入口规则。GetAtt 函数用于获取具有逻辑名称 ELBSecurityGroup 的安全组 ID。

AWS::ElasticLoadBalancingV2::TargetGroup 资源 EC2TargetGroup

  • PortProtocolHealthCheckProtocol 指定 ApplicationLoadBalancer 要向其中路由流量以及 Elastic Load Balancing 用于检查 EC2 实例运行状况的 EC2 实例端口(80)和协议(HTTP)。

  • HealthCheckIntervalSeconds 指定 EC2 实例的每次运行状况检查之间有 30 秒的时间间隔。HealthCheckTimeoutSeconds 定义为 Elastic Load Balancing 等待来自运行状况检查目标响应的时间(本示例中为 15 秒)。超时时间超过之后,Elastic Load Balancing 将标记 EC2 实例运行状况检查为“运行状况不佳”。当 EC2 实例连续三次未通过运行状况检查 (UnhealthyThresholdCount) 时,Elastic Load Balancing 会停止将流量路由到该 EC2 实例,直到该实例连续五次运行状况检查均正常 (HealthyThresholdCount)。此时,Elastic Load Balancing 认为实例运行状况良好,并再次开始将流量路由到该实例。

  • TargetGroupAttributes 将目标组的取消注册延迟值更新为 20 秒。默认情况下,Elastic Load Balancing 会等待 300 秒,才会完成注销过程。

AWS::ElasticLoadBalancingV2::Listener 资源 ALBListener

  • DefaultActions 指定负载均衡器侦听的端口、负载均衡器转发请求的目标组以及用于路由请求的协议。

AWS::ElasticLoadBalancingV2::LoadBalancer 资源 ApplicationLoadBalancer

  • SubnetsSubnets 输入参数的值作为要在其中创建负载均衡器节点的公有子网列表。

  • SecurityGroup 获取安全组的 ID,该安全组充当虚拟防火墙,以便负载均衡器节点控制传入流量。GetAtt 函数用于获取具有逻辑名称 ELBSecurityGroup 的安全组 ID。

AWS::EC2::LaunchTemplate 资源 LaunchTemplate

  • ImageIdLatestAmiId 输入参数的值作为要使用的 AMI。

  • KeyNameKeyName 输入参数的值作为要使用的 EC2 密钥对。

  • SecurityGroupIds 获取逻辑名称为 EC2SecurityGroup 的安全组的 ID,该安全组充当虚拟防火墙,以便 EC2 实例控制传入流量。

  • UserData 是在实例启动并运行之后运行的配置脚本。在此示例中,脚本安装 Apache 并创建 index.html 文件。

AWS::SNS::Topic 资源 NotificationTopic

  • 当有任何扩展活动时,SubscriptionOperatorEmail 输入参数的值作为通知收件人的电子邮件地址。

AWS::AutoScaling::AutoScalingGroup 资源 WebServerGroup

  • MinSizeMaxSize 设置自动扩缩组中的 EC2 实例的最小和最大数量。

  • TargetGroupARNs 使用逻辑名称为 EC2TargetGroup 的目标组的 ARN。随着此自动扩缩组的扩展,它会自动向该目标组注册和注销实例。

  • VPCZoneIdentifierSubnets 输入参数的值作为要在其中创建 EC2 实例的公有子网列表。

步骤 1:启动堆栈

在启动堆栈之前,请检查您是否拥有可以使用以下所有服务的 Amazon Identity and Access Management(IAM)权限:Amazon EC2、Amazon EC2 Auto Scaling、Amazon Systems Manager、Elastic Load Balancing、Amazon SNS 和 Amazon CloudFormation。

以下过程涉及从文件上传示例堆栈模板。在本地计算机上打开文本编辑器并添加其中一个模板。使用文件名 sampleloadbalancedappstack.template 保存该文件。

启动堆栈模板

  1. 登录到 Amazon Web Services Management Console 并打开 Amazon CloudFormation 控制台 https://console.aws.amazon.com/cloudformation

  2. 依次选择创建堆栈使用新资源(标准)

  3. 指定模板下,选择上传模板文件,然后选择选择文件,上传 sampleloadbalancedappstack.template 文件。

  4. 选择 Next(下一步)。

  5. 指定堆栈详细信息页面上,键入堆栈的名称(例如 SampleLoadBalancedAppStack)。

  6. 参数下,查看堆栈的参数并为没有默认值的所有参数提供值,包括 OperatorEmailSSHLocationKeyNameVPCSubnets

  7. 选择 Next(下一步)两次。

  8. Review 页面上,审核并确认设置。

  9. 选择提交

    您可以在 Amazon CloudFormation 控制台的 Status (状态) 列中查看堆栈的状态。Amazon CloudFormation 成功创建堆栈后,您将收到 CREATE_COMPLETE 状态。

    注意

    创建堆栈后,必须先确认订阅,电子邮件地址才能开始接收通知。有关更多信息,请参阅《Amazon EC2 Auto Scaling 用户指南》中的自动扩缩组扩展时获取 Amazon SNS 通知

步骤 2:清除示例资源

为确保您无需为未使用的示例资源付费,请删除堆栈。

删除堆栈
  1. 在 Amazon CloudFormation 控制台中,选择 SampleLoadBalancedAppStack 堆栈。

  2. 选择 Delete (删除)

  3. 在确认消息中,选择删除堆栈

    SampleLoadBalancedAppStack 的状态更改为 DELETE_IN_PROGRESS。当 Amazon CloudFormation 完成删除堆栈后,它会将从列表中移堆栈除。

使用本演练中的示例模板构建您自己的堆栈模板。有关更多信息,请参阅 Amazon EC2 Auto Scaling User Guide 中的 Tutorial: Set up a scaled and load-balanced application