Terraform Recreates EC2 Instances on Every Plan

Have you ever seen an issue where Terraform recreates AWS EC2 instances on every plan and apply?

Let's say you have config like,

resource "aws_instance" "example" {
    ami           = "ami-799d981a"
    instance_type = "t2.micro"
}

Let's look at the AMI,

$ aws ec2 describe-images --image-ids ami-799d981a
{
    "Images": [
        {
            "Architecture": "x86_64",
            "CreationDate": "2017-01-11T05:18:23.000Z",
            "ImageId": "ami-799d981a",
            "ImageLocation": "099720109477/ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-20170110",
            "ImageType": "machine",
            "Public": true,
            "OwnerId": "099720109477",
            "State": "available",
            "BlockDeviceMappings": [
                {
                    "DeviceName": "/dev/sda1",
                    "Ebs": {
                        "Encrypted": false,
                        "DeleteOnTermination": true,
                        "SnapshotId": "snap-0b980056555867089",
                        "VolumeSize": 8,
                        "VolumeType": "gp2"
                    }
                },
                {
                    "DeviceName": "/dev/sdb",
                    "VirtualName": "ephemeral0"
                },
                {
                    "DeviceName": "/dev/sdc",
                    "VirtualName": "ephemeral1"
                }
            ],
            "Hypervisor": "xen",
            "Name": "ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-20170110",
            "RootDeviceName": "/dev/sda1",
            "RootDeviceType": "ebs",
            "SriovNetSupport": "simple",
            "VirtualizationType": "hvm"
        }
    ]
}

In the output above, the sections we're interested in are BlockDeviceMappings, RootDeviceType, and RootDeviceName. All of these indicate that the root device is based on EBS. If you were me, you could change your Terraform config to look like below if you wanted to, for example, increase the disk size in your instance.

resource "aws_instance" "example" {
    ami           = "ami-799d981a"
    instance_type = "t2.micro"

    ebs_block_device = {
        device_name           = "dev/sda1"
        volume_size           = "20"
        volume_type           = "gp2"
        encryption            = false
        delete_on_termination = true
    }
}

When you run your plan for the first time, it'll show you're creating a new instance. Apply that plan to actually create the instance. Run terraform plan again and you'll notice that Terraform wants to destroy the existing instance and create it again.

A lot of people have run into this kind of issue but their problems and solutions were different from this issue.

This particular issue is exactly the same as the one described in the last link above. bflad pointed out the mistake I, and the creator of that GitHub issue, made.

If you are trying to reference the root EBS block device (e.g. device name listed as the RootDeviceName of the AMI), it needs to be declared in your Terraform configuration as the root_block_device argument, not a ebs_block_device argument.

I changed my config like so and Terraform did not attempt to recreate (destroy and create) the EC2 instance anymore on subsequent plans.

resource "aws_instance" "example" {
    ami           = "ami-799d981a"
    instance_type = "t2.micro"

    root_block_device = {
        volume_size           = "20"
        volume_type           = "gp2"
        delete_on_termination = true
    }
}