Infrastructure as Code with Terraform [Part 5]

Hola Friends! Once you've mastered the basics like attributes and outputs, it's time to dive deeper into advanced concepts that make Terraform even more robust and flexible. In this blog, we'll explore Variables, State Files, Modules, Provisioners, and Data Sources with practical examples.

1. Variables in Terraform

Variables in Terraform allow you to parameterize configurations, making them reusable and manageable. Instead of hardcoding values, you can define variables and reuse them across multiple resources.

Defining a Variable

A variable is declared using the variable block. For example:


variable "instance_type" {
  default = "t2.micro"
  description = "The type of instance to be created."
}

Using Variables

You can reference variables in your resources using the var keyword:

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = var.instance_type
}

Passing Variable Values

You can pass values to variables in multiple ways:

1. Command Line: terraform apply -var='instance_type=t2.small'

2. Terraform.tfvars File:

instance_type = "t2.medium"
  1. Environment Variables: export TF_VAR_instance_type=t2.large

2. State Files

State files in Terraform track the state of your infrastructure. Terraform uses this file to determine what needs to be created, updated, or destroyed.

Importance of State Files

  • Keeps Track of Resources: Terraform uses the terraform.tfstate file to understand the current state of resources.

  • Facilitates Dependency Management: It helps Terraform identify resource dependencies.

Local vs Remote State

  • Local State: Stored on your local machine (default).

  • Remote State: Stored in a shared location like S3 or Terraform Cloud for collaboration.

Example: Remote State Configuration

terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "state/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-lock"
  }
}

This configuration stores the state file in an S3 bucket and locks it using DynamoDB to prevent simultaneous modifications.


3. Modules

Modules are reusable packages of Terraform configurations that simplify resource management by encapsulating related resources.

Creating a Module

For example, let’s create a module to launch an EC2 instance:

  1. Directory structure
my-module/
|-- main.tf
|-- variables.tf
|-- outputs.tf

main.tf

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

variables.tf

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

outputs.tf

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

Using a Module

You can use this module in your Terraform configuration:

module "ec2_instance" {
  source         = "./my-module"
  ami            = "ami-0c55b159cbfafe1f0"
  instance_type  = "t2.medium"
}

4. Provisioners

Provisioners execute scripts or commands on a resource after it is created or before it is destroyed. They are typically used for bootstrapping.

Types of Provisioners

  1. local-exec: Runs commands locally.

  2. remote-exec: Runs commands on the resource via SSH or WinRM.

Example: Using remote-exec

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  provisioner "remote-exec" {
    connection {
      type     = "ssh"
      user     = "ec2-user"
      private_key = file("~/.ssh/id_rsa")
      host     = self.public_ip
    }

    inline = [
      "sudo yum update -y",
      "sudo yum install -y httpd",
      "sudo systemctl start httpd"
    ]
  }
}

5. Data Sources

Data sources allow you to fetch external data dynamically, such as the latest AMI ID or existing resources.

Example: Fetching the Latest AMI

data "aws_ami" "latest" {
  most_recent = true
  owners      = ["amazon"]
  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }
}

resource "aws_instance" "example" {
  ami           = data.aws_ami.latest.id
  instance_type = "t2.micro"
}

In this example, the data.aws_ami.latest data source fetches the most recent Amazon Linux 2 AMI.

Fantástica! Terraform's advanced features like variables, state files, modules, provisioners, and data sources empower you to build scalable, reusable, and maintainable infrastructure configurations. By mastering these concepts, you can unlock the full potential of Terraform and streamline your infrastructure as code workflows.

What topics would you like to explore next in Terraform? Let me know in the comments!


A book to read:

"You have power over your mind – not outside events. Realize this, and you will find strength."
~ Marcus Aurelius


Aaqib Ahmad
Senior DevOps Engineer [SRE]