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