创建已扩展且负载均衡的应用程序
在本演练中,您将创建一个堆栈,该堆栈可帮助您设置已扩展且负载平衡的应用程序。此演练为您提供将用于创建堆栈的示例模板。此示例模板预置了自动扩缩组、应用程序负载均衡器、控制负载均衡器和自动扩缩组流量的安全组,以及用于发布有关扩展活动的通知的 Amazon SNS 通知配置。
本模板将创建一个或多个 Amazon EC2 实例和一个应用程序负载均衡器。如果您通过本模板创建堆栈,则需为使用的 AWS 资源支付相应费用。
完整堆栈模板
我们从使用模板开始。
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。必须向每个参数分配一个运行时的值,使 AWS CloudFormation 能够成功预置堆栈。稍后在模板中指定的资源会引用这些值并使用这些数据。
- 
        InstanceType:Amazon EC2 Auto Scaling 预置的 EC2 实例类型。如果未指定,则默认使用t3.micro。
- 
        KeyName:用于允许 SSH 访问实例的现有 EC2 密钥对。
- 
        LatestAmiId:实例的亚马逊机器映像(AMI)。如果未指定,则您的实例将使用由 AWS 维护的 AWS Systems Manager 公有参数,通过 Amazon Linux 2 AMI 启动。有关更多信息,请参阅 AWS 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
- 
        Port、Protocol和HealthCheckProtocol指定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
- 
        Subnets将Subnets输入参数的值作为要在其中创建负载均衡器节点的公有子网列表。
- 
        SecurityGroup获取安全组的 ID,该安全组充当虚拟防火墙,以便负载均衡器节点控制传入流量。GetAtt 函数用于获取具有逻辑名称ELBSecurityGroup的安全组 ID。
AWS::EC2::LaunchTemplate 资源 LaunchTemplate
- 
        ImageId将LatestAmiId输入参数的值作为要使用的 AMI。
- 
        KeyName将KeyName输入参数的值作为要使用的 EC2 密钥对。
- 
        SecurityGroupIds获取逻辑名称为EC2SecurityGroup的安全组的 ID,该安全组充当虚拟防火墙,以便 EC2 实例控制传入流量。
- 
        UserData是在实例启动并运行之后运行的配置脚本。在此示例中,脚本安装 Apache 并创建 index.html 文件。
AWS::SNS::Topic 资源 NotificationTopic
- 
        当有任何扩展活动时, Subscription将OperatorEmail输入参数的值作为通知收件人的电子邮件地址。
AWS::AutoScaling::AutoScalingGroup 资源 WebServerGroup
- 
        MinSize和MaxSize设置自动扩缩组中的 EC2 实例的最小和最大数量。
- 
        TargetGroupARNs使用逻辑名称为EC2TargetGroup的目标组的 ARN。随着此自动扩缩组的扩展,它会自动向该目标组注册和注销实例。
- 
        VPCZoneIdentifier将Subnets输入参数的值作为要在其中创建 EC2 实例的公有子网列表。
步骤 1:启动堆栈
在启动堆栈之前,请检查您是否拥有可以使用以下所有服务的 AWS Identity and Access Management(IAM)权限:Amazon EC2、Amazon EC2 Auto Scaling、AWS Systems Manager、Elastic Load Balancing、Amazon SNS 和 AWS CloudFormation。
以下过程涉及从文件上传示例堆栈模板。在本地计算机上打开文本编辑器并添加其中一个模板。使用文件名 sampleloadbalancedappstack.template 保存该文件。
启动堆栈模板
-  登录到 AWS Management Console 并打开 AWS CloudFormation 控制台 https://console.aws.amazon.com/cloudformation 。 
- 
        依次选择创建堆栈和使用新资源(标准)。 
- 
        在指定模板下,选择上传模板文件,然后选择选择文件,上传 sampleloadbalancedappstack.template文件。
- 
        选择下一步。 
- 
        在指定堆栈详细信息页面上,键入堆栈的名称(例如 SampleLoadBalancedAppStack)。
- 
        在参数下,查看堆栈的参数并为没有默认值的所有参数提供值,包括 OperatorEmail、SSHLocation、KeyName、VPC 和 Subnets。 
- 
        选择 Next(下一步)两次。 
- 
        在 Review 页面上,审核并确认设置。 
- 
        选择提交。 您可以在 AWS CloudFormation 控制台的状态列中查看堆栈的状态。AWS CloudFormation 成功创建堆栈后,您将收到 CREATE_COMPLETE 状态。 注意创建堆栈后,必须先确认订阅,电子邮件地址才能开始接收通知。有关更多信息,请参阅《Amazon EC2 Auto Scaling 用户指南》中的自动扩缩组扩展时获取 Amazon SNS 通知。 
步骤 2:清除示例资源
为确保您无需为未使用的示例资源付费,请删除堆栈。
删除堆栈
- 
        在 AWS CloudFormation 控制台中,选择 SampleLoadBalancedAppStack 堆栈。 
- 
        选择删除。 
- 
        在确认消息中,选择删除堆栈。 SampleLoadBalancedAppStack 的状态更改为 DELETE_IN_PROGRESS。当 AWS CloudFormation 完成删除堆栈后,它会将从列表中移堆栈除。 
使用本演练中的示例模板构建您自己的堆栈模板。有关更多信息,请参阅 Amazon EC2 Auto Scaling User Guide 中的 Tutorial: Set up a scaled and load-balanced application。