AskLearn
Loading...
← Back to Terraform Course
BeginnerGetting Started

Change Infrastructure

Modify existing infrastructure

Tutorial 4: Change Infrastructure

Learning Objectives

  • Understand how Terraform handles infrastructure changes
  • Learn about different types of resource modifications
  • Practice updating existing infrastructure
  • Understand resource lifecycle management

Prerequisites

  • Completed Tutorial 3: Build Infrastructure
  • Understanding of basic Terraform workflow
  • Existing infrastructure from previous tutorial (or recreate it)

Types of Infrastructure Changes

1. In-Place Updates

Changes that can be applied without destroying the resource:

  • Tags modification
  • Security group rule updates
  • Instance metadata changes

2. Recreation Required

Changes that require destroying and recreating the resource:

  • Instance type changes (usually)
  • AMI changes
  • Subnet changes

3. Addition/Removal

  • Adding new resources
  • Removing existing resources

Working with Existing Infrastructure

Current State Check

# List current resources
terraform state list

# Show detailed state
terraform show

# Check current outputs
terraform output

Verify Infrastructure

# Ensure everything is up to date
terraform plan

If you don't have infrastructure from Tutorial 3, recreate it:

# Apply the configuration from Tutorial 3
terraform apply

Making In-Place Changes

Example 1: Updating Tags

Modify your main.tf to update instance tags:

resource "aws_instance" "web" {
  ami                    = data.aws_ami.amazon_linux.id
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.main.id
  vpc_security_group_ids = [aws_security_group.web.id]
  
  user_data = <<-EOF
              #!/bin/bash
              yum update -y
              yum install -y httpd
              systemctl start httpd
              systemctl enable httpd
              echo "<h1>Hello from Terraform - Updated!</h1>" > /var/www/html/index.html
              EOF
  
  tags = {
    Name         = "terraform-web-server"
    Environment  = "development"
    Project      = "terraform-tutorial"
    Owner        = "DevOps Team"
    LastModified = "2024-01-15"
  }
}

Plan and Apply Changes

terraform plan

Expected output:

  # aws_instance.web will be updated in-place
  ~ resource "aws_instance" "web" {
      ~ tags                   = {
          + "LastModified" = "2024-01-15"
          + "Owner"        = "DevOps Team"
            # (3 unchanged elements hidden)
        }
      ~ tags_all               = {
          + "LastModified" = "2024-01-15"
          + "Owner"        = "DevOps Team"
            # (3 unchanged elements hidden)
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.
terraform apply

Example 2: Updating Security Group Rules

Add HTTPS access to the security group:

resource "aws_security_group" "web" {
  name        = "terraform-web-sg"
  description = "Security group for web servers"
  vpc_id      = aws_vpc.main.id
  
  # HTTP access
  ingress {
    description = "HTTP"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  # HTTPS access - NEW RULE
  ingress {
    description = "HTTPS"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  # SSH access
  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]  # Restrict this in production!
  }
  
  # All outbound traffic
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  tags = {
    Name = "terraform-web-sg"
  }
}

Apply the security group changes:

terraform plan
terraform apply

Making Changes That Require Recreation

Example 1: Changing Instance Type

Modify the instance type in main.tf:

resource "aws_instance" "web" {
  ami                    = data.aws_ami.amazon_linux.id
  instance_type          = "t3.micro"  # Changed from t2.micro
  subnet_id              = aws_subnet.main.id
  vpc_security_group_ids = [aws_security_group.web.id]
  
  # ... rest of configuration
}

Plan the Change

terraform plan

Expected output:

  # aws_instance.web must be replaced
-/+ resource "aws_instance" "web" {
      ~ instance_type               = "t2.micro" -> "t3.micro" # forces replacement
      ~ public_ip                   = "54.123.45.67" -> (known after apply)
      # ... other changes
    }

Plan: 1 to add, 0 to change, 1 to destroy.

Note: The -/+ indicates the resource will be destroyed and recreated.

Apply with Caution

terraform apply

Warning: This will cause downtime as the instance is destroyed and recreated.

Adding New Resources

Add an Application Load Balancer

Add to main.tf:

# Create target group for load balancer
resource "aws_lb_target_group" "web" {
  name     = "terraform-web-tg"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.main.id
  
  health_check {
    enabled             = true
    healthy_threshold   = 2
    unhealthy_threshold = 2
    timeout             = 5
    interval            = 30
    path                = "/"
    matcher             = "200"
  }
  
  tags = {
    Name = "terraform-web-tg"
  }
}

# Create Application Load Balancer
resource "aws_lb" "web" {
  name               = "terraform-web-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.web.id]
  subnets            = [aws_subnet.main.id, aws_subnet.secondary.id]
  
  enable_deletion_protection = false
  
  tags = {
    Name = "terraform-web-alb"
  }
}

# Create additional subnet for ALB (requires 2 AZs)
resource "aws_subnet" "secondary" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.2.0/24"
  availability_zone       = "us-west-2b"
  map_public_ip_on_launch = true
  
  tags = {
    Name = "terraform-subnet-secondary"
  }
}

# Associate secondary subnet with route table
resource "aws_route_table_association" "secondary" {
  subnet_id      = aws_subnet.secondary.id
  route_table_id = aws_route_table.main.id
}

# Create listener for load balancer
resource "aws_lb_listener" "web" {
  load_balancer_arn = aws_lb.web.arn
  port              = "80"
  protocol          = "HTTP"
  
  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.web.arn
  }
}

# Attach instance to target group
resource "aws_lb_target_group_attachment" "web" {
  target_group_arn = aws_lb_target_group.web.id
  target_id        = aws_instance.web.id
  port             = 80
}

Update Outputs

Add to outputs.tf:

output "load_balancer_dns" {
  description = "DNS name of the load balancer"
  value       = aws_lb.web.dns_name
}

output "load_balancer_url" {
  description = "URL to access the website via load balancer"
  value       = "http://${aws_lb.web.dns_name}"
}

Apply New Resources

terraform plan
terraform apply

Resource Dependencies and Ordering

Implicit Dependencies

Terraform automatically determines dependencies from resource references:

resource "aws_instance" "web" {
  subnet_id = aws_subnet.main.id  # Depends on subnet
  # Subnet must be created before instance
}

Explicit Dependencies

Use depends_on when implicit dependencies aren't sufficient:

resource "aws_instance" "web" {
  # ... configuration
  
  depends_on = [
    aws_internet_gateway.main,  # Ensure IGW exists first
    aws_route_table_association.main
  ]
}

Understanding Resource Lifecycle

Lifecycle Rules

Control how Terraform handles resource changes:

resource "aws_instance" "web" {
  # ... configuration
  
  lifecycle {
    # Prevent accidental deletion
    prevent_destroy = true
    
    # Create new resource before destroying old one
    create_before_destroy = true
    
    # Ignore changes to certain attributes
    ignore_changes = [
      tags["LastModified"],
      user_data
    ]
  }
}

Create Before Destroy

Useful for zero-downtime deployments:

resource "aws_launch_configuration" "web" {
  # ... configuration
  
  lifecycle {
    create_before_destroy = true
  }
}

Handling Resource Drift

Detect Drift

# Check for configuration drift
terraform plan

# Refresh state without applying changes
terraform refresh

Import Existing Resources

If resources were modified outside Terraform:

# Import manually created resource
terraform import aws_instance.web i-1234567890abcdef0

Ignore External Changes

Use ignore_changes to ignore external modifications:

resource "aws_instance" "web" {
  # ... configuration
  
  lifecycle {
    ignore_changes = [
      tags,           # Ignore tag changes made outside Terraform
      security_groups # Ignore security group changes
    ]
  }
}

Removing Resources

Remove from Configuration

Simply delete the resource block from your configuration:

# Remove this entire block to delete the resource
# resource "aws_lb" "web" {
#   # ... configuration
# }

Plan and Apply Removal

terraform plan  # Shows resources to be destroyed
terraform apply

Protect Important Resources

resource "aws_instance" "production_db" {
  # ... configuration
  
  lifecycle {
    prevent_destroy = true  # Prevents accidental deletion
  }
}

Advanced Change Scenarios

Conditional Resources

Use count to conditionally create resources:

variable "create_load_balancer" {
  description = "Whether to create load balancer"
  type        = bool
  default     = false
}

resource "aws_lb" "web" {
  count = var.create_load_balancer ? 1 : 0
  
  # ... configuration
}

Toggle the load balancer:

# Create with load balancer
terraform apply -var="create_load_balancer=true"

# Remove load balancer
terraform apply -var="create_load_balancer=false"

Resource Replacement Strategies

1. Blue-Green Deployment Pattern

variable "environment_suffix" {
  description = "Environment suffix for blue-green deployments"
  type        = string
  default     = "blue"
}

resource "aws_instance" "web" {
  ami           = data.aws_ami.amazon_linux.id
  instance_type = "t2.micro"
  
  tags = {
    Name = "web-server-${var.environment_suffix}"
  }
}

Switch environments:

# Deploy green environment
terraform apply -var="environment_suffix=green"

# Switch back to blue
terraform apply -var="environment_suffix=blue"

Testing Your Changes

Validate Configuration

terraform validate

Check Plan Output

terraform plan -out=tfplan

Test Infrastructure

# Test web server
curl http://$(terraform output -raw instance_public_ip)

# Test load balancer (if created)
curl http://$(terraform output -raw load_balancer_dns)

Rollback Strategies

Using Version Control

# Revert to previous configuration
git checkout HEAD~1 main.tf
terraform plan
terraform apply

State Backup

# Terraform automatically backs up state
ls terraform.tfstate*

# Restore from backup if needed
mv terraform.tfstate.backup terraform.tfstate

Targeted Operations

# Apply changes to specific resources only
terraform apply -target=aws_instance.web

# Destroy specific resources
terraform destroy -target=aws_lb.web

Best Practices for Changes

1. Always Plan First

terraform plan -out=tfplan
terraform apply tfplan

2. Use Version Control

  • Commit configuration changes
  • Tag releases
  • Review changes via pull requests

3. Test in Non-Production

  • Use separate environments
  • Test changes thoroughly
  • Validate functionality

4. Monitor Changes

  • Watch for unexpected modifications
  • Use resource tagging for tracking
  • Monitor costs and usage

5. Document Changes

  • Comment complex changes
  • Maintain change logs
  • Document rollback procedures

Key Takeaways

  • Terraform handles three types of changes: in-place updates, recreation, and addition/removal
  • Always run terraform plan to preview changes before applying
  • Some changes require resource recreation, which may cause downtime
  • Use lifecycle rules to control resource behavior
  • Resource dependencies are managed automatically by Terraform
  • Practice changes in development environments first
  • Version control your configurations for easy rollbacks

Next Steps

  1. Complete Tutorial 5: Destroy Infrastructure
  2. Learn about variables and input validation
  3. Explore modules for reusable configurations
  4. Practice with more complex change scenarios

Additional Resources