Terraform is an infrastructure as code tool for creating, modifying and versioning infrastructure securely and efficiently across all cloud providers.
Installation
Platform Command Ubuntu/Debian wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpgCentOS/RHEL sudo yum install -y yum-utils && sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repomacOS brew tap hashicorp/tap && brew install terraformWindows choco install terraformDirect binary Download from releases.hashicorp.com
Essential commands
Action Command Description Initialize terraform initInitialize project and download providers Plan terraform planShow changes that will be applied Apply terraform applyApply changes to infrastructure Destroy terraform destroyDelete all managed resources Validate terraform validateCheck file syntax State terraform showDisplay current state Refresh terraform refreshUpdate state with reality
State management
Action Command List resources terraform state listView a resource terraform state show aws_instance.webImport resource terraform import aws_instance.web i-1234567890abcdef0Remove from state terraform state rm aws_instance.webMove resource terraform state mv aws_instance.web aws_instance.web2Pull state terraform state pullPush state terraform state push terraform.tfstate
Useful options
Option Example Usage Target terraform apply -target=aws_instance.webApply only to one resource Auto-approve terraform apply -auto-approveNo interactive confirmation Var-file terraform apply -var-file="prod.tfvars"Use a variables file Var terraform apply -var="instance_count=3"Pass a variable State terraform apply -state=custom.tfstateUse a custom state file Plan file terraform plan -out=plan.outSave the plan
File structure
Recommended organization
terraform-project/
├── main.tf # Main configuration
├── variables.tf # Variable declarations
├── outputs.tf # Outputs
├── terraform.tfvars # Variable values
├── versions.tf # Provider versions
└── modules/ # Reusable modules
├── vpc/
├── ec2/
└── rds/
Example main.tf file
terraform {
required_version = " >= 1.0 "
required_providers {
vsphere = {
source = " hashicorp/vsphere "
version = " ~> 2.0 "
}
}
}
provider "vsphere" {
user = var . vsphere_user
password = var . vsphere_password
vsphere_server = var . vsphere_server
# If self-signed certificate
allow_unverified_ssl = true
}
# Datasources to retrieve vSphere info
data "vsphere_datacenter" "datacenter" {
name = " Datacenter "
}
data "vsphere_datastore" "datastore" {
name = " datastore1 "
datacenter_id = data . vsphere_datacenter . datacenter . id
}
data "vsphere_compute_cluster" "cluster" {
name = " cluster1 "
datacenter_id = data . vsphere_datacenter . datacenter . id
}
data "vsphere_network" "network" {
name = " VM Network "
datacenter_id = data . vsphere_datacenter . datacenter . id
}
data "vsphere_virtual_machine" "template" {
name = " ubuntu-20.04-template "
datacenter_id = data . vsphere_datacenter . datacenter . id
}
# VM
resource "vsphere_virtual_machine" "web" {
name = " ${ var . vm_name } -web "
resource_pool_id = data . vsphere_compute_cluster . cluster . resource_pool_id
datastore_id = data . vsphere_datastore . datastore . id
num_cpus = 2
memory = 4096
guest_id = data . vsphere_virtual_machine . template . guest_id
scsi_type = data . vsphere_virtual_machine . template . scsi_type
network_interface {
network_id = data . vsphere_network . network . id
adapter_type = data . vsphere_virtual_machine . template . network_interface_types[ 0 ]
}
disk {
label = " disk0 "
size = data . vsphere_virtual_machine . template . disks . 0 . size
eagerly_scrub = data . vsphere_virtual_machine . template . disks . 0 . eagerly_scrub
thin_provisioned = data . vsphere_virtual_machine . template . disks . 0 . thin_provisioned
}
clone {
template_uuid = data . vsphere_virtual_machine . template . id
customize {
linux_options {
host_name = " ${ var . vm_name } -web "
domain = " example.com "
}
network_interface {
ipv4_address = " 192.168.1.100 "
ipv4_netmask = 24
}
ipv4_gateway = " 192.168.1.1 "
dns_server_list = [ " 8.8.8.8 " , " 8.8.4.4 " ]
}
}
}
Variables (variables.tf)
variable "vsphere_server" {
description = " vCenter server "
type = string
default = " vcenter.example.com "
}
variable "vsphere_user" {
description = " vSphere user "
type = string
}
variable "vsphere_password" {
description = " vSphere password "
type = string
sensitive = true
}
variable "vm_name" {
description = " Base VM name "
type = string
default = " terraform-vm "
}
variable "vm_count" {
description = " Number of VMs to create "
type = number
default = 1
}
Outputs (outputs.tf)
output "vm_name" {
description = " Created VM name "
value = vsphere_virtual_machine . web . name
}
output "vm_ip" {
description = " VM IP address "
value = vsphere_virtual_machine . web . default_ip_address
}
output "vm_uuid" {
description = " VM UUID "
value = vsphere_virtual_machine . web . uuid
sensitive = false
}
Modules
Create a module
# modules/vm/main.tf
resource "vsphere_virtual_machine" "this" {
name = var . vm_name
resource_pool_id = var . resource_pool_id
datastore_id = var . datastore_id
num_cpus = var . num_cpus
memory = var . memory
guest_id = var . guest_id
network_interface {
network_id = var . network_id
}
disk {
label = " disk0 "
size = var . disk_size
}
clone {
template_uuid = var . template_uuid
customize {
linux_options {
host_name = var . vm_name
domain = var . domain
}
network_interface {
ipv4_address = var . ip_address
ipv4_netmask = 24
}
ipv4_gateway = var . gateway
}
}
}
# modules/vm/variables.tf
variable "vm_name" {
description = " VM name "
type = string
}
variable "num_cpus" {
description = " Number of CPUs "
type = number
default = 2
}
variable "memory" {
description = " Memory in MB "
type = number
default = 4096
}
Use a module
module "web_server" {
source = " ./modules/vm "
vm_name = " web-01 "
resource_pool_id = data . vsphere_compute_cluster . cluster . resource_pool_id
datastore_id = data . vsphere_datastore . datastore . id
network_id = data . vsphere_network . network . id
template_uuid = data . vsphere_virtual_machine . template . id
guest_id = data . vsphere_virtual_machine . template . guest_id
num_cpus = 4
memory = 8192
ip_address = " 192.168.1.101 "
gateway = " 192.168.1.1 "
domain = " example.com "
}
# Reference a module output
output "web_server_ip" {
value = module . web_server . ip_address
}
Best practices
Practice Description Organization Separate by environment and services Tagging Use consistent tags everywhere Remote state Always use a remote backend Secrets Never hardcode secrets Documentation Comment and document the code Validation Test with terraform plan Modules Reuse with modules Versioning Lock provider versions
Debugging & Troubleshooting
Debug Command Debug mode TF_LOG=DEBUG terraform applyDetailed logs TF_LOG=TRACE terraform planGraph terraform graph | dot -Tpng > graph.pngFormat check terraform fmt -check -diffAuto format terraform fmt -recursive