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