Managing resources using Terraform, we sometimes need to protect our resources from accidental deletion.
This is our day 9 of learning Terraform with AWS. Whenever we are managing resources using Terraform, we can destroy all the resources with a single command (terraform destroy). However, there are certain resources we do not want to delete such as databases or S3 buckets with important data.
To protect these resources, Terraform provides lifecycle meta-arguments.
Let’s see how it works
Example 1: Preventing downtime - create_before_destroy
Consider you want to deploy an API on EC2 instances that sit behind a load balancer.
If you destroy the resource, the API will face downtime until a new instance is created again. This can cause business loss, and users may lose trust if it happens frequently.
To prevent downtime, we can use the lifecycle meta-argument create_before_destroy, which tells Terraform to create a new resource before destroying the old one.
Example:
resource "aws_instance" "api_server" {
ami = "ami-12345678"
instance_type = "t3.micro"
lifecycle {
create_before_destroy = true
}
}
Example 2: Protecting critical resources - prevent_destroy
Now consider a requirement to store compliance-related documents. You create an S3 bucket for this purpose.
If this S3 bucket gets destroyed, all compliance documents will be lost.
To avoid this, Terraform provides the prevent_destroy argument.
Example:
resource "aws_s3_bucket" "compliance_docs" {
bucket = "my-compliance-docs-bucket"
lifecycle {
prevent_destroy = true
}
}
Example 3: Ignoring externally managed changes - ignore_changes
Suppose your API experiences a sudden spike and you rely on autoscaling policies.
If an Auto Scaling Group is created using Terraform with a default capacity, Terraform may later try to override changes made automatically by scaling policies. This can cause API performance issues.
To prevent this, we tell Terraform that the capacity is managed outside Terraform, and it should ignore changes to that attribute. For this, we use ignore_changes.
Example:
resource "aws_autoscaling_group" "api_asg" {
name = "api-asg"
min_size = 2
max_size = 10
desired_capacity = 2
lifecycle {
ignore_changes = [desired_capacity]
}
}
Example 4: Triggering replacement on dependency changes - replace_triggered_by
Terraform also provides replace_triggered_by in lifecycle meta-arguments, which is useful when you want to replace a resource when something else changes.
Example:
resource "aws_instance" "app_server" {
ami = "ami-12345678"
instance_type = var.instance_type
lifecycle {
replace_triggered_by = [
var.instance_type,
aws_security_group.app_sg.id
]
}
}
Example 5: Validating input and output - precondition and postcondition
There are cases where we must validate inputs (like regions or environment constraints) or outputs (such as resource attributes after deployment).
To handle these scenarios, Terraform provides precondition and postcondition.
Example:
resource "aws_s3_bucket" "logs" {
bucket = var.bucket_name
lifecycle {
precondition {
condition = length(var.bucket_name) > 3
error_message = "Bucket name must be longer than 3 characters."
}
postcondition {
condition = self.versioning[0].enabled == true
error_message = "Versioning must be enabled for this bucket."
}
}
}
Top comments (0)