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

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

在本演练中,您将创建一个堆栈,该堆栈可帮助您设置已扩展且负载平衡的应用程序。此演练为您提供将用于创建堆栈的示例模板。此示例模板预置了 Amazon EC2 Auto Scaling 组、应用程序负载均衡器、控制负载均衡器和 Amazon EC2 Auto Scaling 组流量的安全组,以及用于发布有关扩展活动的通知的 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 要向其中路由流量以及 ELB 用于检查 EC2 实例运行状况的 EC2 实例端口(80)和协议(HTTP)。

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

  • TargetGroupAttributes 将目标组的取消注册延迟值更新为 20 秒。默认情况下,ELB 会等待 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 设置 Amazon EC2 Auto Scaling 组中的 EC2 实例的最小和最大数量。

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

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

步骤 1:启动堆栈

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

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

启动堆栈模板
  1. 登录到 Amazon Web Services 管理控制台 并打开 Amazon CloudFormation 控制台 https://console.aws.amazon.com/cloudformation

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

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

  4. 选择下一步

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

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

  7. 选择下一步两次。

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

  9. 选择提交

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

    注意

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

步骤 2:清除示例资源

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

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

  2. 选择删除

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

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

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