Packer architecture
Packer itself is a fairly simple binary written in Go. It supports plugins for various inputs and outputs. The plugins that translate your configuration and scripts into artifact outputs are called builders. Common builders include common hypervisors such as VMware, QEMU, VirtualBox, AWS, GCP, and Microsoft Azure. Builders also include multiple container image formats, including LXC, LXD, Docker, and Podman. Many plugins have been contributed by the community and we will cover how you can write your own in a future chapter.
The bit of code you write to tell Packer what to do is called a template. Early versions of Packer expected your template to be written in JavaScript Object Notation (JSON). As of Packer version 1.7.0, both JSON and HashiCorp Configuration Language version 2 (HCL2) are supported, with the latter being preferred. We will cover both formats and how you can migrate a JSON template into an HCL2 template shortly.
Provisioners are tasks or resources that should be applied to your image before packaging. By default, each builder in your template takes each provisioner. Take an example where you want to build a system image with your application across AWS, Azure, and GCP. All you need to do is define your list of builders for AWS, Azure, and GCP and include a single provisioner that uploads your application.
A build job is what runs the Packer build command with your template. Normally, this forks a parallel process for every builder you specify in your template. A build can happen simultaneously across VMware, AWS, Azure, GCP, or other builders while Packer tracks the results and reports any errors. When all builders finish or end in an error, the job is done and the Packer process terminates. Optionally, Packer may compress output images before terminating, to save space.