AWS for DevOps — Auto Scaling
3.5 — Auto Scaling
Auto Scaling automatically adjusts the number of EC2 instances based on demand. When traffic increases, it adds instances. When traffic drops, it removes them. This is how you build systems that are both resilient and cost-efficient.
Components
┌── Launch Template ──────────────────────────┐
│ AMI: ami-0custom123 │
│ Instance Type: t3.medium │
│ Key Pair: devops-key │
│ Security Groups: [sg-app123] │
│ User Data: setup.sh │
│ IAM Instance Profile: app-role │
└─────────────────────────────────────────────┘
│
▼
┌── Auto Scaling Group ──────────────────────┐
│ Min: 2 Desired: 3 Max: 10 │
│ Subnets: [subnet-1a, subnet-1b, subnet-1c]│
│ Health Check: ELB │
│ Target Group: app-tg │
│ │
│ Scaling Policies: │
│ - CPU > 70% → add 2 instances │
│ - CPU < 30% → remove 1 instance │
└─────────────────────────────────────────────┘
Launch Template
A launch template defines how instances are created:
$ aws ec2 create-launch-template \
--launch-template-name web-app-template \
--version-description "v1 - Nginx + app" \
--launch-template-data '{
"ImageId": "ami-0custom123",
"InstanceType": "t3.medium",
"KeyName": "devops-key",
"SecurityGroupIds": ["sg-app123"],
"IamInstanceProfile": {"Name": "app-instance-profile"},
"UserData": "'$(base64 -w0 setup.sh)'",
"TagSpecifications": [
{
"ResourceType": "instance",
"Tags": [
{"Key": "Name", "Value": "web-app"},
{"Key": "Environment", "Value": "production"}
]
}
],
"MetadataOptions": {
"HttpTokens": "required",
"HttpEndpoint": "enabled"
}
}'
Creating an Auto Scaling Group
$ aws autoscaling create-auto-scaling-group \
--auto-scaling-group-name web-app-asg \
--launch-template LaunchTemplateName=web-app-template,Version='$Latest' \
--min-size 2 \
--max-size 10 \
--desired-capacity 3 \
--vpc-zone-identifier "subnet-1a,subnet-1b,subnet-1c" \
--target-group-arns arn:aws:elasticloadbalancing:ap-south-1:123456789012:targetgroup/app-tg/abc123 \
--health-check-type ELB \
--health-check-grace-period 300 \
--tags Key=Name,Value=web-app,PropagateAtLaunch=true \
Key=Environment,Value=production,PropagateAtLaunch=true
| Parameter | Purpose |
|---|---|
min-size |
Never fewer than this many instances |
max-size |
Never more than this many instances |
desired-capacity |
Target number (ASG tries to maintain this) |
health-check-type ELB |
Use ALB health checks (not just EC2 status) |
health-check-grace-period |
Wait 300s after launch before checking health |
Scaling Policies
Target Tracking (recommended) — ASG automatically adjusts to maintain a metric:
$ aws autoscaling put-scaling-policy \
--auto-scaling-group-name web-app-asg \
--policy-name cpu-target-70 \
--policy-type TargetTrackingScaling \
--target-tracking-configuration '{
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ASGAverageCPUUtilization"
},
"TargetValue": 70.0,
"ScaleInCooldown": 300,
"ScaleOutCooldown": 60
}'
This says: “Keep average CPU at 70%. Add instances when above, remove when below.”
Step Scaling — define specific thresholds:
$ aws autoscaling put-scaling-policy \
--auto-scaling-group-name web-app-asg \
--policy-name high-cpu-step \
--policy-type StepScaling \
--adjustment-type ChangeInCapacity \
--step-adjustments \
'MetricIntervalLowerBound=0,MetricIntervalUpperBound=20,ScalingAdjustment=1' \
'MetricIntervalLowerBound=20,ScalingAdjustment=3'
Scheduled Scaling — for predictable traffic patterns:
# Scale up every weekday at 8 AM
$ aws autoscaling put-scheduled-update-group-action \
--auto-scaling-group-name web-app-asg \
--scheduled-action-name morning-scale-up \
--recurrence "0 8 * * MON-FRI" \
--desired-capacity 6
# Scale down at 8 PM
$ aws autoscaling put-scheduled-update-group-action \
--auto-scaling-group-name web-app-asg \
--scheduled-action-name evening-scale-down \
--recurrence "0 20 * * MON-FRI" \
--desired-capacity 2
Monitoring the ASG
# Check current state
$ aws autoscaling describe-auto-scaling-groups \
--auto-scaling-group-names web-app-asg \
--query 'AutoScalingGroups[0].{Min:MinSize,Max:MaxSize,Desired:DesiredCapacity,Instances:Instances[*].{Id:InstanceId,Health:HealthStatus,AZ:AvailabilityZone}}'
{
"Min": 2,
"Max": 10,
"Desired": 3,
"Instances": [
{"Id": "i-0abc1", "Health": "Healthy", "AZ": "ap-south-1a"},
{"Id": "i-0abc2", "Health": "Healthy", "AZ": "ap-south-1b"},
{"Id": "i-0abc3", "Health": "Healthy", "AZ": "ap-south-1c"}
]
}
# View scaling activities
$ aws autoscaling describe-scaling-activities \
--auto-scaling-group-name web-app-asg \
--query 'Activities[0:3].[StartTime,StatusCode,Description]' \
--output table
Instance Refresh (Rolling Deployments)
When you update the launch template (e.g., new AMI), use instance refresh to roll out the change:
$ aws autoscaling start-instance-refresh \
--auto-scaling-group-name web-app-asg \
--preferences '{
"MinHealthyPercentage": 90,
"InstanceWarmup": 300
}'
This replaces instances in batches, keeping at least 90% healthy at all times.
Real-World Analogy
Think of Auto Scaling like a restaurant staffing model:
- Min size = skeleton crew (always at least 2 waiters)
- Desired = normal staffing (3 waiters for typical lunch)
- Max size = maximum capacity (10 waiters for a holiday rush)
- Scaling policy = “if tables are more than 70% full, call in another waiter”
- Cooldown = “wait 5 minutes before calling another one”
Common Mistakes
| Mistake | Why It Hurts | Fix |
|---|---|---|
| Setting min = max = desired | Defeats the purpose of Auto Scaling | Set a range (e.g., 2-10) |
| Not using ELB health checks | Unhealthy instances stay in the group | Set health-check-type ELB |
| Too short cooldown | Thrashing — adding and removing rapidly | Set cooldown to 300s+ |
| No health check grace period | New instances killed before they’re ready | Set grace period to match boot time |
| Not spreading across AZs | One AZ outage takes down everything | Use subnets in 2-3 AZs |
Quick Reference
| Task | Command |
|---|---|
| Create launch template | aws ec2 create-launch-template --launch-template-name NAME --launch-template-data ... |
| Create ASG | aws autoscaling create-auto-scaling-group --auto-scaling-group-name NAME ... |
| Set target tracking | aws autoscaling put-scaling-policy --policy-type TargetTrackingScaling ... |
| Set scheduled action | aws autoscaling put-scheduled-update-group-action --scheduled-action-name NAME ... |
| Start instance refresh | aws autoscaling start-instance-refresh --auto-scaling-group-name NAME |
| View ASG | aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names NAME |
| Update desired capacity | aws autoscaling set-desired-capacity --auto-scaling-group-name NAME --desired-capacity N |
Next → Compute Exercises