What it is
Packer is an open-source tool for creating identical machine images for multiple platforms from a single source configuration. You use it to automate the creation of AMIs, Docker images, VirtualBox VMs, and more.
Installation
Linux
sudo apt update && sudo apt install packer
# or
sudo yum install packer
# or download from releases and add to PATH
wget https://releases.hashicorp.com/packer/1.10.0/packer_1.10.0_linux_amd64.zip
unzip packer_1.10.0_linux_amd64.zip
sudo mv packer /usr/local/bin/
macOS
brew install packer
# or download from releases and add to PATH
wget https://releases.hashicorp.com/packer/1.10.0/packer_1.10.0_darwin_amd64.zip
unzip packer_1.10.0_darwin_amd64.zip
sudo mv packer /usr/local/bin/
Windows
Download the appropriate ZIP file from the Packer releases page. Extract the packer.exe file and place it in a directory that is included in your system’s PATH environment variable.
Core Concepts
- Builders: Define the platform where the image will be created (e.g.,
amazon-ebs,docker,virtualbox-iso). - Provisioners: Define how the machine image will be configured after the base image is created (e.g., running shell scripts, Ansible playbooks, Chef recipes).
- Post-processors: Define actions to take after the image is built (e.g., uploading to a repository, tagging).
- Templates: JSON or HCL files that define the builders, provisioners, and other settings for your image build.
Commands / Usage
Building Images
Validate a template file
packer validate my-template.json
Checks the syntax and structure of your Packer template for errors.
Build an image from a template file
packer build my-template.json
Executes the build process defined in the specified template.
Build an image with a specific builder
packer build -only=amazon-ebs my-template.json
Builds the image using only the builder named amazon-ebs (if multiple builders are defined in the template).
Build an image with variables
packer build -var 'aws_region=us-east-1' my-template.json
Overrides template variables with the values provided via the -var flag.
Build an image with variables from a file
packer build -var-file=variables.json my-template.json
Loads template variables from a JSON file.
Build an image with parallel builds
packer build -parallel-builds=4 my-template.json
Runs up to 4 builds concurrently if your template defines multiple builders.
Inspecting Images
Inspect a template file
packer inspect my-template.json
Outputs a human-readable representation of the template, including all variables and their defaults.
Plugin Management
Install a plugin
packer init .
Downloads and installs Packer plugins required by the template in the current directory.
Debugging
Debug a build
packer build -debug my-template.json
Runs the build in debug mode, pausing before each step and allowing you to interact with the machine.
Other Commands
Version
packer version
Displays the current Packer version.
Plugins
packer plugins list
Lists installed Packer plugins.
Common Patterns
Building an AMI with user data and tags
# my-aws-ami.json
{
"builders": [
{
"type": "amazon-ebs",
{% raw %}
"ami_name": "my-app-ami-{{timestamp}}",
{% endraw %}
"instance_type": "t2.micro",
"region": "us-west-2",
"source_ami_filter": {
"filters": {
"name": "ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"
},
"owners": ["099720109477"],
"most_recent": true
},
"tags": {
"Name": "My App Server",
"Environment": "Production"
}
}
],
"provisioners": [
{
"type": "shell",
"inline": [
"sudo apt update",
"sudo apt install -y nginx",
"echo 'Hello from Packer!' | sudo tee /var/www/html/index.html"
]
}
]
}
packer build my-aws-ami.json
This builds an Amazon Machine Image (AMI) using the amazon-ebs builder, starting from a specific Ubuntu 20.04 AMI, installing Nginx, and tagging the resulting AMI.
Building a Docker image with a shell script
# my-docker-image.json
{
"builders": [
{
"type": "docker",
"image_build_method": "build",
"tag": "my-docker-repo/my-app:latest"
}
],
"provisioners": [
{
"type": "shell",
"script": "setup.sh"
}
]
}
# setup.sh
#!/bin/bash
apt update
apt install -y curl
echo "Docker image built!" > /app/message.txt
packer build my-docker-image.json
This builds a Docker image, running a setup.sh script within the container to install curl and create a message file.
Using variables for region and instance type
# my-vars.json
{
"aws_region": "eu-central-1",
"instance_type": "t3.small"
}
# my-aws-template.json
{
"variables": {
"aws_region": "us-east-1",
"instance_type": "t2.micro"
},
"builders": [
{
"type": "amazon-ebs",
{% raw %}
"ami_name": "my-app-ami-{{timestamp}}",
{% endraw %}
{% raw %}
"instance_type": "{{user `instance_type`}}",
{% endraw %}
{% raw %}
"region": "{{user `aws_region`}}",
{% endraw %}
"source_ami_filter": {
"filters": {
"name": "ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"
},
"owners": ["099720109477"],
"most_recent": true
}
}
]
}
packer build -var-file=my-vars.json my-aws-template.json
This demonstrates how to use a variables block in the template and override them with a var-file, making your templates more reusable.
Creating multiple AMIs for different regions
# multi-region-template.json
{
"builders": [
{
"type": "amazon-ebs",
{% raw %}
"ami_name": "my-app-ami-{{timestamp}}",
{% endraw %}
"region": "us-east-1",
"source_ami_filter": {
"filters": { "name": "ami-0c55b159cbfafe1f0" },
"owners": ["099720109477"]
}
},
{
"type": "amazon-ebs",
{% raw %}
"ami_name": "my-app-ami-{{timestamp}}",
{% endraw %}
"region": "eu-west-1",
"source_ami_filter": {
"filters": { "name": "ami-0427785475542462e" },
"owners": ["099720109477"]
}
}
]
}
packer build multi-region-template.json
This template defines two builders, each targeting a different AWS region with a specific source AMI, and packer build will create AMIs in both regions.
Gotchas
- State Management: Packer creates temporary resources (like EC2 instances) during the build process. If a build fails mid-way, these resources might be left behind. Packer attempts to clean them up, but manual intervention might be needed in case of severe failures.
- Idempotency of Provisioners: Ensure your provisioners are idempotent. Running the same script multiple times should not cause unintended side effects. Packer does not inherently guarantee idempotency across builds for provisioners.
- Source AMI Updates: If you rely on
most_recent: truefor yoursource_ami_filter, be aware that a build might use a newly released, potentially different, base AMI than a previous build, which could lead to unexpected behavior if your provisioning logic is sensitive to subtle OS changes. - Credentials: Packer relies on the cloud provider’s credentials configured in your environment (e.g.,
~/.aws/credentialsfor AWS, environment variables for Docker). Ensure these are set correctly before running a build. - Builder Specifics: Each builder has its own set of specific configurations and limitations. Always consult the official Packer documentation for the builder you are using (e.g.,
amazon-ebs,docker,googlecompute) for detailed options. {% raw %} - Timestamp Formatting: The
{{timestamp}}variable uses a default format. If you need a specific date/time format in yourami_nameor other output, you can use{{timestamp "format"}}. For example,{{timestamp "2006-01-02T15:04:05Z"}}. {% endraw %}