Home / AWS

AWSHow-toIntermediate

Multi-AZ web tier on AWS: Auto Scaling groups behind an Application Load Balancer

Build a self-healing EC2 web tier across three AZs with a launch template, ELB health checks, instance refresh and capacity planning for losing an AZ.

Deepak Bhardwaj2 min read

Applies toAmazon EC2 Auto Scaling, Application Load Balancer

Architecture

            ALB (subnets in AZ a, b, c)
     ┌─────────────┼─────────────┐
  ASG instance   ASG instance   ASG instance
  (ap-south-1a)  (ap-south-1b)  (ap-south-1c)

1. Launch template

AMI built by a pipeline (EC2 Image Builder), IMDSv2 required, instance profile, user data that only pulls config and starts the app. No hand-built servers.

2. Auto Scaling group

aws autoscaling create-auto-scaling-group --auto-scaling-group-name asg-web \
  --launch-template LaunchTemplateName=lt-web,Version='$Latest' \
  --min-size 3 --max-size 12 --desired-capacity 3 \
  --vpc-zone-identifier "subnet-a,subnet-b,subnet-c" \
  --target-group-arns arn:aws:elasticloadbalancing:ap-south-1:111122223333:targetgroup/tg-web/abc \
  --health-check-type ELB --health-check-grace-period 120 \
  --default-instance-warmup 120
  • --health-check-type ELB: instances failing the load balancer health check get replaced, not only those failing EC2 status checks.
  • Spread across AZs is automatic; ASG rebalances when an AZ comes back.

3. Target group health check

aws elbv2 modify-target-group --target-group-arn <arn> \
  --health-check-path /healthz --health-check-interval-seconds 15 \
  --healthy-threshold-count 2 --unhealthy-threshold-count 3 --matcher HttpCode=200
aws elbv2 modify-target-group-attributes --target-group-arn <arn> \
  --attributes Key=deregistration_delay.timeout_seconds,Value=30

Keep /healthz fast and local. If it calls the database and the database blips, every instance fails at once and the ASG starts replacing healthy servers.

4. Scaling policy

Target tracking on ALBRequestCountPerTarget or average CPU:

aws autoscaling put-scaling-policy --auto-scaling-group-name asg-web --policy-name cpu50 \
  --policy-type TargetTrackingScaling \
  --target-tracking-configuration '{"PredefinedMetricSpecification":{"PredefinedMetricType":"ASGAverageCPUUtilization"},"TargetValue":50}'

5. Plan for losing an AZ

With 3 AZs, losing one removes ~33% of capacity. Either keep enough headroom (min 3, target ~50–60% CPU) or rely on scaling, and confirm the instance types have capacity in the remaining AZs (use multiple instance types in a mixed instances policy).

6. Deployments

  • Instance refresh for new AMIs/launch template versions, with minimum healthy percentage (for example 90%) and checkpoints.
  • Or blue/green with two target groups and weighted ALB listener rules.
aws autoscaling start-instance-refresh --auto-scaling-group-name asg-web \
  --preferences '{"MinHealthyPercentage":90,"InstanceWarmup":120}'

Stateless is the requirement

Sessions in ElastiCache/DynamoDB, uploads in S3, config in Parameter Store. If an instance holds state, the ASG replacing it causes data loss.

Tip

Test with AWS Fault Injection Service: stop instances in one AZ, or simulate an AZ power interruption, and watch the ALB HealthyHostCount and error rate.