Packer now supports HCL2, so I rewrote my existing JSON format code
![]()
table of contents
This is Teraoka, an infrastructure engineer.
Packer has finally received a long-awaited update.
It now supports HCL2!
This time, I've rewritten some code that was previously written in JSON format, using HCL2 as the base, so
I'd like to compare and summarize the two versions of the code.
What is Packer?
A CLI tool for creating multi-cloud compatible golden images
Tools for creating this type of golden image
work very well with immutable infrastructure and blue-green deployments, and
are invaluable in environments where servers are frequently created and destroyed, such as with Auto Scaling.
Development is continued by HashiCorp and it is written in Golang.
Similarly, Terraform is also a well-known tool, so many of you are probably familiar with it.
for major cloud services such as AWS, GCP, and Azure, as well as
supports the creation of images
It supports a large number of services (called builders in Packer), and
the advantage is that you can write code and describe the processing using a common format for any builder.
Previously, only JSON format was supported, but
version 1.5 adds support for the HCL2 format.
As of the time of writing this article (2020/03/31), it is still in beta, so
it may be best to thoroughly test it before using it in a production environment.
What is HCL
HCL stands for HashiCorp Configuration Language, and is also developed by HashiCorp.
While its implementation is JSON-compatible, it's a proprietary language that allows for entirely different syntax than JSON.
It's intended for use with command-line tools and has been supported by Terraform for some time, so it
should be familiar to those who write tf files.
Incidentally, there are two versions, HCL1 and HCL2, with HCL2 being the current standard.
Writing a Packer template (Json)
Packer creates images by writing templates, and
we will write the template content in HCL2 while comparing it with the JSON format.
First, let's look at what it looks like written in JSON format.
{ "builders": [ { "type": "amazon-ebs", "region": "{{user `region`}}", "source_ami_filter": { "filters": { "name": "{{user `ami_name`}}}*" }, "owners": [ "self" ], "most_recent": true }, "instance_type": "{{user `instance_type`}}", "ssh_username": "{{user `ssh_username`}}", "ami_name": "{{user `ami_name`}}_{{timestamp}}", "tags": { "Name": "{{user `ami_name`}}_{{timestamp}}" }, "iam_instance_profile": "{{user `iam_instance_profile`}}" } ], "provisioners": [ { "type": "shell", "inline": [ "sudo yum -y update" ] } ] }
The parts like {{user `ami_name`}} are variables, and
the values they store are written in a separate file.
{ "ssh_username": "ec2-user", "region": "ap-northeast-1", "instance_type": "t3.micro", "ami_name": "ami-packer-test", "iam_instance_profile": "role-packer-test" }
Using this template file
$ packer build main.json -var-file=variables.json
By executing the command,
you can build the image while reading the values to be stored in variables from variables.json.
If you build according to the contents of the template above,
- Search for the base AMIID using the contents written in source_ami_filter
- Start the build process based on the AMI that matches the search
- Launch a new EC2 instance from the base AMI
- Create a temporary key pair to log in to your EC2 instance
- Log in to the instance via SSH and execute the process described in the provisioners
- Stop the EC2 instance
- Get an AMI from a stopped instance
- Delete the instance after the acquisition is complete
This is the series of processes that are performed.
When obtaining AMI information, IAM roles can be used, so
in the example above, the EC2 instance that executes the packer command
has the necessary IAM role pre-configured.
The permissions required for the IAM role are summarized below.
https://packer.io/docs/builders/amazon.html
Writing a Packer template (HCL2)
So, what would the above JSON look like if we rewrote it in HCL2?
First, we'll write the values to be stored in the variables.
We'll use the following two files.
variables.pkrvars.hcl
ssh_username = "ec2-user" region = "ap-northeast-1" instance_type = "t3.micro" ami_name = "ami-packer-test" iam_instance_profile = "role-packer-test"
variables.pkr.hcl
variable "ssh_username" { type = string description = "SSH User Name" } variable "region" { type = string description = "AWS Region" } variable "instance_type" { type = string description = "EC2 Instance Type" } variable "ami_name" { type = string description = "EC2 AMI Name" } variable "iam_instance_profile" { type = string description = "EC2 IAM Instance Profile" }
The values to be stored in variables are written in variables.pkrvars.hcl.
In JSON, the format was "value name: value", but in HCL2, it becomes "value name = value".
In HCL2, variables are represented using `variable`.
Similar to programming languages, there is a concept of types, and
in this case, we are using only string type variables.
In addition,
- Number type
- List type (list)
- Map type (map)
- Boolean type (bool)
etc
Next, we will write the actual build processing code.
We will use the following two files.
sources.pkr.hcl
## Source source "amazon-ebs" "example" { region = var.region ami_name = "${var.ami_name}_{{timestamp}}" instance_type = var.instance_type iam_instance_profile = var.iam_instance_profile ssh_username = var.ssh_username source_ami_filter { owners = ["self"] most_recent = true filters { virtualization-type = "hvm" name = "${var.ami_name}*" root-device-type = "ebs" } } tags { Name = "${var.ami_name}_{{timestamp}}" } }
build.pkr.hcl
## Build build { sources = [ "source.amazon-ebs.example" ] provisioner "shell" { inline = [ "sudo yum -y update" ] } }
As you can see, what was written in one file in JSON format
can be separated into two separate files called source and build.
Also, a key feature of HCL2 is that you can insert comments in the middle of the code.
Variables can be referenced using "var.variable_name".
In build.pkr.hcl, the source settings are read,
and the provisioner section contains the processes to be executed during the build.
The sources section is of type list, so it is possible to specify multiple sources as shown below.
sources = [ "source.amazon-ebs.example", "source.amazon-ebs.example2" ]
When you run the build, go to the directory where the template file is located and run
$ packer build -var-file=variables.pkrvars.hcl ./
This will load and execute all files in the current directory
Current issues
Packer has a validate command for syntax checking, but
it cannot be used when writing code in HCL.
Hopefully, this will be addressed in future updates.
https://github.com/hashicorp/packer/issues/8538
summary
Packer is a convenient tool for implementing DevOps using cloud services.
It's easy to integrate into CI/CD flows, and Packer itself has a very simple configuration, so
I encourage everyone to give it a try.
0
