Tutorial 5: Destroy Infrastructure
Learning Objectives
- Understand how to safely destroy Terraform-managed infrastructure
- Learn about partial destruction and resource targeting
- Understand protection mechanisms for critical resources
- Practice cleanup procedures and cost management
Prerequisites
- Completed previous tutorials with running infrastructure
- Understanding of Terraform state and resource dependencies
- Awareness of potential data loss implications
Why Destroy Infrastructure?
Common Scenarios
- Development/Testing: Clean up temporary environments
- Cost Management: Remove unused resources to save money
- Environment Refresh: Start with clean slate
- Decommissioning: Permanently remove old infrastructure
- Troubleshooting: Remove problematic resources
Important Considerations
- Data Loss: Destroying resources may result in permanent data loss
- Dependencies: Some resources must be destroyed in specific order
- Cost Impact: Verify what you're destroying to avoid surprises
- Backup: Ensure important data is backed up before destruction
The Destroy Command
Basic Syntax
terraform destroy
Common Options
# Auto-approve (use with caution)
terraform destroy -auto-approve
# Target specific resources
terraform destroy -target=aws_instance.web
# Use variable file
terraform destroy -var-file="production.tfvars"
# Set variables
terraform destroy -var="environment=dev"
Understanding Destruction Order
Dependency Resolution
Terraform destroys resources in reverse dependency order:
- Resources with no dependencies first
- Resources that depend on others last
- Automatic dependency resolution
Example Destruction Order
Given this infrastructure:
VPC → Subnet → Security Group → EC2 Instance → Load Balancer
Destruction order would be:
Load Balancer → EC2 Instance → Security Group → Subnet → VPC
Safe Destruction Practices
Step 1: Review Current State
# List all resources
terraform state list
# Review current configuration
terraform show
# Check outputs
terraform output
Step 2: Plan Destruction
terraform plan -destroy
This shows exactly what will be destroyed:
Terraform will perform the following actions:
# aws_instance.web will be destroyed
- resource "aws_instance" "web" {
- ami = "ami-0c55b159cbfafe1d0" -> null
- instance_type = "t2.micro" -> null
# ... all attributes will be destroyed
}
# aws_vpc.main will be destroyed
- resource "aws_vpc" "main" {
- cidr_block = "10.0.0.0/16" -> null
# ... all attributes will be destroyed
}
Plan: 0 to add, 0 to change, 6 to destroy.
Step 3: Backup Important Data
# Backup Terraform state
cp terraform.tfstate terraform.tfstate.backup
# Export important data (example)
terraform output > infrastructure-outputs.txt
# Backup any databases or persistent storage
# This varies by resource type and requirements
Step 4: Execute Destruction
terraform destroy
You'll be prompted for confirmation:
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
Partial Destruction (Targeting)
Destroy Specific Resources
# Destroy only the EC2 instance
terraform destroy -target=aws_instance.web
# Destroy multiple specific resources
terraform destroy -target=aws_instance.web -target=aws_lb.web
Destroy by Resource Type
# Remove all instances (if you have multiple)
terraform destroy -target=aws_instance
# This won't work directly, but you can target each individually
Target Module Resources
# Destroy all resources in a specific module
terraform destroy -target=module.web_servers
Protecting Critical Resources
Prevent Destroy Lifecycle Rule
resource "aws_db_instance" "production" {
# ... database configuration
lifecycle {
prevent_destroy = true # Prevents terraform destroy
}
}
If you try to destroy this resource:
terraform destroy
You'll get an error:
Error: Instance cannot be destroyed
on main.tf line 45:
45: resource "aws_db_instance" "production" {
Resource aws_db_instance.production has lifecycle.prevent_destroy
set, but the plan calls for this resource to be destroyed.
Override Protection (Use with Extreme Caution)
# Remove the prevent_destroy rule first, then destroy
# OR use -refresh=false and edit state (not recommended)
Handling Destruction Issues
Dependency Errors
Sometimes resources can't be destroyed due to dependencies:
Error: Error deleting VPC: DependencyViolation: The vpc 'vpc-12345' has dependencies and cannot be deleted.
Solutions:
- Check for manually created resources
- Use AWS Console to identify dependencies
- Remove dependencies manually
- Use
terraform refresh
to update state
Resource Not Found Errors
Error: Error deleting instance: InvalidInstanceID.NotFound
Solutions:
- The resource was already deleted outside Terraform
- Remove from state:
terraform state rm aws_instance.web
- Or run
terraform refresh
first
Stuck Resources
Some resources may fail to destroy due to:
- Protection policies
- Resource dependencies
- Service limits
- Network connectivity issues
Debug approach:
# Enable detailed logging
export TF_LOG=DEBUG
terraform destroy
# Check AWS CloudTrail for API errors
# Review resource-specific documentation
Force Removal from State
When to Use State Removal
- Resource was deleted outside Terraform
- Resource is stuck and can't be destroyed
- Need to stop managing a resource with Terraform
Remove from State (Without Destroying)
# Remove specific resource from state
terraform state rm aws_instance.web
# Remove multiple resources
terraform state rm aws_instance.web aws_instance.app
# Remove entire module
terraform state rm module.web_servers
Warning: This removes the resource from Terraform's knowledge but doesn't destroy the actual resource.
Cost-Effective Destruction Strategies
Stop vs. Destroy
For some resources, stopping is cheaper than destroying and recreating:
# Stop instance instead of destroying
resource "aws_instance" "web" {
# ... configuration
# Use count to effectively "stop" managing the resource
count = var.instance_enabled ? 1 : 0
}
Graduated Destruction
For complex environments, destroy in phases:
- Phase 1: Destroy compute resources (EC2, containers)
- Phase 2: Destroy networking (load balancers, NAT gateways)
- Phase 3: Destroy storage and databases (if safe)
- Phase 4: Destroy core networking (VPCs, subnets)
# Phase 1
terraform destroy -target=aws_instance.web -target=aws_autoscaling_group.web
# Phase 2
terraform destroy -target=aws_lb.web -target=aws_nat_gateway.main
# Phase 3 (be very careful with data!)
terraform destroy -target=aws_db_instance.main -target=aws_s3_bucket.data
# Phase 4
terraform destroy -target=aws_vpc.main
Data Backup Before Destruction
Database Backup Example
# Create RDS snapshot before destroying
aws rds create-db-snapshot \
--db-instance-identifier mydb \
--db-snapshot-identifier mydb-final-snapshot-$(date +%Y%m%d)
# Then destroy with final snapshot
For Terraform-managed snapshots:
resource "aws_db_instance" "main" {
# ... configuration
# Ensure final snapshot is created
final_snapshot_identifier = "mydb-final-snapshot"
skip_final_snapshot = false
# Backup retention
backup_retention_period = 7
}
S3 Bucket Backup
# Sync bucket contents before destroying
aws s3 sync s3://my-terraform-bucket ./backup-folder/
# Or enable versioning and lifecycle policies in Terraform
Automation and Scripts
Pre-Destruction Checklist Script
#!/bin/bash
# pre-destroy-checklist.sh
echo "Pre-Destruction Checklist"
echo "========================"
# Check current resources
echo "Current resources:"
terraform state list
# Show destruction plan
echo -e "\nDestruction plan:"
terraform plan -destroy -out=destroy.plan
# Prompt for confirmation
echo -e "\nPlease review the destruction plan above."
read -p "Are you sure you want to proceed? (yes/no): " confirm
if [ "$confirm" = "yes" ]; then
echo "Proceeding with destruction..."
terraform apply destroy.plan
else
echo "Destruction cancelled."
rm -f destroy.plan
fi
Post-Destruction Verification
#!/bin/bash
# post-destroy-verify.sh
echo "Post-Destruction Verification"
echo "============================"
# Check if any resources remain
resource_count=$(terraform state list | wc -l)
if [ $resource_count -eq 0 ]; then
echo "✓ All resources successfully destroyed"
else
echo "⚠ Warning: $resource_count resources remain in state"
terraform state list
fi
# Check for orphaned AWS resources (example)
echo -e "\nChecking for potential orphaned resources..."
aws ec2 describe-instances --query 'Reservations[].Instances[?Tags[?Key==`CreatedBy` && Value==`Terraform`]]'
Environment-Specific Destruction
Development Environment
# Quick destruction for dev environments
terraform destroy -auto-approve
Staging Environment
# More cautious approach for staging
terraform plan -destroy
# Review plan
terraform destroy
Production Environment
# Very careful approach for production
# 1. Full backup
# 2. Team approval
# 3. Maintenance window
# 4. Gradual destruction
# Create destruction plan
terraform plan -destroy -out=prod-destroy.plan
# Have team review the plan file
# Apply during maintenance window
terraform apply prod-destroy.plan
Monitoring Destruction
Logging
# Enable detailed logging
export TF_LOG=INFO
export TF_LOG_PATH=./terraform-destroy.log
terraform destroy
# Review logs
cat terraform-destroy.log
Cost Tracking
- Monitor AWS billing during destruction
- Verify resources are actually removed
- Check for any ongoing charges
Recovery Procedures
Accidental Destruction Recovery
From State Backup
# Restore state from backup
cp terraform.tfstate.backup terraform.tfstate
# Recreate infrastructure
terraform plan
terraform apply
From Version Control
# Restore configuration from git
git checkout HEAD~1 main.tf
# Recreate infrastructure
terraform init
terraform plan
terraform apply
Partial Recovery
# Import existing resources that weren't destroyed
terraform import aws_instance.web i-1234567890abcdef0
# Recreate only what was lost
terraform plan
terraform apply
Best Practices Checklist
Before Destroying
- Review
terraform plan -destroy
output - Backup critical data and configurations
- Verify backup integrity
- Check for any prevent_destroy lifecycle rules
- Notify team members (for shared environments)
- Document the reason for destruction
During Destruction
- Monitor the destruction process
- Watch for any errors or stuck resources
- Be prepared to handle dependency issues
- Keep logs of the destruction process
After Destruction
- Verify all resources are destroyed
- Check cloud provider billing/console
- Clean up any orphaned resources
- Update documentation
- Remove any DNS entries or external references
Common Mistakes to Avoid
- Not checking dependencies: Always review the destruction plan
- Forgetting data backup: Backup before destroying data resources
- Ignoring costs: Some resources continue billing even after "destruction"
- Not using targeting: Destroying everything when you only need to remove specific resources
- Force removal without cleanup: Using
terraform state rm
without cleaning up actual resources
Key Takeaways
- Always run
terraform plan -destroy
before actual destruction - Terraform destroys resources in reverse dependency order
- Use lifecycle rules to protect critical resources
- Backup important data before destruction
- Use targeting for partial destruction when appropriate
- Monitor costs and verify complete removal
- Have recovery procedures in place for accidental destruction
Next Steps
- Complete Tutorial 6: Variables and Configuration
- Learn about remote state management
- Explore workspace management for multiple environments
- Practice with modules and advanced configurations