Skip to main content

Command Palette

Search for a command to run...

Understanding Terraform: Your Go-To Infrastructure as Code Solution

Published
6 min read
Understanding Terraform: Your Go-To Infrastructure as Code Solution

Terraform is a powerful tool for managing and provisioning infrastructure using code. This blog will delve into what Terraform is, its advantages, architecture, and key concepts like HCL, commands, and files. We'll also provide an HCL code example for creating AWS infrastructure and explain key items such as providers, variables, locals, modules, and loops.

What is Terraform?

Terraform is an open-source Infrastructure as Code (IaC) tool developed by HashiCorp. It enables users to define, provision, and manage infrastructure resources across various cloud providers and on-premises environments using a declarative configuration language.

Advantages of Terraform

  1. Platform Agnostic: Supports multiple cloud providers (AWS, Azure, GCP) and on-premises infrastructure.

  2. Declarative Language: Allows users to describe the desired state of infrastructure.

  3. Version Control: Infrastructure configurations can be stored in version control systems, enabling versioning and collaboration.

  4. Scalability: Easily manages infrastructure at any scale, from small setups to large, complex environments.

  5. Automation: Automates the provisioning and management of infrastructure, reducing manual intervention and errors.

Architecture of Terraform

Terraform's architecture consists of several key components:

  1. Configuration Files: Written in HashiCorp Configuration Language (HCL), defining the desired state of infrastructure.

  2. Terraform Core: Reads configuration files and interacts with providers to create and manage resources.

  3. Providers: Plugins that interact with various infrastructure platforms (AWS, Azure, GCP) to manage resources.

  4. State Management: Maintains the state of the managed infrastructure, ensuring the current state matches the desired state.

What is HCL?

HashiCorp Configuration Language (HCL) is the language used to write Terraform configuration files. HCL is designed to be both human-readable and machine-friendly, making it easy to write and understand infrastructure definitions.

Creating Infrastructure on AWS

To create infrastructure on AWS using Terraform, you need to write HCL code defining the resources you want. This code is then executed by Terraform to provision and manage the infrastructure.

Terraform Commands

Terraform provides several commands for managing infrastructure:

  1. init: Initializes a Terraform working directory by downloading the necessary provider plugins.

  2. plan: Creates an execution plan, showing what actions Terraform will take to achieve the desired state.

  3. apply: Applies the changes required to reach the desired state of the configuration.

  4. destroy: Destroys the managed infrastructure, removing all resources defined in the configuration.

  5. refresh: Updates the state file to match the real-world infrastructure.

  6. import: Imports existing infrastructure into Terraform, allowing it to manage these resources.

Terraform Files

Terraform configurations are organized into several files:

  1. main.tf: Contains the primary configuration for resources and providers.

  2. variables.tf: Defines input variables used to parameterize the configuration.

  3. terraform.tfvars: Provides values for the variables defined in variables.tf.

  4. terraform.tfstate: Stores the state of the managed infrastructure.

  5. terraform.tfstate.backup: A backup of the previous state file.

  6. .terraform.lock.hcl: Locks the versions of provider plugins to ensure consistent deployments.

HCL Code Example: Creating AWS Infrastructure

Here's an example of HCL code to create an AWS EC2 instance:

provider "aws" {
  region = "us-west-2"
}

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

variable "ami_id" {
  default = "ami-0c55b159cbfafe1f0"
}

resource "aws_instance" "example" {
  ami           = var.ami_id
  instance_type = var.instance_type
}

output "instance_id" {
  value = aws_instance.example.id
}

Key Items in HCL Code

  1. Provider: Specifies the infrastructure provider (AWS) and its configuration.

     provider "aws" {
       region = "us-west-2"
     }
    
  2. Variables: Define inputs that can be used to parameterize the configuration.

     variable "instance_type" {
       default = "t2.micro"
     }
    
  3. Resource: Defines a resource to be managed by Terraform (an AWS EC2 instance).

     resource "aws_instance" "example" {
       ami           = var.ami_id
       instance_type = var.instance_type
     }
    
  4. Output: Specifies values to be output after the configuration is applied.

     output "instance_id" {
       value = aws_instance.example.id
     }
    
  5. Locals: Define local values that can be reused in the configuration.

     locals {
       instance_count = 3
     }
    
  6. Modules: Encapsulate reusable configuration blocks, making it easy to organize and reuse code.

     module "network" {
       source = "./modules/network"
     }
    
  7. Loops: Use count, for, and for_each to create multiple instances of a resource or iterate over collections.

     resource "aws_instance" "example" {
       count = 3
       ami           = var.ami_id
       instance_type = var.instance_type
     }
    

Using for

The for expression in Terraform is typically used within a locals block to generate a collection based on another collection. This is often useful for generating lists or maps that can be used elsewhere in the configuration.

Example: Creating a List of Subnet IDs

Let's say you want to create a list of subnet IDs from a list of subnet CIDRs.

variable "subnet_cidrs" {
  type    = list(string)
  default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
}

locals {
  subnet_ids = [for cidr in var.subnet_cidrs : cidr]
}

resource "aws_subnet" "example" {
  count = length(var.subnet_cidrs)

  vpc_id     = aws_vpc.example.id
  cidr_block = var.subnet_cidrs[count.index]

  tags = {
    Name = "example-subnet-${count.index}"
  }
}

output "subnet_ids" {
  value = [for subnet in aws_subnet.example : subnet.id]
}

In this example:

  • The for expression in the locals block generates a list of subnet IDs from the provided list of subnet CIDRs.

  • The for expression in the output block iterates over the aws_subnet.example resources and collects their IDs.

Using for_each

The for_each meta-argument in Terraform allows you to iterate over a collection (like a list or map) and create multiple instances of a resource based on that collection. Each instance is identified by a unique key from the collection.

Example: Creating Multiple EC2 Instances

Let's create multiple EC2 instances, each with a different name and type.

variable "instances" {
  type = map(object({
    instance_type = string
    ami           = string
  }))
  default = {
    "web" = {
      instance_type = "t2.micro"
      ami           = "ami-0c55b159cbfafe1f0"
    },
    "db" = {
      instance_type = "t2.medium"
      ami           = "ami-0c55b159cbfafe1f0"
    }
  }
}

resource "aws_instance" "example" {
  for_each = var.instances

  instance_type = each.value.instance_type
  ami           = each.value.ami

  tags = {
    Name = each.key
  }
}

output "instance_ids" {
  value = { for key, instance in aws_instance.example : key => instance.id }
}

In this example:

  • The for_each argument in the aws_instance.example resource iterates over the var.instances map.

  • Each instance is created with properties specified in the map.

  • The output block collects the IDs of the created instances, mapping them to their corresponding keys.

Using slice

The slice function in Terraform is used to extract a portion of a list. It takes three arguments: the list to slice, the starting index (inclusive), and the ending index (exclusive). Let's go through an example to illustrate how to use the slice function in Terraform.

Example

Here is the complete Terraform configuration using the slice function:

provider "aws" {
  region = "us-west-2"
}

variable "subnet_cidrs" {
  type    = list(string)
  default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24", "10.0.4.0/24"]
}

locals {
  dev_subnet_cidrs = slice(var.subnet_cidrs, 0, 2)
}

resource "aws_vpc" "example" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "dev" {
  count = length(local.dev_subnet_cidrs)

  vpc_id     = aws_vpc.example.id
  cidr_block = local.dev_subnet_cidrs[count.index]

  tags = {
    Name = "dev-subnet-${count.index + 1}"
  }
}

output "dev_subnet_ids" {
  value = [for subnet in aws_subnet.dev : subnet.id]
}

Conclusion

Terraform is a robust and versatile tool for managing infrastructure as code. Its declarative language, platform-agnostic nature, and powerful automation capabilities make it an essential tool for modern infrastructure management. By understanding its architecture, commands, and file structure, you can effectively leverage Terraform to manage your infrastructure on AWS and beyond. As the infrastructure landscape continues to evolve, Terraform will remain a crucial tool for achieving scalable, efficient, and reliable infrastructure management.

Terraform

Part 1 of 1