Operations

Utilizing Packer Images

Packer is a HashiCorp product for creating machine images from a single source configuration. They can be highly useful when provisioning instances in Terraform. Let's take a look at how Packer works and how to integrate Packer generated images into a Terraform configuration.

» Getting Started with Packer

Installing the Packer binary is similar to the Terraform installation. Navigate to the appropriate precompiled binary and unzip. Be sure to add the location to your PATH. Verify the installation by opening a command prompt and checking packer --version. If you get an error that packer could not be found, then your PATH environment variable was not setup properly. Please go back and ensure that your PATH variable contains the directory which has Packer installed.

» Building an Image

Packer can be used to create images for many platforms. We will create an Amazon EC2 AMI as an example.

Packer uses a JSON template. We can create a file called example.json and populate it:

{
  "variables": {
    "aws_access_key": "",
    "aws_secret_key": ""
  },
  "builders": [
    {
      "type": "amazon-ebs",
      "access_key": "{{user `aws_access_key`}}",
      "secret_key": "{{user `aws_secret_key`}}",
      "region": "us-east-1",
      "source_ami_filter": {
        "filters": {
          "virtualization-type": "hvm",
          "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*",
          "root-device-type": "ebs"
        },
        "owners": ["099720109477"],
        "most_recent": true
      },
      "instance_type": "t2.micro",
      "ssh_username": "ubuntu",
      "ami_name": "packer-vault-example {{timestamp}}"
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "inline": [
        "git clone --branch master https://github.com/hashicorp/terraform-aws-vault.git /tmp/terraform-aws-vault",
        "/tmp/terraform-aws-vault/modules/install-vault/install-vault --version 0.10.4"
      ],
      "pause_before": "30s"
    }
  ]
}

» User Variables

To start with, we create a variable block for our user variables. When built, this template will prompt to input user credentials, but you can also use environment variables or a variable file as detailed here.

» Builders

The next portion of this template is a builder block. A builder is a component of Packer that is responsible for creating a machine and turning that machine into an image. This builder creates an EBS-backed AMI by launching a source AMI and re-packaging it into a new AMI after provisioning. For more information about the various types of builders available see the Packer documentation.

» Provisioners

The final block included here is a provisioner block. Much like provisioner blocks in Terraform, provisioners allow quick deployment of software by pre-baking them into the desired image. This particular provisioner is a shell provisioner that clones a repo on an AWS instance to install HashiCorp Vault, but provisioners have several other uses as well. Find out more about the different types of provisioners in the Packer documentation.

» Validating and Building

We can verify that this template is valid by running packer validate example.json.

$ packer validate example.json
Template validated successfully.

Once we have validated the template, we can build our first image. Truncated output detailed below.

$ packer build \
    -var 'aws_access_key=YOUR ACCESS KEY' \
    -var 'aws_secret_key=YOUR SECRET KEY' \
    example.json
==> amazon-ebs: amazon-ebs output will be in this color.

==> amazon-ebs: Creating temporary keypair for this instance...
==> amazon-ebs: Creating temporary security group for this instance...
==> amazon-ebs: Authorizing SSH access on the temporary security group...
==> amazon-ebs: Launching a source AWS instance...
==> amazon-ebs: Waiting for instance to become ready...
==> amazon-ebs: Connecting to the instance via SSH...
==> amazon-ebs: Stopping the source instance...
==> amazon-ebs: Provisioning with shell script: /var/folders/_y/z5xr5v9s6n13g_ln086zwwx80000gn/T/packer-shell881370355...
==> amazon-ebs: Waiting for the instance to stop...
==> amazon-ebs: Creating the AMI: packer-example 1371856345
==> amazon-ebs: AMI: ami-19601070
==> amazon-ebs: Waiting for AMI to become ready...
==> amazon-ebs: Terminating the source AWS instance...
==> amazon-ebs: Deleting temporary security group...
==> amazon-ebs: Deleting temporary keypair...
==> amazon-ebs: Build finished.

==> Builds finished. The artifacts of successful builds are:
--> amazon-ebs: AMIs were created:

us-east-1: ami-19601070

The return value of us-east-1: ami-19601070 is called an artifact. Artifacts are the results of the build. We've successfully built a Packer image! Now let's see what Terraform can do with it.

» Deploying a Packer Image with Terraform

Now that we have an AMI ID, we can start deploying instances with Terraform. Specifying the AMI we were given from the Packer build is all we need to deploy this image to our environment.

provider "aws" {
  access_key = "ACCESS_KEY_HERE"
  secret_key = "SECRET_KEY_HERE"
  region     = "us-east-1"
}

resource "aws_instance" "vault-example" {
  ami           = "ami-19601070"
  instance_type = "t2.micro"
  keypair_name = "KEYNAME"
}