Deploy AWS Autoscaling with Launch Templates using Terraform

Rasanpreet
AWS Tip
Published in
5 min readMay 5, 2024

--

Overview

We will set up an AWS Auto Scaling Group (ASG) during this walkthrough. Also, we will create a Launch Configuration (Launch Template) for EC2 instances with a Security Group depending on your application access needs. Plus, an extra EBS volume and instance profile will be connected to the instances. The complete provisioning solution would be through Terraform.

Amazon Auto Scaling Group (ASG) modifies the number of EC2 instances based on demand at the time. Because of its elasticity, the application can adjust to variations in traffic patterns. When demand is particularly high, ASG allocates more resources to meet the demand. It eliminates extra resources during periods of low demand, which lowers expenses.

A launch template specifies instance configuration information. It contains information used to launch EC2 instances, such as the instance type, security groups, key pair, and Amazon Machine Image (AMI) ID.

Terraform is an infrastructure as code (Iac) tool that automates infrastructure provisioning. It is the most widely used and supports multiple clouds.

Prerequisites

To follow along with the hands-on section of this blog post, you will need the following:

We need to have a single AWS VPC with two subnets for each of the availability zones in the area.
To run the Terraform scripts, we also need a basic understanding of the AWS provider and a local Terraform setup.

Creating the Auto Scaling Group

Let’s start by creating Terraform resources for the EC2 IAM role with the necessary IAM policies, it will be used to make API calls to AWS services.

terraform/role.tf

//This template will also create one SSM IAM role and attach it to EC2 instance 

//Create SSM role
resource "aws_iam_role" "ssm_role" {
name = "EC2-role"
assume_role_policy = <<-EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}

//Attach SSM policy to SSM role
resource "aws_iam_role_policy_attachment" "ssm_policy" {
role = aws_iam_role.ssm_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}



//Attach S3 policy to SSM role
resource "aws_iam_role_policy_attachment" "s3_policy" {
role = aws_iam_role.ssm_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
}



//create instance profile for SSM role
resource "aws_iam_instance_profile" "ssm_profile" {
name = "EC2-profile"
role = aws_iam_role.ssm_role.name
depends_on = [aws_iam_role_policy_attachment.ssm_policy]
}

Next, we’ll create an EC2 Launch Template and use it to create Auto Scaling Group instances of EC2.

terraform/autoscaling.tf

//This template will create EC2 behind the autoscaling group & lauch template with security group and additional volume attached to instance

//Create security group
resource "aws_security_group" "sgw" {
name = var.security_name
description = "Allow web inbound traffic"
vpc_id = var.vpc_id

ingress {
description = "HTTPS allow"
from_port = var.web_port
to_port = var.web_port
protocol = "tcp"
cidr_blocks = [var.vpc_cidr_block]
}
ingress {
description = "SSH allow"
from_port = var.ssh_port
to_port = var.ssh_port
protocol = "tcp"
cidr_blocks = [var.vpc_cidr_block]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

}

// Create launch template
resource "aws_launch_template" "launch" {
name = var.launch_template_name
default_version = var.launch_template_version
image_id = var.instance_ami_id
instance_type = var.instance_type
key_name = var.key_pair_name
vpc_security_group_ids = [aws_security_group.sgw.id]
user_data = filebase64("${path.module}/ssm.sh")
iam_instance_profile {
name = var.iam_instance_profile_name
}
block_device_mappings {
device_name = "/dev/xvdb"
ebs {
volume_size = var.ebs_volume_size
}
}
}

//Create autoscaling group
resource "aws_autoscaling_group" "autoscaling" {
name = var.autoscaling_group_name
vpc_zone_identifier = [var.subnet_private1_id, var.subnet_private2_id]
launch_template {
id = aws_launch_template.launch.id
version = "$Latest"
}
min_size = var.autoscaling_min_size
max_size = var.autoscaling_max_size
desired_capacity = var.autoscaling_desired_capacity
health_check_type = var.autoscaling_health_check_type
force_delete = true
}

In addition, the following User data Shell script will be used to mount the extra EBS volume and load the EC2 with the SSM agent.

terraform/ssm.sh

#!/bin/bash
sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
sudo systemctl enable amazon-ssm-agent
sudo systemctl start amazon-ssm-agent
sudo mkfs -t xfs /dev/xvdb
sudo mkdir /data
sudo mount /dev/xvdb /data/

To use Terraform, we must declare AWS as the Terraform provider. As per our needs, we need to update the AWS region and profile name.

terraform/provider.tf

provider "aws" {
profile = "aws-profile"
region = "us-east-1"
}
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}

Next, we need to declare terraform variables with default values. We can update the default values as per our requirements. First, create the VPC and security group variables with default values.

terraform/variable.tf

//variables specific to vpc_id,vpc_cidr,Subnet ID's
variable "vpc_id"{
type = string
description = "VPC ID"
default = "vpc-06af576fe03d896da"
}
variable "vpc_cidr_block"{
type = string
description = "The VPC CIDR block used in Instance Security group ingress rules"
default = "10.144.10.0/24"
}
variable "subnet_private1_id"{
type = string
description = "VPC private subnet-1 ID"
default = "subnet-05e7401f4f0ba15x7"
}
variable "subnet_private2_id"{
type = string
description = "VPC private subnet-2 ID"
default = "subnet-09976149cfef6f1ed"
}
//variables specific to EC2 Security group

variable "security_name" {
default = "instance-sg"
}
variable "ssh_port" {
default = "22"
}
variable "web_port" {
default = "443"
}

Next in the same variable.tf we will add the following EC2 launch template and auto scaling group variables and use default values. As per the project requirement, we need to update these default values

//variables specific to SSH private key
variable "key_pair_name"{
type = string
description = "Key pair name available in your region"
default = "ssh-key"
}

//variables specific to Instance Information
variable "instance_ami_id"{
type = string
description = "Instance AMI ID"
default = "ami-01e36b7901e884a10"
}
variable "instance_type"{
type = string
description = "Instance type"
default = "t2.micro"
}
variable "ebs_volume_size" {
description = "The additional EBS volume size after root device"
default = "40"
}

//variables specific to launch template
variable "launch_template_name" {
description = "The name of the launch template"
default = "demo-template"
}
variable "launch_template_version" {
description = "The version of the launch template"
default = "1"
}
//variables specific to autoscaling group
variable "autoscaling_group_name" {
description = "The name of the auto scaling group"
default = "demo-asg"
}
variable "autoscaling_min_size" {
description = "The minimum size of the auto scale group"
default = "1"
}
variable "autoscaling_max_size" {
description = "The maximum size of the auto scale group"
default = "2"
}
variable "autoscaling_desired_capacity" {
description = "The number of EC2 instances that should be running in the group"
default = "2"
}
variable "autoscaling_health_check_type" {
description = "EC2 or ELB, how health checking is done."
default = "EC2"
}

Execute Terraform Commands

Open a Command Prompt window in the same directory where we have all Terraform files and run the following Terraform commands.

# Terraform Initialize
terraform init

# Terrafom Validate
terraform validate

# Terraform Plan
terraform plan

# Terraform Apply
terraform apply -auto-approve

--

--

AWS Ambassador & Community Builder. He enjoys creating Cloud infra with IaC & building CI/CD pipelines. https://www.linkedin.com/in/rasanpreet/