使用 Auto Scaling 组保持应用容量

AWSBeginner
立即练习

简介

负载均衡器可以避开故障应用,但本身不会创建替代服务器。本实验将创建启动模板和 Auto Scaling 组,保持两台应用实例。你将让一个应用故障,观察自动替换产生的新实例 ID,并验证新服务器真正处理请求。

你应已理解 EC2 User Data、ALB 目标组和应用健康检查。本次全新环境提供网络、应用镜像、密钥对,以及带 HTTP 监听器的空 ALB 目标组,没有现成的应用实例池。AWS CLI 和连接文件独立于前面的实验准备。

认证考点关联

本实验为以下认证考点提供入门实践。

创建应用启动模板

本步骤定义 Auto Scaling 启动每台应用服务器时使用的配置。

进入工作目录,加载已准备好的网络变量:

cd /home/labex/project
source launch.env

启动模板保存 AMI、实例类型、安全组和启动配置等实例设置。查看已提供的配置:

cat launch-template.json
cat application-user-data.sh

JSON 选择了已准备好的 AMI、t3.micro、report-key 和应用安全组。UserData 包含另行展示的启动脚本的 base64 编码。脚本创建初始配置,将消息设为 Application ready、healthy 设为 true。Auto Scaling 每次启动都必须应用该配置,让替代实例就绪;只在某台旧服务器内部手动修改不会改变模板。

创建模板。file:// 告诉 AWS CLI 将 JSON 文件内容作为参数值:

LT_ID=$(aws ec2 \
  create-launch-template \
  --launch-template-name application-template \
  --launch-template-data file://launch-template.json \
  --query 'LaunchTemplate.LaunchTemplateId' \
  --output text)

模板具有编号的版本。查看组将显式使用的版本 1:

aws ec2 \
  describe-launch-template-versions \
  --launch-template-id "$LT_ID" \
  --versions 1 \
  --query 'LaunchTemplateVersions[].{Version:VersionNumber,AMI:LaunchTemplateData.ImageId,Type:LaunchTemplateData.InstanceType,Key:LaunchTemplateData.KeyName,Groups:LaunchTemplateData.SecurityGroupIds}'

创建模板不会启动实例。打开 AWS View:已提供的 ALB 和目标组存在,但尚无已注册应用目标。

启动并连接应用实例池

本步骤创建 Auto Scaling 组,将其真实应用实例连接到已提供的 ALB。

Auto Scaling 组在最小和最大容量范围内保持期望实例数量。期望容量是组要维持的数量,不是请求吞吐量的度量。最小 2、期望 2、最大 3 表示初始两台服务器,并允许增加一台。

保存已提供目标组的 ARN 和负载均衡器的 DNS 名称:

TG_ARN=$(aws elbv2 \
  describe-target-groups \
  --names application-targets \
  --query 'TargetGroups[0].TargetGroupArn' \
  --output text)

LB_DNS=$(aws elbv2 \
  describe-load-balancers \
  --names application-alb \
  --query 'LoadBalancers[0].DNSName' \
  --output text)

使用模板版本 1 和两个已准备好的子网创建组。--target-group-arns 自动将组实例注册到 ALB。--health-check-type ELB 将负载均衡健康状态纳入替换判断;仅靠 EC2 检查无法发现所有应用故障。宽限期给新实例留出启动时间,之后应用健康状态才会导致替换。本练习使用 30 秒,生产值应匹配应用启动行为:

aws autoscaling \
  create-auto-scaling-group \
  --auto-scaling-group-name application-fleet \
  --launch-template "LaunchTemplateId=$LT_ID,Version=1" \
  --min-size 2 \
  --max-size 3 \
  --desired-capacity 2 \
  --vpc-zone-identifier "$SUBNET_ID,$SECOND_SUBNET_ID" \
  --target-group-arns "$TG_ARN" \
  --health-check-type ELB \
  --health-check-grace-period 30

查看组及其实例 ID:

aws autoscaling \
  describe-auto-scaling-groups \
  --auto-scaling-group-names application-fleet \
  --query 'AutoScalingGroups[].{Min:MinSize,Desired:DesiredCapacity,Max:MaxSize,HealthCheck:HealthCheckType,Grace:HealthCheckGracePeriod,Instances:Instances[].InstanceId}'

等待应用就绪,再查看 ALB 目标:

aws elbv2 \
  wait target-in-service \
  --target-group-arn "$TG_ARN"

aws elbv2 \
  describe-target-health \
  --target-group-arn "$TG_ARN" \
  --query 'TargetHealthDescriptions[].{Instance:Target.Id,Health:TargetHealth.State}' \
  --output table

预期为两个健康 ID。发送六个请求,将响应 ID 与组实例对照:

for request in 1 2 3 4 5 6; do
  curl --config client.conf -sS "http://$LB_DNS/health"
  echo
done

打开 AWS View。确认期望容量 2、两个健康目标,并通过 Send request 观察两个 ID 的真实 200 响应。子网和可用区标签表示配置,本练习不测量实际跨可用区容灾能力。

观察自动故障替换

本步骤让应用故障,并由组替换该实例,而不是手动修复。

选择一个当前组实例,保存其用于 SSH 的公网地址:

OLD_ID=$(aws autoscaling \
  describe-auto-scaling-groups \
  --auto-scaling-group-names application-fleet \
  --query 'AutoScalingGroups[0].Instances[0].InstanceId' \
  --output text)

OLD_IP=$(aws ec2 \
  describe-instances \
  --instance-ids "$OLD_ID" \
  --query 'Reservations[0].Instances[0].PublicIpAddress' \
  --output text)

只修改 healthy,让应用返回 503。与上一个实验一样,使用临时 JSON 文件避免读取时覆盖:

ssh -F ssh_config "ubuntu@$OLD_IP" \
  'sudo jq ".healthy = false" /etc/report-app/config.json > /tmp/report-config.json && sudo install -m 644 /tmp/report-config.json /etc/report-app/config.json'

ssh -F ssh_config "ubuntu@$OLD_IP" \
  'curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8081/health'

预期为 503。应用故障时实例仍在运行。ALB 检测健康检查失败;启动宽限期结束后,组会替换不健康实例以恢复期望容量。相同启动模板会让替代实例以健康配置启动。

保持 AWS View 打开,观察 ID 和健康状态变化。检测后会紧接着替换,不健康状态可能很短;新目标也可能先显示 initial,再变为健康。不要手动修复,也不要额外执行 run-instances。

等待旧实例终止,并等待目标组健康:

aws ec2 \
  wait instance-terminated \
  --instance-ids "$OLD_ID"

aws elbv2 \
  wait target-in-service \
  --target-group-arn "$TG_ARN"

查看旧实例和当前组:

aws ec2 \
  describe-instances \
  --instance-ids "$OLD_ID" \
  --query 'Reservations[].Instances[].{Instance:InstanceId,State:State.Name}'

aws autoscaling \
  describe-auto-scaling-groups \
  --auto-scaling-group-names application-fleet \
  --query 'AutoScalingGroups[].{Desired:DesiredCapacity,Instances:Instances[].InstanceId}'

旧 ID 应为 terminated。期望容量仍为 2,新 ID 替代了旧 ID。替代实例是重新初始化的服务器;只在旧服务器内部进行的修改不会自动保留。

再次发送六个请求:

for request in 1 2 3 4 5 6; do
  curl --config client.conf -sS "http://$LB_DNS/health"
  echo
done

查找两个当前组 ID,包括替代实例,且不应出现旧 ID。在 AWS View 中确认两个健康目标,并通过 Send request 观察替代实例真正响应。仅有原生资源数量还不能证明新应用可用。

替代实例处理请求

示例:期望容量保持为两台,新创建的实例返回 HTTP 200。你的实例 ID 会不同。

删除实例池和启动模板

本步骤删除你的组、实例和启动模板,保留已提供的 ALB 和网络。

用 --force-delete 删除组,即使最小容量为 2,也终止其实例。仅删除模板不会停止运行中的实例:

aws autoscaling \
  delete-auto-scaling-group \
  --auto-scaling-group-name application-fleet \
  --force-delete

aws ec2 \
  wait instance-terminated \
  --filters "Name=tag:aws:autoscaling:groupName,Values=application-fleet"

aws ec2 \
  delete-launch-template \
  --launch-template-id "$LT_ID"

等待器通过 Auto Scaling 自动添加的标签选择本组实例,包括先前被替换的旧实例,并等待所有选中实例终止。检查组已不存在、模板列表和目标注册:

aws autoscaling \
  describe-auto-scaling-groups \
  --auto-scaling-group-names application-fleet \
  --query 'AutoScalingGroups[].AutoScalingGroupName'

aws ec2 \
  describe-launch-templates \
  --query 'LaunchTemplates[].LaunchTemplateName'

aws elbv2 \
  describe-target-health \
  --target-group-arn "$TG_ARN" \
  --query 'TargetHealthDescriptions[].Target.Id'

三个列表都应为 []。目标取消注册可能需要时间;如果仍在进行,稍等并重复最后的查询。AWS View 应保留 ALB 和目标组,但不显示实例池和已注册应用目标。保留已提供的网络、AMI 和密钥对。

总结

你创建了带版本的启动模板和 Auto Scaling 组,保持两台真实应用服务器。你将 ALB 健康检查纳入替换判断,制造应用故障,并验证新实例 ID 真正处理请求。最后,你删除了组、实例和模板,保留了已提供的负载均衡器和网络。

下一个实验将通过简单扩缩策略改变期望容量,并测试组的上下限。