Build Immutable Images with Packer
Define a Packer template that bakes a hardened base image, validate and build it in CI, and version the resulting image so instances boot identically.
Task
Create a reproducible, hardened machine image build pipeline with Packer.
When to use this
Servers are configured by hand or by a long script at boot, so identical instances are hard to reproduce and drift accumulates.
Prerequisites
- Packer installed
- Cloud credentials for the target platform
- A provisioning tool such as Ansible
Steps
1. Write a template with a source image and provisioners that harden and install.
Expected output: The image is fully specified in code.
2. Validate the template and build it in CI on every change.
Expected output: Bugs surface before an image is published.
3. Automate a smoke test that boots the image and checks key services.
Expected output: The image is proven to work.
4. Version and publish the image, and reference the version from IaC.
packer validate template.pkr.hcl && packer build template.pkr.hclExpected output: Instances are immutable and reproducible.
Troubleshooting
Problem
Build is not reproducible
Solution
Pin the base source image and provisioner versions; unpinned sources change underfoot.
Problem
Credentials in the image
Solution
Never bake secrets; inject them at runtime from a secret manager.
Limitations
- Baking images trades rebuild time for boot speed and requires a pipeline to keep images current with patches.
- Immutable images still need a patching cadence; without rebuilds they age and accumulate vulnerabilities.
Context
Create a reproducible, hardened machine image build pipeline with Packer. Servers are configured by hand or by a long script at boot, so identical instances are hard to reproduce and drift accumulates.
Steps
- Write a template with a source image and provisioners that harden and install. Expected: The image is fully specified in code.
- Validate the template and build it in CI on every change. Expected: Bugs surface before an image is published.
- Automate a smoke test that boots the image and checks key services. Expected: The image is proven to work.
- Version and publish the image, and reference the version from IaC. Expected: Instances are immutable and reproducible.
source "amazon-ebs" "base" {
ami_name = "app-base-{{timestamp}}"
source_ami = var.base_ami
instance_type = "t3.micro"
}
build {
sources = ["source.amazon-ebs.base"]
provisioner "ansible" { playbook_file = "hardening.yml" }
}
Verify
- The image is fully specified in code.
- Bugs surface before an image is published.
- The image is proven to work.
- Instances are immutable and reproducible.
Limits
- Baking images trades rebuild time for boot speed and requires a pipeline to keep images current with patches.
- Immutable images still need a patching cadence; without rebuilds they age and accumulate vulnerabilities.