Packer Cheat Sheet
Quick reference for HashiCorp Packer templates, builders, provisioners, and CLI commands used to build immutable machine images.
Basic Commands
Core Packer CLI workflow.
packer init . # Download required pluginspacker fmt . # Format HCL filespacker validate . # Validate template syntaxpacker build . # Build image(s) defined in templatepacker build -var 'region=us-east-1' . # Pass a variablepacker build -only='amazon-ebs.ubuntu' . # Build a single named source
HCL2 Template
Minimal image build definition using the amazon-ebs builder.
packer { required_plugins { amazon = { version = ">= 1.2.0" source = "github.com/hashicorp/amazon" } }}source "amazon-ebs" "ubuntu" { ami_name = "my-app-{{timestamp}}" instance_type = "t3.micro" region = "us-east-1" source_ami_filter { filters = { name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*" } owners = ["099720109477"] most_recent = true } ssh_username = "ubuntu"}build { sources = ["source.amazon-ebs.ubuntu"] provisioner "shell" { inline = ["sudo apt-get update", "sudo apt-get install -y nginx"] }}
Provisioners
Mechanisms Packer uses to configure the image during build.
- shell- Runs inline commands or a local script on the instance being built
- file- Uploads a local file or directory to the build instance
- ansible- Runs an Ansible playbook against the temporary build instance
- powershell- Runs PowerShell commands, typically for Windows image builds
- post-processor "vagrant"- Packages the finished build output into a Vagrant box
- post-processor "manifest"- Writes build artifact metadata (IDs, timestamps) to a JSON file
Common Builders (Sources)
Plugins that define which platform an image is built for.
- amazon-ebs- Builds an AMI backed by an EBS snapshot on AWS
- googlecompute- Builds a custom image on Google Compute Engine
- azure-arm- Builds a managed image or VM image on Azure
- docker- Builds and commits a Docker image using a running container
- qemu- Builds a QEMU/KVM disk image, useful for local or on-prem virtualization
- virtualbox-iso- Builds a VirtualBox VM image starting from an ISO installer
HCP Packer Registry & Channels
Publishing build metadata to the HCP Packer registry and consuming a channel's latest artifact from Terraform.
packer { required_plugins { amazon = { version = ">= 1.2.0" source = "github.com/hashicorp/amazon" } }}hcp_packer_registry { bucket_name = "base-ubuntu" description = "Golden Ubuntu base image" bucket_labels = { "team" = "platform" }}build { hcp_packer_registry { bucket_name = "base-ubuntu" } sources = ["source.amazon-ebs.ubuntu"]}# In Terraform, resolve the latest AMI published to a channel:# data "hcp_packer_artifact" "ubuntu" {# bucket_name = "base-ubuntu"# channel_name = "production"# platform = "aws"# region = "us-east-1"# }
Variables, Locals & Data Sources
Parameterizing templates and computing derived values before a build starts.
variable "region" { type = string default = "us-east-1"}variable "app_version" { type = string}data "amazon-ami" "ubuntu" { filters = { name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*" } most_recent = true owners = ["099720109477"] region = var.region}local "timestamp" { expression = formatdate("YYYYMMDD-hhmm", timestamp())}source "amazon-ebs" "ubuntu" { ami_name = "myapp-${var.app_version}-${local.timestamp}" source_ami = data.amazon-ami.ubuntu.id instance_type = "t3.micro" region = var.region}# packer build -var 'app_version=1.4.2' .
Parallel Builds Across Multiple Sources
Building AMI, Azure image, and Docker image from the same provisioning steps in one run.
source "amazon-ebs" "ubuntu" { ami_name = "myapp-{{timestamp}}" instance_type = "t3.micro" region = "us-east-1" source_ami_filter { filters = { name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*" } owners = ["099720109477"] most_recent = true } ssh_username = "ubuntu"}source "docker" "ubuntu" { image = "ubuntu:22.04" commit = true}build { sources = [ "source.amazon-ebs.ubuntu", "source.docker.ubuntu", ] provisioner "shell" { inline = ["apt-get update", "apt-get install -y nginx"] } post-processor "docker-tag" { only = ["docker.ubuntu"] repository = "myorg/myapp" tags = ["latest"] }}# packer build -parallel-builds=2 .
Advanced Provisioner Features
Lesser-known provisioner options for hardening and speeding up image builds.
- provisioner "shell" { expect_disconnect = true }- Tolerates a provisioner-triggered reboot (e.g. kernel upgrade) without failing the build
- windows-restart provisioner- Reboots a Windows build instance and waits for WinRM to come back before continuing
- pause_before / max_retries- Per-provisioner retry/backoff controls for flaky bootstrap steps (e.g. package mirrors not yet ready)
- only / except on provisioners- Scopes a provisioner to run for just one named source when a build has multiple builders
- build.ID / build.SSHPrivateKey- Special build variables exposing the ephemeral instance ID and generated SSH key inside provisioner templates
- provisioner "breakpoint"- Halts the build and drops into an interactive debug session on the temporary instance (packer build -debug)
Image Hardening & Cleanup Before Snapshot
Common shell steps to shrink and sanitize an image before it's committed as a golden AMI.
# Run as the final shell provisioner before the build endssudo cloud-init clean --logs # Reset cloud-init so first boot re-runssudo rm -rf /var/lib/apt/lists/* # Drop stale apt cachesudo rm -f /etc/ssh/ssh_host_* # Force regeneration of unique host keyssudo find /var/log -type f -exec truncate -s 0 {} \; # Zero out logs, keep file handleshistory -c && cat /dev/null > ~/.bash_history # Clear shell historysudo dd if=/dev/zero of=/EMPTY bs=1M || true # Zero free space for smaller snapshot deltassudo rm -f /EMPTY
Use `packer build -only` and multiple named `source` blocks to build several platform images (AWS, Azure, Docker) from one shared template and one set of provisioners, keeping configuration DRY across clouds.