Skip to content

Packer

Packer

Packer builds the golden VMware templates that Terraform clones from — this keeps "what OS/patch level/base config does a fresh VM start from" version-controlled and reproducible, rather than a manually-maintained template someone clicks through once and forgets.

Official download

Packer install/downloads — always current.

What gets built

  • Ubuntu templates used for general-purpose VMs and Kubernetes cluster nodes
  • Windows templates (including the WDS-adjacent dev-VM path)
  • HAProxy appliance template (haproxy-tanzu), used as the control-plane load balancer in front of a cluster's kube-apiserver

Credentials

Packer authenticates the same way everything else does — Vault-sourced, via terraform/vault/packer.tf (devhome/packer in Vault; see Vault Overview). .pkrvars.hcl files should never contain a literal credential.

Source material

ISOs are staged on the NAS (see TrueNAS Services) and referenced from there rather than re-downloaded per build — the same NFS share Terraform's vsphere_nas_datastore mounts across the ESXi cluster.

Building a template: make build-*-vm-packer (devsetup repo)

Templates aren't built by running packer build directly — the devsetup repo's Makefile wraps it with a flavor selector, a pre-flight vCenter check, and timestamped logging, so building any template is one command regardless of OS or use case:

# Ubuntu — UBUNTU_PACKER_FLAVOR selects which vars file drives the build
make build-ubuntu-vm-packer UBUNTU_PACKER_FLAVOR=dke        # Kubernetes node base image
make build-ubuntu-vm-packer UBUNTU_PACKER_FLAVOR=devtools   # dev-tools-provisioned VM
make build-ubuntu-vm-packer UBUNTU_PACKER_FLAVOR=desktop    # Ubuntu desktop/jumpbox
make build-ubuntu-vm-packer UBUNTU_PACKER_FLAVOR=rke2       # RKE2 node base image

# Windows — WIN_PACKER_FLAVOR maps to a specific PackerBuilds subdirectory
make build-win-vm-packer WIN_PACKER_FLAVOR=win11
make build-win-vm-packer WIN_PACKER_FLAVOR=WinServer2022-AD-DC
make build-win-vm-packer WIN_PACKER_FLAVOR=dke              # -> WinServer2022 dir

What each target actually does:

  1. check-vcsa runs first ($(MAKE) -C $(DEVHOME_REPO) check-vcsa) — a pre-flight guard confirming vCenter is actually reachable before sinking minutes into a build that would just fail partway through otherwise.
  2. Ubuntu flavors resolve to a .auto.pkrvars.hcl file under PackerBuilds/ubuntu-flavors/<flavor>/ — an invalid flavor name fails immediately with the valid options listed, rather than a confusing Packer error further in. All flavors share one template directory (ubuntu-vsphere-template); only the vars file changes per flavor.
  3. Windows flavors instead map to an entirely different PackerBuilds/ directory per flavor (win11, WinServer2022-AD-DC, or WinServer2022 for the dke flavor) and pick up whatever *.auto.pkrvars.hcl file exists there — Windows templates differ enough between flavors (AD DC promotion, different answer files) that they don't share a single template directory the way Ubuntu flavors do.
  4. Both run packer init . then packer build -var-file=..., and tee timestamped output to $(LOG_DIR)/build-*-vm-packer-<timestamp>.log so a failed overnight build has a log to check in the morning instead of a scrolled-off terminal.

Adding a new flavor is just adding a new .auto.pkrvars.hcl file in the right place — no Makefile change needed unless it's an entirely new OS family.

Rebuilding after a base image or provisioning script changes

If a template's provisioning steps changed (an OS patch baseline, a new cloud-init convention, an HAProxy config change like the PermitRootLogin/cert-chain setup used for the Tanzu Supervisor's control-plane load balancer), rebuild the template with Packer before the next Terraform apply that clones it — Terraform has no way to detect that the template it's pointed at is stale.