Builders and Platforms
Learn about different Packer builders and how to create images for multiple platforms
TLDR: Packer supports 30+ builders for different platforms. Common ones are AWS EBS, Docker, Google Compute, Azure, and VirtualBox. You can use multiple builders in one template to create the same image for different platforms.
Builders are plugins that know how to create machine images for specific platforms. Each builder handles the platform-specific details of launching instances, connecting to them, and creating images.
Amazon EBS Builder
The amazon-ebs builder creates EBS-backed AMIs:
source "amazon-ebs" "example" {
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-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"]
}
ssh_username = "ubuntu"
# Optional: use specific VPC/subnet
vpc_id = "vpc-12345678"
subnet_id = "subnet-87654321"
# Optional: enable EBS encryption
encrypt_boot = true
kms_key_id = "arn:aws:kms:us-east-1:123456789:key/abc-123"
}
Key options:
source_amiorsource_ami_filter: Base AMI to start frominstance_type: EC2 instance type for buildingssh_username: User for SSH connection (ubuntu, ec2-user, admin)iam_instance_profile: IAM role for the build instancesecurity_group_ids: Security groups for the build instance
Docker Builder
The docker builder creates Docker images:
source "docker" "nginx" {
image = "nginx:alpine"
commit = true
# Optional: export to tar
export_path = "nginx-custom.tar"
}
build {
sources = ["source.docker.nginx"]
provisioner "shell" {
inline = [
"apk add --no-cache curl jq"
]
}
post-processor "docker-tag" {
repository = "mycompany/nginx-custom"
tags = ["1.0.0", "latest"]
}
post-processor "docker-push" {
login = true
login_username = var.docker_username
login_password = var.docker_password
}
}
When to use Docker builder:
- You need complex build steps (compiling, multi-stage provisioning)
- You want to share provisioning logic with VM builds
- You're integrating with existing config management tools
For simple cases, Dockerfiles are usually better.
Google Compute Builder
The googlecompute builder creates GCE images:
source "googlecompute" "example" {
project_id = "my-project"
source_image_family = "ubuntu-2204-lts"
ssh_username = "packer"
zone = "us-central1-a"
image_name = "my-app-{{timestamp}}"
image_family = "my-app"
# Use preemptible instance for cost savings
preemptible = true
# Machine type
machine_type = "n1-standard-1"
}
Authentication: Use service account JSON key or Application Default Credentials.
Azure ARM Builder
The azure-arm builder creates Azure Managed Images:
source "azure-arm" "example" {
# Authentication
client_id = var.azure_client_id
client_secret = var.azure_client_secret
subscription_id = var.azure_subscription_id
tenant_id = var.azure_tenant_id
# Image details
managed_image_name = "my-app-{{timestamp}}"
managed_image_resource_group_name = "packer-images"
# Build configuration
os_type = "Linux"
image_publisher = "Canonical"
image_offer = "0001-com-ubuntu-server-jammy"
image_sku = "22_04-lts"
# VM size
vm_size = "Standard_B2s"
# Location
location = "eastus"
}
DigitalOcean Builder
The digitalocean builder creates Droplet snapshots:
source "digitalocean" "example" {
api_token = var.do_api_token
image = "ubuntu-22-04-x64"
region = "nyc3"
size = "s-1vcpu-1gb"
snapshot_name = "my-app-{{timestamp}}"
ssh_username = "root"
}
VirtualBox Builder
The virtualbox-iso builder creates VirtualBox machines from ISO:
source "virtualbox-iso" "example" {
guest_os_type = "Ubuntu_64"
iso_url = "https://releases.ubuntu.com/22.04/ubuntu-22.04-live-server-amd64.iso"
iso_checksum = "sha256:84aeaf7823c8c61baa0ae862d0a06b03409394800000b3235854a6b38eb4856f"
ssh_username = "packer"
ssh_password = "packer"
ssh_timeout = "30m"
shutdown_command = "echo 'packer' | sudo -S shutdown -P now"
vboxmanage = [
["modifyvm", "{{.Name}}", "--memory", "2048"],
["modifyvm", "{{.Name}}", "--cpus", "2"]
]
}
Multi-Platform Builds
Build the same image for multiple platforms:
variable "version" {
type = string
}
source "amazon-ebs" "app" {
ami_name = "myapp-${var.version}-{{timestamp}}"
instance_type = "t3.micro"
region = "us-east-1"
source_ami_filter {
filters = {
name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*"
}
most_recent = true
owners = ["099720109477"]
}
ssh_username = "ubuntu"
}
source "googlecompute" "app" {
project_id = "my-project"
source_image_family = "ubuntu-2204-lts"
zone = "us-central1-a"
image_name = "myapp-${var.version}-{{timestamp}}"
ssh_username = "packer"
}
source "digitalocean" "app" {
api_token = var.do_api_token
image = "ubuntu-22-04-x64"
region = "nyc3"
size = "s-1vcpu-1gb"
snapshot_name = "myapp-${var.version}-{{timestamp}}"
ssh_username = "root"
}
build {
# Build all three platforms
sources = [
"source.amazon-ebs.app",
"source.googlecompute.app",
"source.digitalocean.app"
]
# Shared provisioning for all platforms
provisioner "shell" {
inline = [
"sudo apt-get update",
"sudo apt-get install -y nginx"
]
}
# Platform-specific provisioning
provisioner "shell" {
only = ["amazon-ebs.app"]
inline = ["echo 'Running on AWS' > /tmp/platform.txt"]
}
provisioner "shell" {
only = ["googlecompute.app"]
inline = ["echo 'Running on GCP' > /tmp/platform.txt"]
}
}
Run with:
packer build -var="version=1.0.0" template.pkr.hcl
Packer builds all platforms in parallel by default.
Selecting Specific Builders
Build only specific platforms:
# Build only AWS
packer build -only='amazon-ebs.app' template.pkr.hcl
# Build AWS and GCP
packer build -only='amazon-ebs.app,googlecompute.app' template.pkr.hcl
Builder Communication
Builders need to communicate with instances:
SSH (Linux):
- Most builders use SSH
- Packer generates temporary keys
- Default timeout: 5 minutes
WinRM (Windows):
- Windows AMIs use WinRM
- Configure in user data or via source AMI
source "amazon-ebs" "windows" {
ami_name = "windows-{{timestamp}}"
instance_type = "t3.medium"
region = "us-east-1"
source_ami_filter {
filters = {
name = "Windows_Server-2022-English-Full-Base-*"
}
most_recent = true
owners = ["amazon"]
}
communicator = "winrm"
winrm_username = "Administrator"
winrm_use_ssl = true
user_data_file = "bootstrap-winrm.ps1"
}
Best Practices
Use the right builder: EBS for AWS, docker for containers, ISO builders for bare metal.
Start from official images: Use vendor images (Canonical, AWS, etc.) as base images.
Test locally first: Use Docker or VirtualBox builder to test provisioning before cloud builds.
Parallelize builds: Let Packer build multiple platforms simultaneously (default behavior).
Tag images properly: Include version, git commit, build date in image metadata.
Clean up failures: Use packer build -force to replace existing images during development.
What's Next
Now that you understand builders, the next chapter covers provisioners in depth - the tools that customize your images.
Found an issue?