During my learning of AWS and its deployment via Terraform, I came across an issue where my EC2 instances kept getting destroyed, even when no changes had been made to them. For example in the plan output:
# aws_instance.spoke2-ec2 must be replaced
-/+ resource "aws_instance" "spoke2-ec2" {
~ arn = "arn:aws:ec2:eu-west-2:97123148471:instance/i-04c0e1bc6b05b8b57" -> (known after apply)
~ associate_public_ip_address = false -> (known after apply)
~ disable_api_stop = false -> (known after apply)
~ disable_api_termination = false -> (known after apply)
~ ebs_optimized = false -> (known after apply)
+ enable_primary_ipv6 = (known after apply)
- hibernation = false -> null
+ host_id = (known after apply)
+ host_resource_group_arn = (known after apply)
~ id = "i-04c0e1bc6b05b8b57" -> (known after apply)
~ instance_initiated_shutdown_behavior = "stop" -> (known after apply)
+ instance_lifecycle = (known after apply)
~ instance_state = "running" -> (known after apply)
~ ipv6_address_count = 0 -> (known after apply)
~ ipv6_addresses = [] -> (known after apply)
+ key_name = (known after apply)
~ monitoring = false -> (known after apply)
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
~ placement_partition_number = 0 -> (known after apply)
~ primary_network_interface_id = "eni-048c35632b8cb0cca" -> (known after apply)
~ private_dns = "ip-10-192-4-11.eu-west-2.compute.internal" -> (known after apply)
~ private_ip = "10.192.4.11" -> (known after apply)
+ public_dns = (known after apply)
+ public_ip = (known after apply)
~ secondary_private_ips = [] -> (known after apply)
~ security_groups = [ # forces replacement
+ "sg-0a015bbb1dc6abac9",
]
+ spot_instance_request_id = (known after apply)
tags = {
"Name" = "spoke2-ec2"
}
+ user_data_base64 = (known after apply)
~ vpc_security_group_ids = [
- "sg-0a015bbb1dc6abac9",
] -> (known after apply)
Notice the “# forces replacement” on the security_groups directive.
Turns it it was quite a simple fix, although there are lifecycle directives you can add to avoid things being destroyed (or destroyed when you don’t expect them to be), in my case I was using the wrong directive for adding security groups. Instead of “security_groups”, I should have been using “vpc_security_groups_ids” instead. Swapping these directives in the Terraform allowed me to plan and apply without destroying my EC2 instances (when no modifications has been made).
resource "aws_instance" "spoke1-ec2" {
provider = aws.spoke1
ami = "ami-008ea0202116dbc56"
instance_type = "t2.micro"
tenancy = "default"
availability_zone = "eu-west-2a"
key_name = ""
subnet_id = aws_subnet.spoke1.id
#security_groups = [aws_security_group.spoke1-ec2-sg.id]
vpc_security_group_ids = [aws_security_group.spoke1-ec2-sg.id] # avoids replacement each time.
iam_instance_profile = aws_iam_instance_profile.ec2_profile1.name
tags = {
Name = "spoke1-ec2"
}
}
I should be using vpc_security_group_ids, instead of security_groups. The latter is only for default VPC and EC2-Classic.