Packer
Machine image builder - create reproducible VM templates for Proxmox and cloud providers.
Packer Basics
packer init .
packer validate .
packer fmt .
packer build .
packer build -var "iso_url=https://mirror.example.com/rocky-9.iso" .
packer build -var-file=prod.pkrvars.hcl .
packer build -only=proxmox-iso.rocky9 .
PACKER_LOG=1 packer build -debug .
MUSCLE MEMORY: packer fmt . && packer validate . && packer build .
Proxmox Builder
packer {
required_plugins {
proxmox = {
version = ">= 1.1.0"
source = "github.com/hashicorp/proxmox"
}
}
}
source "proxmox-iso" "rocky9" {
proxmox_url = var.proxmox_url
username = var.proxmox_username
token = var.proxmox_token
node = "pve"
insecure_skip_tls_verify = true
vm_id = 9000
vm_name = "rocky9-template"
template_description = "Rocky 9 template - built {{ timestamp }}"
iso_file = "local:iso/Rocky-9-latest-x86_64-minimal.iso"
unmount_iso = true
qemu_agent = true
os = "l26"
memory = 2048
cores = 2
cpu_type = "host"
sockets = 1
scsi_controller = "virtio-scsi-pci"
disks {
type = "scsi"
disk_size = "32G"
storage_pool = "local-lvm"
format = "raw"
}
network_adapters {
model = "virtio"
bridge = "vmbr0"
}
cloud_init = true
cloud_init_storage_pool = "local-lvm"
boot_command = [
"<up><wait>",
"e<wait>",
"<down><down><end>",
" inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg",
"<F10>"
]
http_directory = "http"
ssh_username = "root"
ssh_password = var.ssh_password
ssh_timeout = "20m"
}
build {
sources = ["source.proxmox-iso.rocky9"]
provisioner "shell" {
inline = [
"dnf update -y",
"dnf install -y qemu-guest-agent cloud-init",
"systemctl enable qemu-guest-agent",
"cloud-init clean",
]
}
provisioner "ansible" {
playbook_file = "./ansible/harden.yml"
}
provisioner "shell" {
inline = [
"truncate -s 0 /etc/machine-id",
"rm -f /var/lib/dbus/machine-id",
"cloud-init clean --logs --seed",
]
}
}
PATTERN: Template pipeline: ISO → Packer → Proxmox template → Terraform clones.
Variables
# variables.pkr.hcl
variable "proxmox_url" {
type = string
description = "Proxmox API URL"
}
variable "proxmox_username" {
type = string
description = "Proxmox API token ID"
}
variable "proxmox_token" {
type = string
sensitive = true
}
variable "ssh_password" {
type = string
sensitive = true
default = ""
}
# prod.pkrvars.hcl
proxmox_url = "https://pve.inside.domusdigitalis.dev:8006/api2/json"
proxmox_username = "packer@pve!packer-token"
export PKR_VAR_proxmox_token="secret-token-value"
export PKR_VAR_ssh_password="build-password"
packer build .
SECURITY: Sensitive variables never appear in logs. Use sensitive = true and env vars.
Provisioners
provisioner "shell" {
inline = [
"dnf update -y",
"dnf install -y vim htop tmux",
]
}
provisioner "shell" {
script = "scripts/setup.sh"
environment_vars = [
"DEBIAN_FRONTEND=noninteractive",
]
}
provisioner "file" {
source = "configs/sshd_config"
destination = "/etc/ssh/sshd_config"
}
provisioner "ansible" {
playbook_file = "./ansible/baseline.yml"
extra_arguments = [
"--extra-vars", "env=template",
"-vv",
]
}
ORDER: provisioners run sequentially top-to-bottom. Put cleanup last.
Quick Reference
| Task | Command |
|---|---|
Initialize plugins |
|
Validate template |
|
Format HCL files |
|
Build image |
|
Build with variables |
|
Build from var file |
|
Build specific source |
|
Debug build (step mode) |
|
Inspect template |
|