Terraform Development
Project Structure
terraform/ ├── main.tf # Main resources ├── variables.tf # Input variables ├── outputs.tf # Output values ├── providers.tf # Provider config ├── versions.tf # Version constraints ├── terraform.tfvars # Variable values └── modules/ └── vpc/ ├── main.tf ├── variables.tf └── outputs.tf
Provider Configuration
versions.tf
terraform { required_version = ">= 1.5"
required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } }
backend "s3" { bucket = "terraform-state" key = "prod/terraform.tfstate" region = "us-east-1" dynamodb_table = "terraform-locks" encrypt = true } }
provider "aws" { region = var.aws_region
default_tags { tags = { Environment = var.environment ManagedBy = "terraform" } } }
Variables
variables.tf
variable "environment" { description = "Environment name" type = string
validation { condition = contains(["dev", "staging", "prod"], var.environment) error_message = "Environment must be dev, staging, or prod." } }
variable "instance_config" { description = "EC2 instance configuration" type = object({ instance_type = string ami_id = string volume_size = number })
default = { instance_type = "t3.micro" ami_id = "ami-12345678" volume_size = 20 } }
Resources
main.tf
resource "aws_vpc" "main" { cidr_block = var.vpc_cidr enable_dns_hostnames = true
tags = { Name = "${var.project}-vpc" } }
resource "aws_subnet" "private" { count = length(var.availability_zones) vpc_id = aws_vpc.main.id cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index) availability_zone = var.availability_zones[count.index]
tags = { Name = "${var.project}-private-${count.index + 1}" } }
Modules
Using a module
module "vpc" { source = "./modules/vpc"
project = var.project environment = var.environment cidr_block = "10.0.0.0/16" }
Module outputs
output "vpc_id" { value = module.vpc.vpc_id }
Data Sources
data "aws_ami" "amazon_linux" { most_recent = true owners = ["amazon"]
filter { name = "name" values = ["amzn2-ami-hvm-*-x86_64-gp2"] } }
resource "aws_instance" "web" { ami = data.aws_ami.amazon_linux.id instance_type = var.instance_type }
Workflow
Initialize
terraform init
Format
terraform fmt -recursive
Validate
terraform validate
Plan
terraform plan -out=tfplan
Apply
terraform apply tfplan
Destroy
terraform destroy
Best Practices
-
Use remote state with locking
-
Use modules for reusability
-
Use variables for all configurable values
-
Use data sources for existing resources
-
Tag all resources
-
Use workspaces or directories for environments