Packer
Differences between HCL2 and JSON templates
This document explains the differences between JSON to HCL2 templates, including how converting JSON templates to HCL2 affects builder, provisioner, and post-processor behavior.
Introduction
Packer uses JSON or HCL2 templates to orchestrate builds for one or more artifacts.
In legacy JSON templates, declare a series of builders, provisioners, and post-processors to build images.
In HCL2 templates, you can specify builders through sources and collect them into build blocks.
You can use the packer hcl2_upgrade
command when converting your existing JSON templates to HCL2. Refer to the hcl2_upgrade page for more information on its usage.
Builders
Builders are components that are specialized for a platform. Their role is to set the stage for the steps that will let you build the final image from your configuration template.
JSON
In JSON, the builders
attribute declares how a builder will be invoked to build an image.
{
"builders": [
{
"type": "null",
"name": "test",
"communicator": "none"
}
]
}
HCL2
In HCL2, builders are declared through a source
block. Sources on their own are not enough, and must be invoked in a build
block.
The build
block serves as a container for all the steps (i.e. source
, provisioners
and post-processors
) to go from a blank image to a finished one.
source "null" "test" {
communicator = "none"
}
build {
sources = ["null.test"]
}
Provisioners
Provisioners are components that modify the state of the machine image you are building. They can be used for installing packages, writing data to the remote file system, or executing remote commands. They can be defined in both JSON or HCL templates.
JSON
In a JSON template, provisioners are declared at the top-level of the template as an array of sequentially invoked components to provision the image you are building. They apply to all the builders defined in the template.
{
"builders": [
{
"type": "null",
"name": "test",
"communicator": "none"
}
],
"provisioners": [
{
"type": "shell-local",
"inline": ["echo test"]
}
]
}
HCL2
In HCL2, provisioners are declared in the build
block, and apply only to the sources invoked as
part of this build block.
This lets you declare multiple build blocks, each with its own set of provisioners, which will
result in multiple different builds executed in parallel.
source "null" "test" {
communicator = "none"
}
build {
sources = ["null.test"]
provisioner "shell-local" {
inline = ["echo test"]
}
}
Post-processors
Post-processors are components that are invoked after the image was produced. Their role is to consume an artifact produced by a builder, or another post-processor, and build a new artifact from that.
JSON
As with provisioners, in JSON templates, post-processors are sequentially invoked after a build finished provisioning, and are declared in the template under "post-processors".
{
"builders": [
{
"type": "null",
"name": "test",
"communicator": "none"
}
],
"provisioners": [
{
"type": "shell-local",
"inline": ["echo test"]
}
],
"post-processors": [
{
"type": "manifest"
}
]
}
HCL2
In HCL2, much like provisioners, they are also part of the build
block, and similar rules
apply as with provisioners.
source "null" "test" {
communicator = "none"
}
build {
sources = ["null.test"]
provisioner "shell-local" {
inline = ["echo test"]
}
post-processor "manifest" {}
}