BuggyCodeMaster

Back

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
bash

Linux (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
bash

Linux (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
bash

Windows#

Download the installer from the official Packer website and run it, or use Chocolatey:

choco install packer
powershell

Verify your installation with:

packer version
bash

Packer 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"
  }
}
hcl

Save 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
bash

Packer Commands#

Here are the essential Packer commands:

  • packer init . - Initialize Packer configuration, downloading plugins
  • packer validate . - Validates your template syntax
  • packer fmt . - Formats your template files
  • packer build . - Builds the image according to your template
  • packer build -var 'key=value' . - Builds with variable overrides

Hands-on Exercise: Create a Docker Image#

Let’s create a Docker image with Nginx installed:

  1. 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
  1. Initialize Packer to download necessary plugins:
packer init .
bash
  1. Validate your template:
packer validate .
bash
  1. Build the Docker image:
packer build docker-nginx.pkr.hcl
bash
  1. Once complete, you can run your new Docker image:
docker run -d -p 8080:80 my-nginx:latest
bash
  1. 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"
  }
}
hcl

Packer 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!

Packer Basics
https://sanjaybalaji.dev/blog/packer-basics
Author Sanjay Balaji
Published at March 12, 2025