AWS Auto Scaling with Terraform

Christopher Lawshe
5 min readMar 4, 2023

--

For this project, my goal was to create a deployment with Terraform with the following components:

  • An Auto Scaling Group that spans 2 subnets in my VPC
  • A security group that allows web traffic associated with my ASG instances
  • A script used to start an Apache web server on all my instances when created

After this was done, I verified that my ASG was operational by deleting an EC2 instance and waiting for a new one to be created.

Prerequisites to complete this project:

1.) A default VPC to house my new resources

2.) AWS Free-Tier account

3.) An IDE running Terraform to build and house the code(I used AWS Cloud9)

Let’s get started.

To build my infrastructure I created a new directory in my Cloud9 EC2 environment and performed:

terraform init

This command initializes Terraform in the system and allows me to use HCL to build out my infrastructure as code. The next step was to create 3 files to define my infrastructure:

  1. ‘main.tf’ — this houses the main body of my code that contains all my resources that will be deployed
  2. ‘variables.tf’ — this is used to define parameters for my resources outside of my main code. The main benefit of this file is making code more reusable and modular.
  3. ‘userdata.sh’ — this file will be used to give my EC2 instances instructions on what commands to run when they initialize for the first time.

Take a look below to see the code typed out for each file mentioned above.

‘main.tf’:

#Declare provider(s)
provider "aws" {
region = "us-east-1"
}

#Create new VPC
resource "aws_vpc" "Week21_VPC" {
cidr_block = "10.0.0.0/16"


tags = {
Name = "Week21_VPC"
}
}

# Get AWS Availability Zones
data "aws_availability_zones" "available" {
state = "available"
}

#Deploye 2 subnets to default VPC

resource "aws_subnet" "public_subnet" {
vpc_id = aws_vpc.Week21_VPC.id
cidr_block = var.pub_sub_cidr[count.index]
count = 2
map_public_ip_on_launch = true
availability_zone = data.aws_availability_zones.available.names[count.index]
}

#Create Internet Gateway
resource "aws_internet_gateway" "internet_gateway" {
vpc_id = aws_vpc.Week21_VPC.id

tags = {
Name = "Week21_gateway"
}
}

#Create public route table

resource "aws_route_table" "week21_public_RT" {
vpc_id = aws_vpc.Week21_VPC.id

route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.internet_gateway.id
}
}

#Create security groups to contorl access

resource "aws_security_group" "week21_security_group" {
name = "week21-security-group"
description = "Week21 Security Group"
vpc_id = aws_vpc.Week21_VPC.id

ingress {
description = "HTTPS from web"
from_port = 443
to_port = 443
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 = "week21_security_group"
}
}


#Launch EC2 Instance(s) with Apache install configuration

resource "aws_launch_configuration" "Week21_Config" {
name_prefix = "Week21-Project-"
image_id = "ami-006dcf34c09e50022"
instance_type = "t2.micro"
user_data = file("userdata.sh")
security_groups = [aws_security_group.week21_security_group.id]

}

resource "aws_autoscaling_group" "Week21_autoscaling" {

vpc_zone_identifier = [for i in aws_subnet.public_subnet[*] : i.id]
launch_configuration = aws_launch_configuration.Week21_Config.name
desired_capacity = 2
max_size = 5
min_size = 2
health_check_grace_period = 30
health_check_type = "EC2"

tag {
key = "Name"
value = "week21 ec2 instance"
propagate_at_launch = true
}

lifecycle {
create_before_destroy = true
}
}

‘variables.tf’

NOTE: (I only defined one resource in this project in ‘variables.tf’ to show a simple use case. However, each resource in ‘main.tf’ could have been easily defined there as well.)

variable "pub_sub_cidr" {
description = "public subnet cidr"
type = list(string)
default = ["10.0.4.0/24", "10.0.5.0/24"]
}

‘userdata.sh’

#Update instance depencencies and install Apache web server 

sudo yum update -y
sudo yum install -y httpd
sudo systemctl start httpd
sudo systemctl enable httpd

The only thing Terraform needs to coordinate these files for deployment is for them to all be in the same directory and have the correct names (as shown above). Once they were compiled I needed to run a few more Terraform commands:

terraform validate

This command tells Terraform to validate the configuration files in the directory.

terraform plan

This command tells Terraform to look over our configuration files and give a preview of the actions Terraform would take to create/modify my infrastructure. (It will also help expose some errors in the code.)

terraform apply --auto-approve

This command tells Terraform to create a plan just like the previous command, but then actually executes the plan to build out my infrastructure or make changes. (Auto-Approve allows me to skip Terraform asking for approval before executing ‘terraform apply’.

terraform state list

This command tells Terraform to display a list of the current infrastructure that was built out by Terraform. (Take a look at mine below)

This command showed that my code instructed Terraform to build:

  • 1 Auto Scaling group (comprised of 2 EC2 instances)
  • 1 Internet Gateway
  • 1 Routing Table
  • 1 Security Group
  • 2 Subnets
  • 1 VPC

Once Terraform successfully deployed my infrastructure I needed to check my EC2 instances were up and running in the AWS console:

Since they were both running and in the correct security group I know my code worked as planned. Now I needed to terminate one of them (completed in the console):

Once the terminated instance disappeared I waited for a few minutes for another one to spin back up to make sure my ASG is working as intended:

After a few minutes a new EC2 began initializing and proved my project to be a success.

--

--

Christopher Lawshe
Christopher Lawshe

Written by Christopher Lawshe

IT enthusiast — looking to learn from and connect with IT professionals to help push the world forward through Cloud DevOps

No responses yet