Create AMI for Existing Instance Using Terraform

We are going to create an AMI from an existing EC2 instance named "devops-ec2"

Steps:

1. We need to find the existing EC2 instance by its name (tag) to get its ID.

2. Then, we will create an AMI from that instance ID.

3. We will name the AMI as "devops-ec2-ami".

4. We must ensure that the AMI is in the "available" state before we consider the process complete.

However, note that creating an AMI is an asynchronous operation. Terraform will not wait for the AMI to be available by default.

We can use the AWS_AMI resource and then use a data source to wait for the AMI to become available? But note: Terraform might not have built-in waiting for the AMI to be available in the resource. We might have to use a provisioner or a separate null_resource with a local-exec to wait.

Alternatively, we can use the AWS_AMI resource and then use a null_resource with a local-exec that uses the AWS CLI to wait until the AMI is available.

However, let's consider: The AWS_AMI resource has an attribute state which we can check via a data source, but we cannot easily make Terraform wait without a custom provisioner.

Another idea:

We can use the AWS_AMI resource and then use a time_sleep resource to wait for a while and then use a Data source to check the AMI status? But that is not deterministic.

Alternatively, we can use the AWS_AMI resource and then use a provisioner “local-exec” that runs a script to wait for the AMI to be available.

But note: The AWS_AMI resource does not have a direct provisioner. We can use a null_resource that depends on the AWS_AMI and then runs a script to wait.

Let's break down:

Step 1:

Find the instance by name. We'll use a data source to get the instance ID.

Step 2:

Create the AMI using the aws_ami_from_instance resource. This resource is specifically for creating an AMI from an instance.

Step 3:

We want to ensure that the AMI is available. We can use the aws_ami data source to wait for the AMI to be available, but note that the data source does not wait by default. We can use a depends_on in the data source? Actually, the data source will read at apply time, but if the AMI is not available, it will fail.

Alternatively, we can use the aws_ami data source and set it to depend on the aws_ami_from_instance resource. Then we can have a local-exec that waits? Or we can use the aws_ami data source and then use its state to trigger a wait script?

However, there is a better way: the aws_ami_from_instance resource has an attribute id which is the AMI ID. We can use a null_resource that runs a script to wait for the AMI to be available using the AWS CLI.

Let’s Now create the main.tf file :

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "6.6.0"
    }
  }
}

provider "aws" {
  # Configuration options
  region = "us-east-1"
}

# Fetch existing EC2 instance
data "aws_instance" "devops_ec2" {
  filter {
    name   = "tag:Name"
    values = ["devops-ec2"]
  }
}

# Create AMI from instance
resource "aws_ami_from_instance" "devops_ec2_ami" {
  name               = "devops-ec2-ami"
  source_instance_id = data.aws_instance.devops_ec2.id
}

# Wait for AMI availability
resource "null_resource" "wait_for_ami" {
  triggers = {
    ami_id = aws_ami_from_instance.devops_ec2_ami.id
  }

  provisioner "local-exec" {
    command = "aws ec2 wait image-available --image-ids ${aws_ami_from_instance.devops_ec2_ami.id} --region ${data.aws_region.current.name}"
  }
}

Key Points:

  • Instance Lookup: The aws_instance data source retrieves the instance ID of devops-ec2using its Name tag.

  • AMI Creation: aws_ami_from_instance creates the AMI with the specified name directly from the instance.

  • Wait Command: The null_resource runs aws ec2 wait image-available after AMI creation, ensuring Terraform pauses until the AMI is ready. This uses the AWS CLI's built-in wait mechanism.

  • Region Handling: The —region parameter in the wait command dynamically uses the instance's availability zone region for compatibility.

Initialize & Apply:

terraform init
terraform apply
  1. Terraform Will:

    • Fetch the devops-ec2 instance ID.

    • Create the AMI.

    • Halt further execution until the AMI status is avilable (confirmed by the AWS CLI wait command).

  2. Verification:

    • Check the AMI status in the AWS Console under EC2 > AMIs.

    • Confirm the AMI devops-ec2-ami exists and is in the available state.

Clean-up alert guys …do not forgot to delete the resource after every hands on in case you don’t want to pay from your important pocket.

LinkedIn

Twitter(X)

1
Subscribe to my newsletter

Read articles from Kunal Kumar Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Kunal Kumar Singh
Kunal Kumar Singh

I am a DevOps Engineer working in MNC. Where I automate Infrastructure using various DevOps tools and AWS Cloud.