Skip to main content

Terraform

Terraform

Core

Init, Plan, Apply
  • terraform init
    • Set up providers & backend in that directory
terraform init
  • terraform plan
    • Preview changes
terraform plan
  • terraform apply
    • Make changes (add -auto-approve to skip prompt)
terraform apply
Core Concept
1. Providers
  • Providers is a Terraform Plugin to interact with API
  • Best practice: Providers must be located in a separate file ex:terrafrom.tf
  • Example of providers which Terraform Support
# terraform.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5. 0"
}
}
}

provider "aws" {
region = "us-east-1"
}

  • Local provider is used for creating and managing resources on your local machine (no API interaction)
# terraform.tf
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "2.5.3"
}
}
}
2. Resources + Meta-Arguments
  • Actual components that will be define
  • Best practice: Resources must be located in main.tf
  • Syntax:
resource "type" "resource_name" {}
# main.tf (local provider)
resource "local_file" "local" {
# requirement
filename = "<relative path>/filename.txt"

# or use a relative path command with ${}
# filename = "${path.module}/filename.txt"

#optional
content = "This is a local file created by Terraform"
}

  • Meta-Arguments:
    • Special arguments that can be used with every resource
    • They work with every resource type to control how Terraform creates or manages them.
depends_on
  • Forces an explicit dependency between resources.
  • Useful when Terraform can’t automatically detect the dependency.
  • Example:
resource "aws_s3_bucket" "example" {
bucket = "my-bucket"
}

resource "aws_s3_bucket_policy" "example_policy" {
bucket = aws_s3_bucket.example.id
policy = data.aws_iam_policy_document.example.json

depends_on = [aws_s3_bucket.example] # ensures bucket is created first
}
count
  • Creates multiple instances of the same resource.
  • You can access each instance with an index ([0], [1], etc.).
  • Example:
resource "aws_instance" "servers" {
count = 3
ami = "ami-123456"
instance_type = "t2.micro"
}
  • → Creates 3 EC2 instances.
for_each
  • Similar to count, but instead of an index, it uses a map or set of strings.
  • Gives more control over naming and referencing.
  • Example:
resource "aws_s3_bucket" "buckets" {
for_each = toset(["dev", "staging", "prod"])
bucket = "myapp-${each.key}"
}
  • → Creates 3 uniquely named buckets.
provider
  • Lets you specify which provider configuration a resource should use, especially when multiple providers of the same type exist.
  • Example:
provider "aws" {
region = "us-east-1"
alias = "east"
}

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

resource "aws_instance" "west_server" {
provider = aws.west
ami = "ami-654321"
instance_type = "t2.micro"
}
lifecycle
  • Controls special behaviors for resources during apply/destroy.
  • Common options:
    • create_before_destroy = true → ensures a new resource is made before deleting the old one.
    • prevent_destroy = true → protects critical resources from being destroyed.
    • ignore_changes = [field] → tells Terraform to ignore changes to certain fields.
  • Example:
3. State management
Definitions
  1. What It Is

    • The state file is like Terraform’s “notebook.”
    • It records all resources that Terraform has created, modified, or deleted.
    • It acts as Terraform’s database for keeping track of infrastructure.
  2. Current vs Desired State

    • Desired State = what you define in your .tf configuration files.
    • Current State = what Terraform knows already exists (stored in the state file).
    • Terraform compares the two and makes changes to bring the current state in line with the desired state.
  3. How It Works in Practice

    • At first, the state file is empty because nothing exists.
    • When you run terraform apply, Terraform:
      1. Creates the infrastructure.
      2. Updates the state file with details of the created resources (like IDs, attributes, etc.).
    • If you later change or delete resources in your config, Terraform compares with the state file and applies only the necessary updates.
  4. State File Format

    • Stored as JSON in terraform.tfstate.
    • Contains metadata (Terraform version, provider info).
    • Stores details of each resource: type, name, attributes, IDs, and configuration.
  5. Why It’s Important

    • Terraform relies on it to know what’s already been provisioned.
    • Without it, Terraform would not know whether resources already exist and might recreate or duplicate them.
    • It enables Terraform’s declarative approach: always moving the current state toward the desired state.
State Sub Command
  • Usage: terraform state <subcommand> [options] [args]
    • List all sub commands: terraform state -h
  • terraform state list, List resources in the state
  • terraform state mv, Move an item in the state
  • terraform state pull, Pull current state and output to stdout
  • terraform state push, Update remote state from a local state file
  • terraform state replace-provider, Replace provider in the state
  • terraform state rm, Remove instances from the state
  • terraform state show, Show a resource in the state
    • terraform state show <specific resources>, gives information of that resource only
IMPORTANT: State Drift
  • State Drift: Actual InfrastructureTerraform tfstate\color{tomato}\text{Actual Infrastructure} \neq \text{Terraform tfstate}
  • Occur when someone delete resources manually from the Provider's UI
  • Solution:
    1. terraform init and then terraform apply (Recommend)
      • Init helps to compare the actual infra and current state file
      • apply create the missing/difference between the two, hence create missing resource(s) + config the state file
    2. terraform refresh (Not Recommend)
      • If the deletion is intentional
      • terraform refresh will not change anything in the infra, but it will changes the current state file
      • However, this command doesn't consider the resource file
Variables and Outputs
Modules