Automating AWS AMI Creation with Packer HCL2 and amazon-ebs
Learn how to use Packer HCL2 and the amazon-ebs builder to automate the creation of consistent, reproducible Amazon Machine Images (AMIs) and eliminate configuration drift.
09 Sept 2026, 04:36 UTC

The Challenge: Eliminating Manual Image Drift
Manual snapshots of production servers lead to "snowflake" images—configurations that cannot be reproduced or audited. To ensure consistency across scaling groups, you need a repeatable pipeline that boots a clean base image, installs dependencies, and registers a new Amazon Machine Image (AMI) automatically.
The Takeaway: By using the amazon-ebs builder in HashiCorp Packer HCL2, you can define your image as code, ensuring every instance in your fleet starts from an identical, verified baseline.
Prerequisites
- Packer Installed: Version 1.7.0 or later (to ensure full HCL2 support).
- AWS Credentials: An IAM user or role with permissions for
ec2:RunInstances,ec2:CreateSnapshot,ec2:RegisterImage, andec2:TerminateInstances. - Network Access: A VPC with a public subnet and a Security Group that allows SSH (port 22) from your build machine's IP.
Defining the Build Configuration
Packer HCL2 separates the source (the base image and hardware) from the build (the software installation). Create a file named build.pkr.hcl.
The Source Block
The source block defines the starting point. Avoid hardcoding the AMI ID; instead, use a variable to allow for easy updates when the base OS provider releases a new patch.
variable "ami_id" {
type = string
default = "ami-0c55b159cbfafe1f0" # Example Amazon Linux 2 AMI
}
source "amazon-ebs" "ubuntu_base" {
ami_name = "web-server-{{timestamp}}"
instance_type = "t3.micro"
region = "us-east-1"
source_ami = var.ami_id
ssh_username = "ubuntu"
}
The Build Block
The build block executes the provisioners. The shell provisioner is the most common method for installing packages via a remote SSH connection.
build {
sources = ["source.amazon-ebs.ubuntu_base"]
provisioner "shell" {
inline = [
"sudo apt-get update",
"sudo apt-get install -y nginx",
"sudo systemctl enable nginx"
]
}
}
Execution and Verification
Run these commands from your local terminal where the .pkr.hcl file is located.
1. Syntax Validation
Before launching AWS resources, check for logic errors or missing variables.
# Run in local terminal
packer validate .
2. Triggering the Build
The build command will launch a temporary EC2 instance, run the scripts, stop the instance, and create the AMI.
# Run in local terminal
packer build .
Risk: If the Security Group does not allow SSH access to the temporary instance, Packer will hang and eventually timeout. Ensure your security_group_id is correctly assigned in the source block if you are not using the default group.
3. Result Verification
Once the build completes, Packer outputs the new AMI ID. Verify the image by launching a test instance:
- Log into the AWS Management Console > EC2 > AMIs.
- Confirm the image name matches the
ami_namepattern. - Launch an instance from this AMI and run
systemctl status nginxto confirm the provisioner succeeded.
Comparison: Shell Provisioner vs. External Scripts
| Method | Best Use Case | Pros | Cons |
|---|---|---|---|
inline |
Small updates, single commands | Fast, visible in code | Hard to maintain for complex setups |
scripts |
Complex installations, bash scripts | Versionable scripts, cleaner HCL | Requires managing external files |
Rollback and Cleanup
Because Packer creates a new AMI rather than modifying an existing one, there is no "rollback" of the image itself. If a build fails:
- Deregister AMI: If a partial AMI was created, deregister it via the AWS Console or CLI to avoid clutter.
- Delete Snapshot: Delete the associated EBS snapshot to avoid storage costs.
- Terminate Orphaned Instances: If Packer crashes before it can clean up, manually terminate the temporary build instance in the EC2 dashboard.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.