Introduction
AWS Auto Scaling Groups are a foundational component for building scalable and highly available cloud infrastructure. An ASG helps ensure that the correct number of Amazon EC2 instances is available to handle the load for an application. You create collections of EC2 instances, called Auto Scaling groups, and specify the minimum, maximum, and desired capacity for each group. Using Auto Scaling groups enables automatic scaling and management of a logical grouping of instances.
Terraform is a preferred Infrastructure as Code tool to set up ASGs over manual configuration in the AWS console because it brings consistency, version control, and automation to deployments. Defining scaling in code once and reusing it across environments avoids manual changes in production. A core concept is that an Auto Scaling Group in AWS is a collection of EC2 instances treated as a logical grouping for automatic scaling and management, with minsize, maxsize and desired_capacity controlling the fleet.
Core Concepts and Terminology
An ASG is a logical grouping of EC2 instances running the same configuration. ASGs allow for dynamic scaling and make it easier to manage a group of instances that host the same services.
The basic parameters that define an ASG are:
- min_size: minimum number of instances allowed in the group
- max_size: maximum number of instances allowed in the group
- desired_capacity: the target count to launch
- launch_configuration or launch template: the configuration used for each instance
- vpczoneidentifier: list of subnets where new instances will launch
You cannot modify a launch configuration. Any changes to the definition force Terraform to create a new resource. The createbeforedestroy argument in the lifecycle block instructs Terraform to create the new version before destroying the original to avoid service interruptions.
Terraform is not aware of the member instances of the group, only the capacity. You can scale the number of instances manually, which allows launching more instances running the same configuration, but requires monitoring infrastructure to understand when to modify capacity.
Auto Scaling groups also support automated scaling events, which can be implemented using Terraform.
Reference Implementation with Launch Template and Dynamic Scaling
A hands-on Terraform IaC setup for a highly available, scalable web environment demonstrates the full workflow.
The infrastructure includes:
- Default VPC and subnets ap-south-1a and ap-south-1b
- Security Group allowing HTTP 80 and SSH 22
- Launch Template with Ubuntu AMI and Apache Web Server
- Auto Scaling Group with dynamic scale-out and scale-in policies based on CPU utilization
- CloudWatch Alarms to trigger ASG scaling automatically
Architecture flow is Load/Stress to Auto Scaling Group to EC2 Instance 1 and EC2 Instance 2 running Apache Web Server. The ASG ensures instances scale automatically based on CPU utilization. CloudWatch monitors CPU metrics and triggers scale-out when CPU exceeds 60 percent or scale-in when CPU drops below 20 percent policies.
Prerequisites for this deployment are:
- Terraform >= 1.5.0
- AWS CLI configured with proper IAM permissions
- Existing SSH key pair ebsinstancekry in ap-south-1
- Ubuntu AMI ami-02d26659fd82cf299 in ap-south-1
How to deploy:
- Clone the repository
- Initialize Terraform
- Plan the deployment
- Apply the configuration
Terraform will create the security group, launch template, ASG, and CloudWatch alarms.
Testing auto scaling involves SSH into any ASG instance with ssh -i ebsinstancekry.pem ubuntu@ and generating CPU load with sudo apt-get install -y stress and stress --cpu 1 --timeout 300. Monitoring is done via terraform output asginstancepublic_ips. New instances launch automatically when CPU exceeds threshold and scale-in occurs when CPU drops below threshold.
Outputs provided are asgname and asginstancepublicips.
Notes from this setup:
- Uses default VPC and subnets for simplicity and ease of deployment
- t2.micro instances are burstable; CPU may not sustain high load long enough without credits
- CloudWatch alarms and scaling policies ensure dynamic scaling without manual intervention
- Apache web server is installed and configured automatically via user-data in the launch template
HashiCorp Tutorial Configuration
A Terraform tutorial uses a launch configuration named terramino and an ASG named terramino.
The user data script installs dependencies and initializes Terramino, a Terraform-skinned Tetris application. A security group is associated with the instances and allows ingress traffic on port 80 and egress traffic to all endpoints.
Example main.tf resource:
hcl
resource "aws_autoscaling_group" "terramino" {
min_size = 1
max_size = 3
desired_capacity = 1
launch_configuration = aws_launch_configuration.terramino.name
vpc_zone_identifier = module.vpc.public_subnets
}
This ASG configuration sets the minimum and maximum number of instances allowed in the group, the desired count to launch, a launch configuration to use for each instance, and a list of subnets where the ASGs will launch new instances.
The tutorial assumes familiarity with the standard Terraform workflow. Requirements are Terraform v1.8+ installed locally, an AWS account with credentials configured for Terraform, and the AWS CLI.
Steps are to clone the example repository, change into the repository directory, and open main.tf to review configuration. The configuration uses the vpc module to create a new VPC with public subnets for provisioning the rest of the resources. Other resources reference the VPC module outputs.
Lifecycle arguments can be used to avoid unwanted scaling of the ASG.
Terraform AWS Autoscaling Module Features
A community Terraform module creates Auto Scaling resources on AWS.
Capabilities include:
- Autoscaling group with launch template - either created by the module or utilizing an existing launch template
- Autoscaling group utilizing mixed instances policy
- Ability to configure autoscaling groups to set instance refresh configuration and add lifecycle hooks
- Ability to create an autoscaling group that respects desired_capacity or one that ignores to allow for scaling without conflicting Terraform diffs
- IAM role and instance profile creation
Example module usage:
hcl
module "asg" {
source = "terraform-aws-modules/autoscaling/aws"
name = "example-asg"
min_size = 0
max_size = 1
desired_capacity = 1
wait_for_capacity_timeout = 0
health_check_type = "EC2"
vpc_zone_identifier = ["subnet-1235678", "subnet-87654321"]
initial_lifecycle_hooks = [
{
name = "ExampleStartupLifeCycleHook"
default_result = "CONTINUE"
heartbeat_timeout = 60
lifecycle_transition = "autoscaling:EC2_INSTANCE_LAUNCHING"
notification_metadata = jsonencode({ "hello" = "world" })
},
{
name = "ExampleTerminationLifeCycleHook"
default_result = "CONTINUE"
heartbeat_timeout = 180
lifecycle_transition = "autoscaling:EC2_INSTANCE_TERMINATING"
notification_metadata = jsonencode({ "goodbye" = "world" })
}
]
instance_refresh = {
strategy = "Rolling"
preferences = {
checkpoint_delay = 600
checkpoint_percentages = [35, 70, 100]
instance_warmup = 300
min_healthy_percentage = 50
max_healthy_percentage = 100
}
triggers = ["tag"]
}
}
Specification Comparison
| Component | Detail |
|---|---|
| ASG scaling triggers | CPU >60% scale-out, CPU <20% scale-in |
| Launch template AMI | ami-02d26659fd82cf299 Ubuntu |
| Subnets | ap-south-1a, ap-south-1b |
| Security group ports | HTTP 80, SSH 22 |
| Terraform minimum version | >=1.5.0 for reference repo, v1.8+ for tutorial |
| Instance type note | t2.micro burstable |
| Parameter | Example Value |
|---|---|
| min_size | 1 |
| max_size | 3 |
| desired_capacity | 1 |
| healthchecktype | EC2 |
| waitforcapacity_timeout | 0 |
Deployment steps:
- Clone the repository
- Run terraform init
- Run terraform plan
- Run terraform apply
- Confirm with yes when prompted
Best Practices and Operational Notes
Using Terraform for ASGs brings consistency, version control, and automation to deployments and avoids ClickOps in production. Launch templates are preferred over launch configurations because templates can be versioned and updated.
Createbeforedestroy lifecycle management prevents service interruption when replacing launch configurations. Instance refresh with rolling strategy and preferences for checkpoint delay, instance warmup, and healthy percentages allows controlled updates.
Lifecycle hooks enable actions on instance launching and termination with heartbeat timeout and notification metadata.
Outputs such as asgname and asginstancepublicips simplify post-deployment validation and testing.
Monitoring ASG behavior requires checking public IPs and generating load to validate scale-out and scale-in. Burstable instances like t2.micro may not sustain high CPU load long enough without credits, which impacts test reliability.
CloudWatch alarms and scaling policies ensure dynamic scaling without manual intervention. User-data can install and configure services automatically, such as Apache web server.
Conclusion
Terraform ASG implementations combine declarative capacity control with dynamic, metric-driven scaling to deliver production-ready cloud architectures. The core ASG parameters of minsize, maxsize and desiredcapacity provide guardrails, while launch templates enable immutable instance definitions and safe replacements via createbefore_destroy.
Reference deployments show a complete path from default VPC and subnets in ap-south-1a and ap-south-1b, through a security group allowing HTTP 80 and SSH 22, to a launch template with Ubuntu AMI ami-02d26659fd82cf299 and Apache configured via user-data. CloudWatch-driven policies at CPU >60% for scale-out and CPU <20% for scale-in demonstrate real-time load response.
The HashiCorp tutorial reinforces the pattern with a terramino ASG using minsize 1, maxsize 3, desiredcapacity 1, launchconfiguration referencing a launch configuration, and vpczoneidentifier sourced from a VPC module. It highlights that Terraform tracks capacity not individual instances, and that lifecycle arguments prevent unwanted scaling diffs.
The community autoscaling module extends these patterns with mixed instances policies, instance refresh with rolling preferences and checkpoint percentages, initial lifecycle hooks for launch and termination events, and options to respect or ignore desired_capacity to avoid Terraform diff conflicts.
Together these approaches provide a consistent, auditable, and automatable way to build scalable EC2 fleets that respond to load, support safe updates, and integrate with operational tooling without manual console changes.