Eliminate Image Drift with Packer HCL2 Multi-Builds
Learn how Packer's HCL2 Multi‑Build feature lets you define one set of provisioners and create identical AWS AMIs and Azure Images in a single run, eliminating image drift.
20 Jun 2026, 21:18 UTC

The Problem: Configuration Drift Across Clouds
When managing infrastructure across multiple cloud providers, a common failure point is \"image drift.\" This happens when the AWS AMI, the Azure Managed Image, and the GCP Image—all intended to be identical clones of a gold master—slowly diverge because they are managed by separate build scripts. Updating a security patch in one template but forgetting it in another leads to inconsistent environments and unpredictable deployment failures.
Why HCL2 and Multi‑Builds Help
Packer moved from JSON to HCL2 (HashiCorp Configuration Language), which adds variables, locals, and complex data structures. With a single HCL2 file you can declare several source blocks and reference them in one build block. Packer then launches those sources in parallel, runs the same provisioners inside each temporary VM, and captures the resulting images. Because the provisioner code lives in one place, the installed software is identical across clouds, eliminating drift.
Worked Example: Web Server on AWS and Azure
The following HCL2 snippet defines an Amazon EBS source and an Azure ARM source, then uses a shared shell provisioner to install Nginx. Save the file as build.pkr.hcl.
variable \"web_version\" {\n type = string\n default = \"latest\"\n}\nsource \"amazon-ebs\" \"web_aws\" {\n ami_name = \"web-server-{{timestamp}}\"\n instance_type = \"t3.micro\"\n region = \"us-east-1\"\n source_ami = \"ami-0c55159cbfe1f0\" # Example Amazon Linux 2\n ssh_username = \"ec2-user\"\n}\nsource \"azure-arm\" \"web_azure\" {\n publisher = \"Canonical\"\n offer = \"UbuntuServer\"\n sku = \"18.04-LTS\"\n location = \"East US\"\n vm_size = \"Standard_B1s\"\n}\nbuild {\n sources = [\n \"source.amazon-ebs.web_aws\",\n \"source.azure-arm.web_azure\"\n ]\n provisioner \"shell\" {\n inline = [\n \"echo 'Installing web server version ${var.web_version}...'\",\n \"sudo apt-get update || sudo yum update -y\",\n \"sudo apt-get install -y nginx || sudo yum install -y nginx\"\n ]\n }\n}\nRunning the Build
First validate the syntax, then execute the multi‑build. Ensure your AWS and Azure credentials are exported as environment variables.
packer validate build.pkr.hcl\npacker build build.pkr.hclPacker will show two concurrent streams of output as it provisions the AWS and Azure instances. When finished, you will see an AMI in the AWS EC2 console and a Managed Image in the Azure Portal, both containing Nginx installed by the same shell script.
Trade‑offs and Practical Checks
Multi‑builds run builders in parallel by default, which can strain the host machine’s CPU, memory, and network if many clouds are targeted simultaneously. Monitor your CI runner’s resource usage or limit parallelism with the -parallelism flag. Also remember that provisioners execute inside the VM; the Packer host must be able to reach each temporary instance over SSH or WinRM. If network connectivity fails, the build will stall.
To verify that drift has not occurred, compare the installed package versions in each image. For example, log into each image and run nginx -v; the version string should match.
Closing
By consolidating source definitions and provisioner logic in a single HCL2 file, Packer Multi‑Builds give you a single source of truth for golden images across clouds. The approach removes drift at the cost of higher concurrent resource demand, which can be managed with parallelism limits and proper host sizing.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.