Getting Started with Terraform

Last updated: April 13, 2025

1. Introduction: What is Terraform?

Terraform, developed by HashiCorp, is a leading open-source Infrastructure as Code (IaC) tool. It allows you to define, provision, and manage infrastructure resources (like virtual machines, networks, databases, DNS entries) across various cloud providers (AWS, Azure, GCP) and other services using a declarative configuration language.

Instead of manually clicking through web consoles or writing complex scripts, you describe your desired infrastructure in configuration files. Terraform then figures out how to create, update, or delete resources to match your definition, making infrastructure management more predictable, repeatable, and versionable.

This guide provides a hands-on introduction to get you started with Terraform basics.

2. Installation

Terraform is distributed as a single binary. Download the appropriate package for your operating system from the official Terraform downloads page.

  1. Download the ZIP archive.
  2. Unzip the package. You'll find a single binary file named terraform (or terraform.exe on Windows).
  3. Move the binary to a directory included in your system's PATH environment variable (e.g., /usr/local/bin on Linux/macOS, or a dedicated folder added to PATH on Windows).

Verify the installation by opening a new terminal session and running:

terraform --version

Alternatively, use package managers like Homebrew (macOS) or Chocolatey (Windows):

# macOS (Homebrew)
brew tap hashicorp/tap
brew install hashicorp/tap/terraform

# Windows (Chocolatey)
choco install terraform

3. Core Terraform Concepts

3.1 HCL (HashiCorp Configuration Language)

Terraform configurations are written in HCL, a declarative language designed to be human-readable and machine-friendly. Files typically have a .tf extension.

3.2 Providers

Providers are plugins that allow Terraform to interact with specific APIs (e.g., AWS, Azure, GCP, Docker, GitHub). You declare which providers your configuration needs, and Terraform downloads them automatically during initialization.

3.3 Resources

Resources are the fundamental building blocks of your infrastructure (e.g., an AWS EC2 instance, a GCP VPC network, an Azure storage account). You define resources in your configuration files, specifying their type and desired attributes.

3.4 State

Terraform maintains a state file (usually terraform.tfstate) to keep track of the real-world resources it manages, their configuration, and their dependencies. This state file is crucial for Terraform to understand what infrastructure currently exists and how to plan updates.

Important: For team collaboration, the state file should be stored remotely and securely (e.g., in an AWS S3 bucket, Azure Blob Storage, or Terraform Cloud/Enterprise) with locking enabled to prevent conflicts.

3.5 Core Workflow (init, plan, apply)

The basic Terraform workflow involves three main commands:

  1. terraform init: Initializes the working directory, downloads provider plugins, and sets up the backend for state storage. Run this once per project initially and whenever providers change.
  2. terraform plan: Creates an execution plan. Terraform compares your configuration files with the current state file and the actual infrastructure to determine what changes (create, update, delete) are needed. It shows you this plan for review before making any changes.
  3. terraform apply: Executes the actions proposed in the plan to reach the desired state described in your configuration.

4. Your First Terraform Project (AWS Example)

Let's create a simple AWS EC2 instance.

Prerequisites:

  • Terraform installed.
  • An AWS account.
  • AWS credentials configured for Terraform to use (e.g., via environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or an IAM role if running on EC2). See AWS Provider Authentication for details.

4.1 Project Setup

Create a new directory for your project:

mkdir terraform-learn
cd terraform-learn

4.2 Configure the Provider

Create a file named main.tf (or any name ending in .tf) and configure the AWS provider:

# main.tf

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0" # Specify desired provider version
    }
  }
}

# Configure the AWS Provider
provider "aws" {
  region = "us-west-2" # Choose your desired AWS region
}

4.3 Define a Resource

In the same main.tf file, define an AWS EC2 instance resource:

# Define an AWS EC2 instance resource
resource "aws_instance" "example_server" {
  # ami           = "ami-08d70e59c07c61a3a" # Example: Ubuntu 22.04 LTS for us-west-2 (Find current AMI for your region)
  ami           = data.aws_ami.ubuntu.id # Use data source below for dynamic AMI lookup
  instance_type = "t2.micro"          # Instance size

  tags = {
    Name = "HelloWorldServer"
  }
}

# Data source to find the latest Ubuntu 22.04 AMI in the selected region
data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical's AWS account ID for Ubuntu images
}
  • resource "aws_instance" "example_server": Declares a resource of type aws_instance with the local name example_server.
  • ami: Specifies the Amazon Machine Image ID (operating system). Using a data source like data.aws_ami.ubuntu.id is recommended to find the latest AMI dynamically.
  • instance_type: Specifies the size of the EC2 instance.
  • tags: Assigns metadata tags to the resource.
  • data "aws_ami" "ubuntu" { ... }: A data source block that looks up information (in this case, an AMI ID) from AWS without creating a resource.

Note: Always check the AWS documentation or console for the latest appropriate AMI ID for your desired OS and region, or use a data source as shown.

4.4 Initialize the Project (terraform init)

Run this command in your project directory:

terraform init

Terraform downloads the AWS provider plugin specified in your configuration.

4.5 Plan the Changes (terraform plan)

See what Terraform intends to do:

terraform plan

Terraform will analyze your configuration and show output indicating it plans to create one resource (the aws_instance). Review the plan carefully.

4.6 Apply the Changes (terraform apply)

Execute the plan to create the EC2 instance:

terraform apply

Terraform will show the plan again and ask for confirmation. Type yes and press Enter.

Terraform will now interact with the AWS API to create the instance. This might take a minute or two.

4.7 Inspect State (terraform show)

After applying, you can see the resources Terraform is managing:

terraform show

This displays information about the created instance from the state file.

4.8 Destroy Resources (terraform destroy)

When you're finished with the resources, you can destroy them:

terraform destroy

Terraform will show a plan of resources to be destroyed and ask for confirmation. Type yes to proceed.

5. Using Variables and Outputs

5.1 Input Variables

Avoid hardcoding values like regions or instance types. Use input variables.

Create a file variables.tf:

# variables.tf
variable "aws_region" {
  description = "The AWS region to deploy resources in."
  type        = string
  default     = "us-west-2"
}

variable "instance_type" {
  description = "EC2 instance type."
  type        = string
  default     = "t2.micro"
}

Modify main.tf to use these variables:

# main.tf (modified)
provider "aws" {
  region = var.aws_region # Use variable
}

resource "aws_instance" "example_server" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = var.instance_type # Use variable

  tags = {
    Name = "HelloWorldServer"
  }
}
# ... (data source remains the same) ...

You can override default variable values using a terraform.tfvars file or via the command line (-var="aws_region=eu-central-1").

5.2 Output Values

Define output values to display useful information after applying changes, like an instance's IP address.

Create a file outputs.tf:

# outputs.tf
output "instance_public_ip" {
  description = "Public IP address of the EC2 instance."
  value       = aws_instance.example_server.public_ip
}

output "instance_id" {
  description = "ID of the EC2 instance."
  value       = aws_instance.example_server.id
}

After running terraform apply, these values will be displayed.

6. Next Steps

This guide covers the absolute basics. Explore further:

  • More Resource Types: Define networks (VPC), security groups, databases (RDS), load balancers, etc.
  • Modules: Organize and reuse Terraform code.
  • Remote State: Store state files securely for team collaboration.
  • Provisioners: Execute scripts on resources after creation (use sparingly; prefer configuration management tools or immutable images).
  • Data Sources: Query existing infrastructure or external data.
  • Functions and Expressions: Use built-in functions for dynamic configurations.

7. Conclusion

Terraform provides a powerful, declarative way to manage infrastructure as code. By defining resources in HCL, using providers to interact with APIs, and following the init, plan, apply workflow, you can automate infrastructure provisioning, improve consistency, and enable version control for your infrastructure. This basic introduction should give you the foundation to start exploring Terraform for managing your own cloud resources.

External Resources