← Back to hashicorp/packer

How to Deploy & Use hashicorp/packer

# Packer Deployment & Usage Guide

Complete guide for building, configuring, and deploying HashiCorp Packer to create identical machine images across multiple platforms.

## 1. Prerequisites

### Required
- **Go 1.21+** — For building from source (matches `go.mod` requirements)
- **Git** — For cloning and plugin management
- **Make** — For using build automation (standard HashiCorp Makefile expected)

### Optional (Platform-Specific)
- **Docker** — Required for Docker builder workflows
- **AWS CLI** — For Amazon EBS/EC2 builders (configure credentials via `~/.aws/credentials` or env vars)
- **Azure CLI** — For Azure builders
- **GCP SDK** — For Google Cloud builders
- **HCP Account** — For HCP Packer Registry integration (requires service principal or user credentials)

## 2. Installation

### Option A: Install from Source (Development)

```bash
# Clone the repository
git clone https://github.com/hashicorp/packer.git
cd packer

# Build the binary
go build -o packer .

# Or install to $GOPATH/bin
go install .

# Verify installation
./packer version

Option B: Download Release Binary

# Download from HashiCorp releases (replace X.Y.Z with version)
curl -O https://releases.hashicorp.com/packer/X.Y.Z/packer_X.Y.Z_linux_amd64.zip
unzip packer_X.Y.Z_linux_amd64.zip
sudo mv packer /usr/local/bin/

Option C: Homebrew (macOS/Linux)

brew tap hashicorp/tap
brew install hashicorp/tap/packer

Plugin Installation

Packer uses external plugins for platform support. Initialize plugins defined in your config:

packer init .

Or install specific plugins manually (example for AWS):

packer plugins install github.com/hashicorp/amazon

3. Configuration

HCL2 Configuration Structure

Create a main.pkr.hcl file with required blocks:

# Define required plugins with version constraints
packer {
  required_plugins {
    amazon = {
      version = ">= 1.0.0"
      source  = "github.com/hashicorp/amazon"
    }
    docker = {
      version = ">= 1.0.0"
      source  = "github.com/hashicorp/docker"
    }
  }
}

# Input variables (type constraints supported in HCL2)
variable "aws_region" {
  type    = string
  default = "us-east-1"
}

# Local variables for computed values
locals {
  timestamp = regex_replace(timestamp(), "[- TZ:]", "")
}

# Source configuration (previously "builders" in JSON)
source "amazon-ebs" "example" {
  region        = var.aws_region
  source_ami    = "ami-12345678"
  instance_type = "t2.micro"
  ssh_username  = "ubuntu"
  ami_name      = "packer-example-${local.timestamp}"
}

# Build block defining provisioners and post-processors
build {
  sources = ["source.amazon-ebs.example"]
  
  provisioner "shell" {
    inline = ["echo 'Provisioning...'", "sudo apt-get update"]
  }
  
  post-processor "manifest" {
    output = "manifest.json"
  }
}

Environment Variables

VariableDescription
PACKER_LOGSet to 1 for debug logging
PACKER_LOG_PATHPath to log file
PACKER_PLUGIN_PATHCustom directory for plugins
PACKER_CONFIG_DIRPacker configuration directory (default: ~/.config/packer/)
HCP_CLIENT_IDHCP service principal ID (for registry)
HCP_CLIENT_SECRETHCP service principal secret

HCP Packer Registry Configuration

To publish artifacts to HCP Packer, add to your build block:

build {
  hcp_packer_registry {
    bucket_name = "my-application"
    description = "Machine image for web servers"
    
    bucket_labels = {
      "os" = "ubuntu-20.04"
    }
    
    build_labels = {
      "build-time" = timestamp()
    }
  }
  
  sources = ["source.amazon-ebs.example"]
}

Authenticate via:

export HCP_CLIENT_ID="your-client-id"
export HCP_CLIENT_SECRET="your-client-secret"

Migrating from JSON

If upgrading legacy JSON templates:

packer hcl2_upgrade my-template.json

This generates my-template.json.pkr.hcl. Note: Avoid mixing Go templating ({{ }}) with HCL2 expressions (${ }) as they execute at different phases.

4. Build & Run

Development Workflow

# Format HCL files
packer fmt .

# Validate configuration
packer validate .

# Build with debug mode (keeps resources on failure for inspection)
packer build -debug .

# Build with specific variable overrides
packer build -var="aws_region=us-west-2" .

# Build with variable file
packer build -var-file="variables.pkrvars.hcl" .

Local Development Build

# Run directly from source without installing
go run . build .

# Run with race detector (development only)
go run -race . build .

Core Execution Options

When using Packer as a library (from packer/core.go):

import "github.com/hashicorp/packer/packer"

config := &packer.CoreConfig{
    Template:   tpl,           // *template.Template
    Variables:  map[string]string{"aws_region": "us-east-1"},
    Version:    "1.9.0",
}

core, err := packer.NewCore(config)
if err != nil {
    log.Fatal(err)
}

Debugging Builds

Enable detailed logging:

PACKER_LOG=1 PACKER_LOG_PATH=packer.log packer build .

5. Deployment

CI/CD Integration

GitHub Actions Example:

name: Build Image
on: [push]
jobs:
  packer:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Packer
        uses: hashicorp/setup-packer@main
        with:
          version: "latest"
      - name: Init plugins
        run: packer init .
      - name: Validate
        run: packer validate .
      - name: Build
        run: packer build .
        env:
          HCP_CLIENT_ID: ${{ secrets.HCP_CLIENT_ID }}
          HCP_CLIENT_SECRET: ${{ secrets.HCP_CLIENT_SECRET }}

GitLab CI Example:

build:
  image: hashicorp/packer:latest
  script:
    - packer init .
    - packer build .
  variables:
    PACKER_LOG: "1"

Docker Usage

Run Packer in Docker without local installation:

docker run --rm -v $(pwd):/workspace -w /workspace \
  -e AWS_ACCESS_KEY_ID \
  -e AWS_SECRET_ACCESS_KEY \
  hashicorp/packer:latest build .

HCP Packer Registry Publishing

Images are automatically published to HCP when hcp_packer_registry block is configured. The registry tracks:

  • Buckets: Logical groupings of images (e.g., "web-server", "database")
  • Versions: Individual builds with metadata
  • Channels: Mutable pointers to specific versions (e.g., "latest", "production")

Heartbeat signals are sent every 2 minutes during builds to indicate active status.

Plugin Distribution

For air-gapped environments, pre-download plugins:

# Download plugins to local directory
packer plugins install --path ./plugins github.com/hashicorp/amazon

# Archive for transfer
tar -czf packer-plugins.tar.gz ./plugins

# On target system, extract and set plugin path
export PACKER_PLUGIN_PATH=/path/to/plugins
packer build .

6. Troubleshooting

Plugin Version Compatibility

Error: incompatible API version or protocol version mismatch

Solution: Check plugin SDK compatibility. From BinaryInstallationOptions, verify:

  • APIVersionMajor and APIVersionMinor match between Packer core and plugin
  • Update plugin to version supporting your Packer version:
    packer plugins install github.com/hashicorp/amazon@latest
    

HCL2 Syntax Errors

Error: Unsupported block type or Argument or block definition required

Solution:

  • Run packer fmt . to fix formatting
  • Ensure file suffix is .pkr.hcl (not .hcl alone)
  • Check that variable references use var.name not {{user \name`}}` (JSON syntax)

HCP Authentication Failures

Error: unable to authenticate with HCP or 401 Unauthorized

Solution:

  • Verify HCP_CLIENT_ID and HCP_CLIENT_SECRET are exported (not HCP_API_KEY)
  • Check service principal has contributor role on HCP Packer registry
  • For organization-level buckets, ensure proper resource naming conventions

Build Failures with Source Images

Error: Source image not found or Invalid AMI

Solution:

  • Verify source AMI exists in specified region
  • Check IAM permissions for ec2:DescribeImages (AWS) or equivalent
  • Use most_recent filter in source block:
    source_ami_filter {
      filters = {
        name                = "ubuntu/images/*ubuntu-focal-20.04-amd64-server-*"
        virtualization-type = "hvm"
      }
      owners      = ["099720109477"] # Canonical
      most_recent = true
    }
    

Plugin Installation Issues

Error: Failed to install plugin or checksum validation failures

Solution:

  • Clear plugin cache: rm -rf ~/.config/packer/plugins
  • Check network access to releases.hashicorp.com
  • For custom plugins, verify packer plugins install path includes protocol version subdirectory

HCL2 Upgrade Issues

Error: mixed go templating and HCL2 calls after upgrade

Solution:

  • Review generated .pkr.hcl file
  • Replace Go template syntax {{ timestamp }} with HCL2 timestamp()
  • Move complex logic to locals blocks rather than inline in builder definitions

Debugging Plugin Crashes

Enable plugin-specific logging:

PACKER_LOG=1 PACKER_LOG_PATH=packer.log packer build -debug .

Check logs for panic in plugin subprocesses. Plugin logs appear in /tmp/packer-plugin-* during execution when PACKER_LOG=1 is set.