DEV Community

Udoh Deborah
Udoh Deborah

Posted on

Day 68 — Scaling with Terraform

Important: replace every with your actual values (region, AMI, key pair name, VPC/subnet IDs). The AMI in your example may be region-specific — verify it for your region.

Project layout

day68-autoscaling/
  ├─ main.tf
  ├─ variables.tf
  ├─ outputs.tf
  └─ terraform.tfvars   (optional)
Enter fullscreen mode Exit fullscreen mode
variables.tf

variable "region" {
  type    = string
  default = "us-east-1"
}

variable "ami" {
  type    = string
  default = "ami-005f9685cb30f234b" # replace if not available in your region
}

variable "instance_type" {
  type    = string
  default = "t2.micro"
}

variable "key_name" {
  type    = string
  default = "<YOUR_KEY_PAIR_NAME>"
}

variable "vpc_id" {
  type = string
  default = "<YOUR_VPC_ID>"
}

variable "public_subnet_ids" {
  type = list(string)
  default = ["<PUBLIC_SUBNET_ID_1>", "<PUBLIC_SUBNET_ID_2>"]
}
Enter fullscreen mode Exit fullscreen mode

main.tf

This creates a security group (SSH & HTTP), a classic ELB (optional but included because your example referenced a load balancer), a launch configuration, and an autoscaling group.

terraform {

  required_providers {
    aws = { source = "hashicorp/aws" version = "~> 5.0" }
  }
}

provider "aws" {
  region = var.region
}

# --- Security group for web instances ---
resource "aws_security_group" "web_server" {
  name        = "day68-web-sg"
  description = "Allow SSH and HTTP"
  vpc_id      = var.vpc_id

  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]    # For demo only. Restrict in production.
  }

  ingress {
    description = "HTTP"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = { Name = "day68-web-sg" }
}

# --- Optional Classic ELB to attach to ASG (example) ---
resource "aws_elb" "web_server_lb" {
  name               = "day68-web-elb"
  subnets            = var.public_subnet_ids
  security_groups    = [aws_security_group.web_server.id]

  listener {
    instance_port     = 80
    instance_protocol = "http"
    lb_port           = 80
    lb_protocol       = "http"
  }

  health_check {
    healthy_threshold   = 2
    unhealthy_threshold = 2
    timeout             = 3
    target              = "HTTP:80/"
    interval            = 30
  }

  tags = { Name = "day68-web-elb" }
}

# --- Launch configuration (legacy) ---
resource "aws_launch_configuration" "web_server_lc" {
  name_prefix   = "day68-lc-"
  image_id      = var.ami
  instance_type = var.instance_type
  key_name      = var.key_name
  security_groups = [aws_security_group.web_server.id]

  user_data = <<-EOF
              #!/bin/bash
              # simple web page bootstrap
              if command -v yum >/dev/null 2>&1; then
                yum update -y
                yum install -y httpd
                systemctl enable httpd
                systemctl start httpd
                echo "<html><body><h1>You're doing really Great</h1></body></html>" > /var/www/html/index.html
              elif command -v apt-get >/dev/null 2>&1; then
                apt-get update -y
                apt-get install -y apache2
                systemctl enable apache2
                systemctl start apache2
                echo "<html><body><h1>You're doing really Great</h1></body></html>" > /var/www/html/index.html
              fi
              EOF

  lifecycle {
    create_before_destroy = true
  }
}

# --- Auto Scaling Group ---
resource "aws_autoscaling_group" "web_server_asg" {
  name                      = "web-server-asg"
  launch_configuration      = aws_launch_configuration.web_server_lc.name
  min_size                  = 1
  max_size                  = 3
  desired_capacity          = 2
  vpc_zone_identifier       = var.public_subnet_ids
  health_check_type         = "EC2"
  health_check_grace_period = 120

  # attach ELB (classic) created above
  load_balancers = [aws_elb.web_server_lb.name]

  tag {
    key                 = "Name"
    value               = "day68-web"
    propagate_at_launch = true
  }
}

Enter fullscreen mode Exit fullscreen mode
outputs.tf

output "asg_name" {
  value = aws_autoscaling_group.web_server_asg.name
}

output "elb_dns_name" {
  value = aws_elb.web_server_lb.dns_name
}
Enter fullscreen mode Exit fullscreen mode

Run it (commands)
A. Initialize:

cd day68-autoscaling
terraform init
Enter fullscreen mode Exit fullscreen mode

B. Validate & plan:

terraform validate
terraform plan -out plan.tfplan
Enter fullscreen mode Exit fullscreen mode

C. Apply:

terraform apply "plan.tfplan"
# or: terraform apply -auto-approve
Enter fullscreen mode Exit fullscreen mode

Terraform will create the ELB, Launch Configuration, and ASG which launches instances in the two public subnets.

Test scaling (console + CLI)

Console

  1. Go to EC2, Auto Scaling Groups, select web-server-asg.
  2. Click Edit ,change Desired capacity to 3 ,Save.
  3. Wait a few minutes for instances to launch.
  4. Verify in EC2 , Instances.
  5. Change desired capacity back to 1 to scale down and confirm termination.

AWS CLI (optional)

# scale up
aws autoscaling set-desired-capacity --auto-scaling-group-name web-server-asg --desired-capacity 3 --honor-cooldown


# scale down
aws autoscaling set-desired-capacity --auto-scaling-group-name web-server-asg --desired-capacity 1 --honor-cooldown
Enter fullscreen mode Exit fullscreen mode

Verify web page
• If you used ELB, open the ELB DNS:

http://$(terraform output -raw elb_dns_name)
Enter fullscreen mode Exit fullscreen mode

You should see You’re doing really Great.

• Or open the public IP of any instance.

Cleanup

To remove resources and stop charges:

terraform destroy -auto-approve
Enter fullscreen mode Exit fullscreen mode

Troubleshooting tips
• ASG not launching instances: check subnet IDs, IAM permissions, and AMI availability in region.
• User data script failed: inspect instance system logs in EC2 console or SSH and check /var/log/cloud-init-output.log.
• Health check failures: increase health_check_grace_period to allow setup time.
• SSH exposed to 0.0.0.0/0: change ingress to your IP only for security.

Notes & best practice recommendations
• aws_launch_configuration is legacy. Prefer aws_launch_template for new projects — launch templates are more flexible (and needed for many modern features). I can provide a launch_template + ASG + ALB example if you want.
• For HTTP scaling, prefer an ALB (Application Load Balancer) + Target Group instead of Classic ELB. ALB integrates with target tracking and metrics better.
• In production, restrict SSH to your IP or use SSM Session Manager instead of opening port 22.
• For autoscaling based on metrics, add scaling policies (target tracking or step policies) to auto-adjust based on CPU, request counts, etc.

Top comments (0)