Hi @Alko89,
The behavior you’ve outlined here – of making a change that only applies to new instances of a resource rather than immediately replacing the existing ones – is what the ignore_changes lifecycle setting is aimed at:
resource "aws_instance" "ubuntu_linux" {
ami = data.aws_ami.ubuntu_linux_ami.id
# ...
lifecycle {
ignore_changes = [ami]
}
}
This tells Terraform to ignore the fact that you’ve (in effect) changed the configuration of this resource when comparing to already-existing instances. With that done, you’ll then need to define some separate process by which the updated AMI will eventually be used, which will ultimately require replacing this instance, but you can make that a separate explicit step rather than it just happening immediately after a new AMI is available.
One direct way to arrange for that replacement would be to use the -replace option to terraform plan, which essentially forces Terraform to generate a “replace” plan for a particular resource instance even though there isn’t a configuration change calling for that:
terraform apply -replace='aws_instance.ubuntu_linux'
This last part is more of an AWS thing than a Terraform thing, but I also wanted to note that when it comes to managing fleets of EC2 instances that all run the same software for the purposes of scaling out, it can be helpful to use AWS autoscaling rather than managing each instance individually in Terraform.
If you use autoscaling then the AMI will be part of the launch configuration or launch template, and so you can get an effect similar to what you described here by using Terraform to change the launch settings such that EC2 autoscaling will use the new settings for any new instances it creates, but will leave the others untouched.
For fleets of instances that are all interchangeable, this model can make it easier to roll out changes such as a new AMI in a way that doesn’t cause downtime, with strategies such as gradually terminating the old instances one by one (waiting each time for autoscaling to automatically launch a replacement in order to retain the desired amount) or by temporarily increasing the desired instance count and then decreasing it again once autoscaling has responded, at which point autoscaling will gradually terminate instances to return to the previous count.
(You can use the termination_policies argument to influence which instances autoscaling will terminate first when it detects that there are more instances than desired.)