Terraform Basics to Advanced in One Guide_v1.2
Terraform Basics to Advanced in One Guide_v1.2
TO ADVANCED
IN ONE GUIDE
https://www.techopsexamples.com/
Table of Contents
Introduction 4
Target Audience 4
Resources 4
Terraform Fundamentals 5
Introduction
This guide is designed to provide the essentials needed to
master Terraform, creating a strong foundation for
effective infrastructure management. Whether you’re just
starting out or aiming to advance your skills, this guide
offers a clear and structured path to set you up for long-
term success
Target Audience
This guide is for:
Beginners who want to understand the needed
fundamentals before getting into advanced IaC.
Resources
To discover real-world use cases, tech updates, and
learning resources, check out:
1. Terraform Fundamentals
Terraform is a powerful Infrastructure as Code (IaC) tool
that enables you to define and provision data center
infrastructure using a declarative configuration language.
Understanding its core concepts is essential to efficiently
manage scalable infrastructure.
Key Concepts:
Terraform vs. Other IaC Tools
Declarative vs. Imperative Approach
High-Level Architecture
Focus on the
resource
desired state;
Declarative "aws_s3_bucket"
automation
"my_bucket" { ... }
handles the 'how'.
High-Level Architecture
2. Terraform Core:
The core processes the .tf files, plans the changes, and
ensures the current state matches the desired state.
It manages the state file, which tracks your
infrastructure's current configuration.
Providers: Enable Terraform to interact with cloud
APIs like AWS, Azure, and Kubernetes.
Provisioners: Handle post-deployment tasks (e.g.,
running scripts or transferring files).
Key Concepts:
Terraform Installation
Configuring Providers
Understanding Terraform State
Configuring Backends for State Storage
Terraform Installation
Terraform is a single, lightweight executable file that
works on Windows, Linux, and macOS. Follow the steps
for your operating system below to get it installed and
ready.
Configuring Providers
Terraform uses providers to communicate with the
infrastructure you want to manage. Providers are plugins
that allow Terraform to work with specific services like
AWS, Azure, Google Cloud, or even on-premises
platforms like VMware.
1. Declare Providers
Providers are defined using the provider block, which tells
Terraform which API or service to interact with.
2. Download Providers
The terraform init command downloads the specified
providers from the Terraform Registry (or a local mirror)
into the .terraform directory.
3. Provider Caching
Use plugin_cache_dir to enable caching, speeding up
provider downloads and enabling offline workflows.
provider "google" {
project = "my-gcp-project"
region = "us-central1"
}
Provider Meta-Arguments
Alias: Use the same provider with different
configurations (e.g., multiple accounts, regions).
Default Provider: If no alias is specified, it is the
default configuration.
provider "google" {
project = "default-project"
region = "us-central1"
}
provider "google" {
alias = "secondary"
project = "secondary-project"
region = "us-east1"
}
resource "google_storage_bucket"
"secondary_bucket" {
provider = google.secondary
name = "my-secondary-bucket"
}
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
}
provider "google" {
project = "my-gcp-project"
region = "us-central1"
}
Best Practices:
Use remote backends for state storage.
Enable state locking using S3 (for AWS) or equivalent
solutions.
Regularly back up your state file.
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
use_lockfile = true
encrypt = true
}
}
terraform {
backend "azurerm" {
resource_group_name = "my-rg"
storage_account_name = "mystorageaccount"
container_name = "tfstate"
key =
"prod.terraform.tfstate"
}
}
terraform {
backend "gcs" {
bucket = "my-tf-state-bucket"
prefix = "prod/state"
}
}
Key Concepts:
Initialization (`terraform init`)
Writing and Organizing Terraform Configurations
Planning Changes (`terraform plan`)
Applying Changes (`terraform apply`)
Destroying Infrastructure (`terraform destroy`)
Run:
terraform init
Sample Output:
Example:
provider "aws" {
region = "us-east-1"
}
Example:
Example:
variable "instance_type" {
description = "Type of EC2 instance"
default = "t2.micro"
}
Example:
output "instance_ip" {
value = aws_instance.example.public_ip
}
Example:
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
}
}
Example:
instance_type = "t3.small"
Working Process:
Run:
terraform plan
Sample Output:
Creating/Modifying Resources:
Run:
terraform apply
Example output:
Run:
terraform destroy
Example output:
terraform destroy -
target=aws_instance.example
Key Concepts:
Working with Modules
Managing Multiple Environments
terraform-modules/
├── ec2-instance/
│ ├── main.tf # Main resource definitions
│ ├── variables.tf # Input variables
│ ├── outputs.tf # Outputs
variable "ami" {
description = "AMI ID for the instance"
}
variable "instance_type" {
description = "EC2 instance type"
default = "t2.micro"
}
output "instance_ip" {
value = aws_instance.resource_A.public_ip
}
module "ec2_instance" {
source = "./terraform-modules/ec2-instance"
ami = "ami-12345678"
instance_type = "t2.small"
}
terraform init
terraform apply
variable "ami" {
description = "AMI ID for the instance"
}
variable "instance_type" {
description = "Instance type"
default = "t2.micro"
}
module "ec2_instance" {
source = "./modules/child_module"
ami = "ami-12345678"
instance_type = "t2.small"
}
terraform init
terraform apply
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "3.14.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b"]
public_subnets = ["10.0.1.0/24",
"10.0.2.0/24"]
}
Output:
Output:
default
* dev
Command Description
Key Concepts:
Using Input Variables
Understanding Terraform Data Types
Outputs and Sharing Data Across Modules
variable "instance_type" {
description = "Type of EC2 instance to use"
default = "t2.micro"
}
variable "instance_count" {
description = "Number of instances to create"
type = number
default = 1
}
Here:
description: Describes the purpose of the variable.
type: Specifies the variable’s data type (optional but
good practice).
default: Provides a default value if no value is supplied.
instance_type = "t3.medium"
instance_count = 2
2. Using the CLI: Pass values directly using the -var flag
export TF_VAR_instance_type="t3.small"
Numeric values
Number count = var.count
(integers/floats).
enabled =
Boolean True or false values.
var.enabled
name =
Object Complex structures.
var.config.name
variables.tf:
variable "app_config" {
description = "Configuration for the
application"
type = object({
name = string
instance_count = number
tags = map(string)
})
default = {
name = "my-app"
instance_count = 3
tags = {
environment = "dev"
owner = "team-devops"
}
}
}
main.tf:
Example:
output "public_ip" {
description = "The public IP of the EC2
instance"
value = aws_instance.example.public_ip
}
Accessing Outputs
After applying your Terraform configuration, use the terraform
output command to view output values:
terraform output
Example Output:
public_ip = "54.123.45.67"
Example:
output "subnet_id" {
value = aws_subnet.example.id
}
Root Module:
module "network" {
source = "./modules/network"
}
module "app" {
source = "./modules/app"
subnet_id = module.network.subnet_id
Key Concepts:
Handling Dependencies in Terraform
Managing Sensitive Data
Dealing with Large Infrastructure
Implicit Dependencies
Terraform automatically detects implicit dependencies when
one resource references another. You do not need to define
these explicitly.
Example:
In this case:
Terraform understands that aws_subnet.example
depends on aws_vpc.example because vpc_id
references the VPC ID.
Explicit Dependencies
For cases where Terraform cannot infer dependencies
automatically, you can use the depends_on meta-argument
to define explicit dependencies.
Example:
depends_on = [aws_vpc.example]
}
terraform graph
Best Practices:
1. Use Remote Backends: Store state files securely in
encrypted remote backends like S3 with encryption enabled.
terraform {
backend "s3" {
bucket = "my-terraform-state"
encrypt = true
}
}
Sensitive Outputs
To prevent sensitive data from being exposed in Terraform
outputs, use the sensitive argument.
Example:
output "db_password" {
value = var.db_password
sensitive = true
}
provider "aws" {
max_retries = 3
}
Key Concepts:
Understanding Provisioners
Managing Resource Lifecycles
Managing Resource Cleanup and Failure Scenarios
Understanding Provisioners
Provisioner
Use Case Execution
Type
Run
Executes on the
scripts/commands
Local-Exec machine running
locally on your
Terraform.
machine.
Local-Exec Provisioner
The local-exec provisioner runs commands on the local
machine where Terraform is executed.
provisioner "local-exec" {
command = "echo 'EC2 instance created' >
instance_status.txt"
}
}
Remote-Exec Provisioner
The remote-exec provisioner runs commands on the remote
resource, like an EC2 instance.
connection {
type = "ssh"
user = "ec2-user"
private_key = file("~/.ssh/id_rsa")
host = self.public_ip
}
provisioner "remote-exec" {
inline = [
"sudo yum update -y",
"sudo yum install -y httpd",
"sudo systemctl start httpd"
]
}
}
Here:
1. connection block establishes an SSH connection.
2. inline specifies the list of commands to run sequentially.
connection {
type = "ssh"
user = "ec2-user"
private_key = file("~/.ssh/id_rsa")
host = self.public_ip
}
provisioner "remote-exec" {
inline = [
"sudo yum update -y",
"sudo yum install -y httpd",
"sudo systemctl start httpd"
]
}
}
Here:
1. connection block establishes an SSH connection.
2. inline specifies the list of commands to run sequentially.
Output:
Example:
terraform apply
Behavior Description
Example:
provisioner "local-exec" {
command = "exit 1"
on_failure = "continue"
}
terraform destroy
provisioner "local-exec" {
command = "./cleanup_script.sh"
on_failure = "continue"
}
Key Concepts:
Debugging Basics
Common Debugging Commands
Debugging Common Terraform Issues
Debugging Best Practices
Debugging Basics
Debugging in Terraform starts with understanding how to
enable logging and interpret log levels.
Example:
export TF_LOG=DEBUG
terraform apply
Example:
export TF_LOG=TRACE
terraform plan
Example:
export TF_LOG=DEBUG
export TF_LOG_PATH=/tmp/terraform.log
terraform apply
Steps to Debug:
1. Check provider configurations in provider.tf
2. Run with debugging enabled:
export TF_LOG=DEBUG
terraform init
Example Error:
Solution:
Ensure internet connectivity.
Check Terraform version compatibility with providers.
Steps to Debug:
1. Review the error message for resource-specific issues.
2. Enable detailed logs:
export TF_LOG=TRACE
terraform plan
terraform validate
Example Error:
Solution:
Verify variable values in terraform.tfvars.
Check if the correct workspace is selected.
Steps to Debug:
1. Run terraform state list to identify inconsistencies.
2. Use terraform refresh to reconcile the state with the real
infrastructure.
3. For critical issues, manually edit the state file (use with
caution).
Example Error:
Solution:
If a resource no longer exists, use terraform state rm to
remove it from the state
Command Description
Command Description
Command Description
Note:
LinkedIn link