Build an image
With Packer installed, it is time to build your first image. In this tutorial, you will build a t2.micro
Amazon EC2 AMI.
Note
This tutorial will provision resources that qualify under the AWS free-tier. If your account doesn't qualify under the AWS free-tier, we're not responsible for any charges that you may incur.
Write Packer template
A Packer template is a configuration file that defines the image you want to build and how to build it. Packer templates use the Hashicorp Configuration Language (HCL).
Create a new directory named packer_tutorial
. This directory will contain your Packer template for this tutorial.
$ mkdir packer_tutorial
Navigate into the directory.
$ cd packer_tutorial
Create a file aws-ubuntu.pkr.hcl
, add the following HCL block to it, and save the file.
packer { required_plugins { amazon = { version = ">= 1.2.8" source = "github.com/hashicorp/amazon" } }} source "amazon-ebs" "ubuntu" { ami_name = "learn-packer-linux-aws" instance_type = "t2.micro" region = "us-west-2" source_ami_filter { filters = { name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*" root-device-type = "ebs" virtualization-type = "hvm" } most_recent = true owners = ["099720109477"] } ssh_username = "ubuntu"} build { name = "learn-packer" sources = [ "source.amazon-ebs.ubuntu" ]}
This is a complete Packer template that you will use to build an AWS Ubuntu AMI in the us-west-2
region. In the following sections, you will review each block of this template in more detail.
Packer Block
The packer {}
block contains Packer settings, including specifying a required Packer version.
In addition, you will find required_plugins
block in the Packer block, which specifies all the plugins required by the template to build your image. Even though Packer is packaged into a single binary, it depends on plugins for much of its functionality. Some of these plugins, like the Amazon AMI Builder (AMI builder) which you will to use, are built, maintained, and distributed by HashiCorp — but anyone can write and use plugins.
Each plugin block contains a version and source
attribute. Packer will use these attributes to download the appropriate plugin(s).
- The
source
attribute is only necessary when requiring a plugin outside the HashiCorp domain. You can find the full list of HashiCorp and community maintained builders plugins in the Packer Builders documentation page. - The version attribute is optional, but we recommend using it to constrain the plugin version so that Packer does not install a version of the plugin that does not work with your template. If you do not specify a plugin version, Packer will automatically download the most recent version during initialization.
In the example template above, Packer will use the Packer Amazon AMI builder plugin that is greater than or equal to version 1.2.8
.
Source block
The source
block configures a specific builder plugin, which is then invoked by a build
block. Source blocks use builders and communicators to define what kind of virtualization to use, how to launch the image you want to provision, and how to connect to it. Builders and communicators are bundled together and configured side-by-side in a source block. A source
can be reused across multiple builds, and you can use multiple source
s in a single build. A builder plugin is a component of Packer that is responsible for creating a machine and turning that machine into an image.
A source block has two important labels: a builder type and a name. These two labels together will allow us to uniquely reference sources later on when we define build runs.
In the example template, the builder type is amazon-ebs
and the name is ubuntu
.
source "amazon-ebs" "ubuntu" { ami_name = "learn-packer-linux-aws" instance_type = "t2.micro" region = "us-west-2" source_ami_filter { filters = { name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*" root-device-type = "ebs" virtualization-type = "hvm" } most_recent = true owners = ["099720109477"] } ssh_username = "ubuntu"}
Each builder has its own unique set of configuration attributes. The amazon-ebs
builder launches the source AMI, runs provisioners within this instance, then repackages it into an EBS-backed AMI.
In the example template, the amazon-ebs
builder configuration launches a t2.micro
AMI in the us-west-2
region using an ubuntu-jammy
AMI as the base image, then creates an image named learn-packer-linux-aws
from that instance. The builder will create all the temporary resources necessary (for example, keypairs, security group rules, etc..) to temporarily access the instance while the image is being created.
This example template also uses the SSH communicator. By specifying the ssh_username
attribute, Packer is able to SSH into EC2 instance using a temporary keypair and security group to provision your instances. The next tutorial walks you through modify your AMI using provisioners.
The Build Block
The build
block defines what Packer should do with the EC2 instance after it launches.
In the example template, the build block references the AMI defined by the source block above (source.amazon-ebs.ubuntu
).
build { sources = [ "source.amazon-ebs.ubuntu" ]}
Tip
In later tutorials, you will add the provision
block (define additional provisioning steps) and post-process
block (define what do to with the build artifacts) to the build block.
Authenticate to AWS
Before you can build the AMI, you need to provide your AWS credentials to
Packer. These credentials have permissions to create, modify and delete EC2
instances. Refer to the
documentation
to find the full list IAM permissions required to run the amazon-ebs
builder.
To allow Packer to access your IAM user credentials, set your AWS access key ID as an environment variable.
$ export AWS_ACCESS_KEY_ID="<YOUR_AWS_ACCESS_KEY_ID>"
Now set your secret key.
$ export AWS_SECRET_ACCESS_KEY="<YOUR_AWS_SECRET_ACCESS_KEY>"
Tip
If you don't have access to IAM user credentials, use another authentication method described in the Packer documentation.
Initialize Packer configuration
Initialize your Packer configuration.
$ packer init .
Packer will download the plugin you've defined above. In this case, Packer will download the Packer Amazon plugin that is greater than or equal to version 1.2.8
.
You can run packer init
as many times as you'd like. If you already have the plugins you need, Packer will exit without an output.
Packer has now downloaded and installed the Amazon plugin. It is ready to build the AMI!
Format and validate your Packer template
We recommend using consistent formatting in all of your template files. The packer fmt
command updates templates in the current directory for readability and consistency.
Format your template. Packer will print out the names of the files it modified, if any. In this case, your template file was already formatted correctly, so Packer won't return any file names.
$ packer fmt .
You can also make sure your configuration is syntactically valid and internally consistent by using the packer validate
command.
Validate your template. If Packer detects any invalid configuration, Packer will print out the file name, the error type and line number of the invalid configuration. The example configuration provided above is valid, so Packer will return nothing.
$ packer validate .
Build Packer image
Build the image with the packer build
command. Packer will print output similar to what is shown below.
$ packer build aws-ubuntu.pkr.hcllearn-packer.amazon-ebs.ubuntu: output will be in this color. ==> learn-packer.amazon-ebs.ubuntu: Prevalidating any provided VPC information==> learn-packer.amazon-ebs.ubuntu: Prevalidating AMI Name: learn-packer-linux-aws learn-packer.amazon-ebs.ubuntu: Found Image ID: ami-0dd273d94ed0540c0==> learn-packer.amazon-ebs.ubuntu: Creating temporary keypair: packer_608a6435-e0b2-c633-95f0-bf168f01e891==> learn-packer.amazon-ebs.ubuntu: Creating temporary security group for this instance: packer_608a6437-6b48-288e-6d5e-c085366a5541==> learn-packer.amazon-ebs.ubuntu: Authorizing access to port 22 from [0.0.0.0/0] in the temporary security groups...==> learn-packer.amazon-ebs.ubuntu: Launching a source AWS instance...==> learn-packer.amazon-ebs.ubuntu: Adding tags to source instance learn-packer.amazon-ebs.ubuntu: Adding tag: "Name": "Packer Builder" learn-packer.amazon-ebs.ubuntu: Instance ID: i-023d696a318e9594c==> learn-packer.amazon-ebs.ubuntu: Waiting for instance (i-023d696a318e9594c) to become ready...==> learn-packer.amazon-ebs.ubuntu: Using ssh communicator to connect: 35.166.142.55==> learn-packer.amazon-ebs.ubuntu: Waiting for SSH to become available...==> learn-packer.amazon-ebs.ubuntu: Connected to SSH!==> learn-packer.amazon-ebs.ubuntu: Stopping the source instance... learn-packer.amazon-ebs.ubuntu: Stopping instance==> learn-packer.amazon-ebs.ubuntu: Waiting for the instance to stop...==> learn-packer.amazon-ebs.ubuntu: Creating AMI learn-packer-linux-aws from instance i-023d696a318e9594c learn-packer.amazon-ebs.ubuntu: AMI: ami-0703a21445140541e==> learn-packer.amazon-ebs.ubuntu: Waiting for AMI to become ready...==> learn-packer.amazon-ebs.ubuntu: Terminating the source AWS instance...==> learn-packer.amazon-ebs.ubuntu: Cleaning up any extra volumes...==> learn-packer.amazon-ebs.ubuntu: No volumes to clean up, skipping==> learn-packer.amazon-ebs.ubuntu: Deleting temporary security group...==> learn-packer.amazon-ebs.ubuntu: Deleting temporary keypair...Build 'learn-packer.amazon-ebs.ubuntu' finished after 3 minutes 5 seconds. ==> Wait completed after 3 minutes 5 seconds ==> Builds finished. The artifacts of successful builds are:--> learn-packer.amazon-ebs.ubuntu: AMIs were created:us-west-2: ami-0703a21445140541e
Visit the AWS AMI page to verify that Packer successfully built your AMI.
Congratulations — you built your first image using Packer!
Managing the Image
Packer only builds images. It does not attempt to manage them in any way. After they're built, it is up to you to launch or destroy them as you see fit.
After running the above example, your AWS account now has an AMI associated with it. AMIs are stored in S3 by Amazon so you may be charged.
You can remove the AMI by first deregistering it on the AWS AMI management page. Next, delete the associated snapshot on the AWS snapshot management page.
Next steps
In this tutorial, you launched an EC2 instance and used it to create an AMI. Although you essentially repackaged an existing AMI, you should now have a general idea of how Packer works, what templates are and how to validate and build templates into machine images. Now that you have created your first Packer image, continue to the next tutorial to install and configure software into your image with provisioners.
Refer to the following resources for additional details on the concepts covered in this tutorial:
- Read more about the Packer Amazon AMI builder plugin.
- Learn more about the
packer init
andpacker build
commands. - For more information about Packer-specific HCL blocks, refer to the Packer HCL documentation page.