Packer Basics
A beginner's guide to HashiCorp Packer for automated machine image creation
TLDR; Packer automates the creation of machine images across multiple platforms from a single source configuration.
Just like its sibling Terraform, HashiCorp Packer is an infrastructure as code tool that helps automate a crucial part of your infrastructure setup: creating machine images. These images can be deployed across various platforms including AWS AMIs, Azure images, Docker containers, VMware, and more.
Packer is particularly useful because it enables you to build consistent machine images for different environments from a single template, saving time and reducing configuration drift between environments.
Installing Packer#
MacOS#
Use homebrew:
brew tap hashicorp/tap
brew install hashicorp/tap/packer
bashLinux (Debian/Ubuntu)#
wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install packer
bashLinux (RHEL/CentOS/Fedora)#
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum -y install packer
bashWindows#
Download the installer from the official Packer website ↗ and run it, or use Chocolatey:
choco install packer
powershellVerify your installation with:
packer version
bashPacker Components#
Packer uses JSON or HCL files to define the configuration for building images. Here are the key components:
Builders#
Builders create machine images for specific platforms like AWS, Azure, or Docker. Each builder has its own configuration options.
Provisioners#
Provisioners install and configure software within the image after it boots. Examples include shell scripts, Ansible, Chef, or Puppet.
Post-Processors#
Post-processors take the result of a builder or another post-processor and process it further. For example, creating a Vagrant box from a VMware image.
Your First Packer Template#
Let’s create a simple Packer template to build an AWS AMI:
packer {
required_plugins {
amazon = {
version = ">= 1.0.0"
source = "github.com/hashicorp/amazon"
}
}
}
source "amazon-ebs" "ubuntu" {
ami_name = "learn-packer-ubuntu"
instance_type = "t2.micro"
region = "us-west-2"
source_ami_filter {
filters = {
name = "ubuntu/images/*ubuntu-focal-20.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"] # Canonical's AWS account ID
}
ssh_username = "ubuntu"
}
build {
sources = [
"source.amazon-ebs.ubuntu"
]
provisioner "shell" {
script = "scripts/setup.sh"
}
}
hclSave this as aws-ubuntu.pkr.hcl
. You’ll also need a scripts/setup.sh
file:
#!/bin/bash
# Update and upgrade packages
sudo apt-get update
sudo apt-get upgrade -y
# Install some basic tools
sudo apt-get install -y nginx git
bashPacker Commands#
Here are the essential Packer commands:
packer init .
- Initialize Packer configuration, downloading pluginspacker validate .
- Validates your template syntaxpacker fmt .
- Formats your template filespacker build .
- Builds the image according to your templatepacker build -var 'key=value' .
- Builds with variable overrides
Hands-on Exercise: Create a Docker Image#
Let’s create a Docker image with Nginx installed:
- Create a file called
docker-nginx.pkr.hcl
with the following content:
packer {
required_plugins {
docker = {
version = ">= 1.0.0"
source = "github.com/hashicorp/docker"
}
}
}
source "docker" "ubuntu" {
image = "ubuntu:20.04"
commit = true
}
build {
name = "nginx-image"
sources = ["source.docker.ubuntu"]
provisioner "shell" {
inline = [
"apt-get update",
"DEBIAN_FRONTEND=noninteractive apt-get install -y nginx",
"echo 'Hello from Packer' > /var/www/html/index.html"
]
}
post-processor "docker-tag" {
repository = "my-nginx"
tags = ["latest", "1.0"]
}
}
hcl- Initialize Packer to download necessary plugins:
packer init .
bash- Validate your template:
packer validate .
bash- Build the Docker image:
packer build docker-nginx.pkr.hcl
bash- Once complete, you can run your new Docker image:
docker run -d -p 8080:80 my-nginx:latest
bash- Visit http://localhost:8080 ↗ in your browser to see “Hello from Packer”.
Advanced Exercise: Multi-Platform Images#
For a more advanced exercise, try creating a template that builds images for multiple platforms simultaneously. This is ideal for environments that use different cloud providers or need consistent images across development, staging, and production environments.
Here’s a skeleton for a multi-platform template:
packer {
required_plugins {
amazon = {
version = ">= 1.0.0"
source = "github.com/hashicorp/amazon"
}
azure = {
version = ">= 1.0.0"
source = "github.com/hashicorp/azure"
}
}
}
source "amazon-ebs" "web_server" {
# AWS-specific configuration
}
source "azure-arm" "web_server" {
# Azure-specific configuration
}
build {
name = "web-server"
sources = [
"source.amazon-ebs.web_server",
"source.azure-arm.web_server"
]
# Common provisioning steps for both images
provisioner "shell" {
script = "scripts/install_web_server.sh"
}
}
hclPacker and Terraform Together#
Packer and Terraform make a powerful combination:
- Use Packer to create standardized machine images with your applications pre-installed
- Use Terraform to deploy and manage infrastructure using those images
This workflow ensures consistency between environments and speeds up deployments by reducing installation time during instance creation.
Feel free to reach out if you have questions about automating image creation with Packer!