Packer now supports HCL2, so I rewrote the existing Json format code.
table of contents
My name is Teraoka and I am an infrastructure engineer.
There was a long-awaited update to Packer.
Finally supported HCL2!
This time, I tried rewriting the code that was written in existing Json based on HCL2, so
I would like to summarize it while comparing each code.
What is Packer?
A CLI tool that can create multi-cloud compatible golden images.
This type of golden image creation tool is
highly compatible with Immutable Infrastructure and blue-green deployments, and
is useful in environments such as AutoScaling where server creation and destruction are frequently repeated.
Development continues by HashiCorp and is written in Golang.
Terraform is also a famous tool, so many people may be familiar with it.
supports the creation of hypervisor-type machine images such as Docker images and VMware
as well as major cloud services such as AWS, GCP, and Azure Although it is compatible with many services (called builders in Packer),
the advantage is that you can write code and process in a common format for all builders.
Previously, it could only be written in Json format, but
from version 1.5 it supports HCL2 format.
At the time of writing this article (2020/03/31), it is still in beta,
so it may be better to test it carefully before using it in a production environment.
What is HCL?
It stands for HashiCorp Configuration Language and is also developed by HashiCorp.
In terms of implementation, it is compatible with Json, but since it is a proprietary language, you can write your own unique descriptions that are completely different from Json.
It is intended to be used as a command line tool, and has been supported by Terraform for some time, so
I think it will be familiar to those who write tf files.
By the way, there are two different versions, HCL1 and HCL2, and currently HCL2 is the mainstream.
Let's write a Packer template (Json)
Packer creates images by writing something called a template, but
I would like to write it in HCL2 while comparing the contents of the template with the Json format.
First, let's take a look at what is 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" ] } ] }
Parts such as {{user `ami_name`}} are variables, and
the stored values are written in separate files.
{ "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 above template,
- Search 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 into your EC2 instance
- Log in to the instance using SSH and execute the process described in provisioners
- Stop the EC2 instance
- Get an AMI from a stopped instance
- Delete the instance after acquisition is complete
A series of processes are performed.
IAM roles can be used to obtain AMI information, so
, the IAM role required for execution is set in advance
on the EC2 instance that executes the packer command The permissions required for IAM roles are summarized below.
https://packer.io/docs/builders/amazon.html
Try writing a Packer template (HCL2)
So, what will happen if we rewrite the above Json to HCL2?
First, we will write the value to be stored in the variable.
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" }
Write the values to be stored in variables in variables.pkrvars.hcl.
In Json, it was "value name: value", but in HCL2 it is "value name = value".
Use variable to express variables in HCL2.
Like programming languages, there is a concept of types, and
this time we are all using string type variables.
In addition,
- Numeric type (number)
- List type (list)
- Map type (map)
- Boolean type (bool)
and so on.
Next, we will describe the actual build processing part.
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, in the Json format, what was written in one file
can be separated into separate files for source and build.
Another 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, we read the source settings and
write the processing to be executed during build in the provisioner part.
The sources part is of list type, so you can specify multiple sources as shown below.
sources = [ "source.amazon-ebs.example", "source.amazon-ebs.example2" ]
When running the build, move to the directory where the template file exists.
$ packer build -var-file=variables.pkrvars.hcl ./
This will read and execute all files in the current directory.
Current issues
Packer has a validate command to check the syntax, but
this cannot be used when written in HCL.
I look forward to future updates.
https://github.com/hashicorp/packer/issues/8538
summary
Packer is a useful tool for practicing DevOps using cloud services.
Packer itself is very simple to incorporate into your CI/CD flow, so we
encourage everyone to try using it.