How to create an Auto Scaling Group using Terraform

Step by step guide to set up a basic Auto Scaling Group using Terraform

How to create an Auto Scaling Group using Terraform

Terraform is an infrastructure as code tool that lets you define both cloud and on-prem resources in human-readable configuration files that you can version, reuse, and share. It is a wildly popular tool to manage your Infrastructure as Code. This blog is a step-by-step guide to creating the most basic Auto Scaling group using terraform.

TLDR; You can find the code for this demo here.

Development environment setup

You will need to set up a few things in your development environment before we get started.

Terraform Setup

First off, you will need to install terraform in your development environment. You can follow the steps from the official terraform website. For the code in this blog to work, you will need to have terraform version 1.0+. Ensure the installation of Terraform is complete with the following command.

$ terraform -v
Terraform v1.1.8
on linux_amd64

AWS CLI Setup

You will need to be able to call AWS APIs from your CLI. You can follow this guide to set up your AWS CLI. Make sure you are following the best practices mentioned in this blog for your AWS account setup. You can run a quick sanity test by calling the following command

$ aws sts get-caller-identity

Terraform project

With that, we are ready for the actual implementation. Terraform projects have a fairly standard directory structure.

$ tree auto-scaling-group-demo/
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
├── versions.tf

The names are very self-explanatory. The first file you should populate is the versions.tf file. While it is optional, it can save a lot of headaches with versions conflicts and reconciling different .tfstate files in the future. Add this to your versions.tf file.

terraform {
  required_version = ">= 1.0"
  
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 4.7"
    }
  }
}

The majority of the code will be written in the main.tf file. We will start with the basic setup.

provider "aws" {
  region = local.region

  default_tags {
    tags = {
      Project = "auto-scaling-group-demo"
    }
  }
}

locals {
  name   = "auto-scaling-group-basic"
  region = "us-east-1"
  tags = {
    Environment = "demo"
    Blog = "auto-scaling-group-setup"
  }
}

The entries in the local block can be moved into the variables.tf file for more configurable. For this demo, I will simplify it by hardcoding them into the main.tf file.

Networking

It is extremely important to secure your AWS Infrastructure. And it all starts with networking. At the bare minimum, you should launch your instances in a private VPC. VPCs do not cost anything to set up and give full control over the networking of your environment  This demo assumes you do not have a private VPC setup. If you have one, you can just pass in the subnets in vpc_zone_identifier field of Auto Scaling group.

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"

  name = local.name
  cidr = "10.99.0.0/18"

  azs             = ["${local.region}a", "${local.region}b", "${local.region}c"]
  public_subnets  = ["10.99.0.0/24", "10.99.1.0/24", "10.99.2.0/24"]
  private_subnets = ["10.99.3.0/24", "10.99.4.0/24", "10.99.5.0/24"]

  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = local.tags
}

We are using a verified Terraform module for VPC. This VPC has 3 availability zones, and public and private subnets in each.

Next up, we configure the security group of your group using a Terraform module. Security groups control the flow of data within your VPC. Do note that we do not allow any traffic to come into the instance in this Security group. This means you will not be able to ssh into the instance.

module "asg_sg" {
  source  = "terraform-aws-modules/security-group/aws"
  version = "~> 4.0"

  name        = local.name
  description = "A security group"
  vpc_id      = module.vpc.vpc_id

  egress_rules = ["all-all"]

  tags = local.tags
}

I will write a full blog about networking in AWS to explain what these resources are, and how to securely configure your infrastructure.

Launch Template

Launch template determines the configuration of the instance that gets launched in your auto-scaling group. For this example, we only specify the AMI and instance type to use. We will use t3.micro instance type in order to utilize the free tier.

data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name = "name"

    values = [
      "amzn-ami-hvm-*-x86_64-gp2",
    ]
  }
}

resource "aws_launch_template" "this" {
  name_prefix   = "${local.name}-launch-template"
  image_id      = data.aws_ami.amazon_linux.id
  instance_type = "t3.micro"

  lifecycle {
    create_before_destroy = true
  }
}

Auto Scaling Group

This is where we create the actual Auto Scaling Group. We will once again use a published terraform module. The last thing we will need to add to terraform file is the user_data. This is the script that gets run when an instance starts. Add the user data to the  locals block we created earlier

  user_data = <<-EOT
  #!/bin/bash
  echo "Hello World!"
  EOT

Now let's add the group configuration

module "auto-scaling-group-demo" {
  source  = "terraform-aws-modules/autoscaling/aws"
  
  name = "external-${local.name}"

  vpc_zone_identifier = module.vpc.private_subnets
  security_groups     = [module.asg_sg.security_group_id]
  min_size            = 0
  max_size            = 1
  desired_capacity    = 1

  create_launch_template  = false
  launch_template         = aws_launch_template.this.name
  user_data               = base64encode(local.user_data)

  tags = local.tags
}

Applying the configuration

You need to know three main commands to apply this configuration and create the infrastructure in your AWS account.

  1. terraform init -> This command initializes the working directory containing Terraform configuration files. You will need to only run this once. This command handles version checks, plugin installations, etc. You can learn more about this here.
  2. terraform plan -> This command prints out a diff of resources in your AWS account against the current configuration. It is an action plan of changes that would happen should you choose to apply the configuration. You can learn more about this command here.
  3. terraform apply -> This command executes the changes listed in terraform plan. It prompts you for a confirmation, and go ahead and update the resources in your AWS environment. You can learn more about this command here.
  4. terraform destroy -> This command destroys all the resources created by a terraform configuration. You can learn more about this command here.

To see how the module you created works, go ahead and run the first three commands. Once Terraform finishes creating the resources, you can see the created instance in your account. You can either go to the console or run describe-auto-scaling-groups command using the CLI.

Lastly, run terraform destroy to clean up the resources we created for this demo.