Terraform 1.5: Using prevent_destroy to Enable Cost‑Saving Instance Lifecycle
0 reputation · 25 Nov 2024, 18:47 UTC
0 reputation · 25 Nov 2024, 18:47 UTC
Reduce recurring hourly charges for a low‑traffic application by periodically destroying non‑critical compute resources while keeping essential stateful components alive.
The prevent_destroy lifecycle block is documented to protect specified resources, but its interaction with count or for_each when scaling down raises questions. Remote state backends with locking add another layer of complexity, especially when automated scripts trigger terraform destroy during off‑peak windows. DNS propagation delays and cold‑start latency also need to be accounted for in the overall cost‑saving strategy.
lifecycle { prevent_destroy = true } on critical resources while allowing count‑controlled compute instances to be destroyed and recreated without breaking dependencies?terraform destroy be reliably integrated with remote backend locking to avoid race conditions during idle‑period cost optimization?31275 reputation · 26 Nov 2024, 03:53 UTC
To protect essential resources with lifecycle { prevent_destroy = true } while allowing count-controlled compute instances to be destroyed and recreated, follow these steps:
lifecycle block:resource "aws_db_instance" "critical" {
# … configuration …
lifecycle {
prevent_destroy = true
}
}count-based compute instance references only immutable identifiers of the protected resource (e.g., its ID or ARN). Do **not** reference changeable attributes such as public IP, DNS name, or endpoint that could change on replacement.resource "aws_instance" "worker" {
count = var.worker_count
ami = data.aws_ami.latest.id
instance_type = "t3.micro"
# Reference the protected DB by its immutable ID
db_subnet_group = aws_db_instance.critical.db_subnet_group_name
# Example: pass the DB ID via an environment variable or user data
user_data = <<-EOF
#!/bin/bash
echo "DB_ID=${aws_db_instance.critical.id}" >> /etc/app.conf
EOF
lifecycle {
# Optional: ignore changes to the protected resource’s tags to avoid unnecessary recreation
ignore_changes = [tags]
}
}depends_on on the instance, not the other way around:resource "aws_instance" "worker" {
# …
depends_on = [aws_db_instance.critical]
}
count variable (or use for_each) and run terraform apply. Terraform will destroy the excess instances while leaving the protected resource untouched.terraform apply (with reduced count) in a script that acquires a lock before running. If you use a remote backend with locking (e.g., S3 + DynamoDB, Consul, or Terraform Cloud), the backend lock already prevents concurrent runs; you only need to ensure the scheduler does not launch overlapping invocations.prevent_destroy = true blocks any destroy action on that resource, irrespective of whether it uses count or for_each.prevent_destroy (including count‑controlled compute instances) can still be targeted for destroy/recreate even when other resources have the flag set, provided there are no hard dependencies on mutable attributes of the protected resource.To keep dependencies stable across destroy/recreate cycles, expose only immutable identifiers from the protected resource (e.g., id, arn) to the compute instances. Avoid referencing attributes that may change if the protected resource were ever replaced (e.g., public_ip, dns_endpoint). If you must use a changeable attribute, consider adding a lifecycle { ignore_changes = [...]} block on the compute instance or using a data source that reads the current value after each apply.
State drift from external processes (autoscaling groups, manual edits) can be mitigated by:
terraform refresh before each scheduled apply to reconcile state with real‑world infrastructure.terraform plan -detailed-exitcode in automation and treating any non‑zero exit as a drift alert.Do any of your count‑controlled compute instances directly reference mutable attributes (e.g., public IP, DNS name, or endpoint) of the prevent_destroy-protected resource? If yes, the destroy/recreate cycle may fail or cause downtime, and you would need to replace those references with immutable IDs or introduce a data source/indirection layer.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.