1
votes

Im trying to create a Custom AMI for my AWS Deployment with terraform. Its working quite good also its possible to run a bash script. Problem is it's not possible to create the instance temporary and then to terminate the ec2 instance with terraform and all the depending resources. First im building an "aws_instance" than I provide a bash script in my /tmp folder and let this be done via ssh connection in the terraform script. Looking like the following:

Fist the aws_instance is created based on a standard AWS Amazon Machine Image (AMI). This is used to later create an image from it.

resource "aws_instance" "custom_ami_image" {
  tags = { Name = "custom_ami_image" }

  ami             = var.ami_id                               //base custom ami id 
  subnet_id       = var.subnet_id
  vpc_security_group_ids  = [var.security_group_id]
  iam_instance_profile    = "ec2-instance-profile"
  instance_type           = "t2.micro"

  ebs_block_device {
                     //...further configurations
                   }

Now a bash script is provided. The source is the location of the bash script on the local linux box you are executing terraform from. The destination is on the new AWS instance. In the file I install further stuff like python3, oracle drivers and so on...

  provisioner "file" {
    source      = "../bash_file"
    destination = "/tmp/bash_file"
  }

Then I'll change the permissions on the bash script and execute it with a ssh-user:

  provisioner "remote-exec" {
    inline = [
      "chmod +x /tmp/bash_file",
      "sudo /tmp/bash_file",
    ]
  }

No you can login to the ssh-user with the previous created key.

  connection {
    type        = "ssh"
    user        = "ssh-user"
    password    = ""
    private_key = file("${var.key_name}.pem")
    host        = self.private_ip
  }
}

With the aws_ami_from_instance the ami can be modelled with the current created EC2 instance. And now is callable for further deployments, its also possible to share it in to further aws accounts.

resource "aws_ami_from_instance" "custom_ami_image {
  name               = "acustom_ami_image"
  source_instance_id = aws_instance.custom_ami_image.id
}

Its working fine, but what bothers me is the resulting ec2 instance! Its running and its not possible to terminate it with terraform? Does anyone have an idea how I can handle this? Sure, the running costs are manageable, but I don't like creating datagarbage....

1

1 Answers

3
votes

The best way to create AMI images i think is using Packer, also from Hashicorp like Terraform.

What is Packer?

Provision Infrastructure with Packer Packer is HashiCorp's open-source tool for creating machine images from source configuration. You can configure Packer images with an operating system and software for your specific use-case.

Packer creates an temporary instance with temporary keypair, security_group and IAM roles. In the provisioner "shell" are custom inline commands possible. Afterwards you can use this ami with your terraform code.

A sample script could look like this:

packer {
  required_plugins {
    amazon = {
      version = ">= 0.0.2"
      source  = "github.com/hashicorp/amazon"
    }
  }
}

source "amazon-ebs" "linux" {
  # AMI Settings
  ami_name                      = "ami-oracle-python3"
  instance_type                 = "t2.micro"
  source_ami                    = "ami-xxxxxxxx"
  ssh_username                  = "ec2-user"
  associate_public_ip_address   = false
  ami_virtualization_type       = "hvm"
  subnet_id                     = "subnet-xxxxxx" 
  
  launch_block_device_mappings {
    device_name = "/dev/xvda"
    volume_size = 8
    volume_type = "gp2"
    delete_on_termination = true
    encrypted = false
  }

  # Profile Settings
  profile                       = "xxxxxx"
  region                        = "eu-central-1"
}

build {
  sources = [
    "source.amazon-ebs.linux"
  ]
  provisioner "shell" {
    inline = [
        "export no_proxy=localhost"
    ]
  }
}

You can find documentation about packer here.