Today, I’d like to share a practical example of working with HashiCorp Packer. This amazing open-source tool is used for creating identical machine images for multiple platforms from a single source configuration. In this case, we will focus on creating a custom image and pushing it to the Azure Compute Gallery.
Let’s get started!
Step 1: Install Packer and Azure CLI
To begin, you’ll need to install both Packer and Azure CLI on your machine. You can follow the respective official guides for Packer and Azure CLI for installation.
Step 2: Prepare Your Packer Configuration Files
We’ll use the HCL language that is native to the HashiCorp ecosystem for our configuration files. In line with best practices, we will separate our configuration, variables, and values into different HCL files.
- azure.pkr.hcl: This is where the Packer configuration will reside.
- variables.hcl: This file will contain the variable definitions.
- values.auto.pkrvars.hcl: This file will contain the variable values.
- install.sh: A shell script with installation instructions that the provisioner will execute.
These files should look like this:
.
├── azure.pkr.hcl
├── install.sh
├── values.auto.pkrvars.hcl
└── variables.pkr.hcl
0 directories, 4 files.
Create these files in your working directory.
- azure.pkr.hcl:
packer
required_plugins {
azure = {
version = ">= 1.0.0"
source = "github.com/hashicorp/azure"
}
}
}
source "azure-arm" "example" {
managed_image_name = "test-ubuntu-20.04img-${formatdate("DD-MMM-YYYY-hh-mm-ss", timestamp())}" managed_image_resource_group_name = var.gallery_resource_group
managed_image_storage_account_type = "Standard_LRS"
location = var.location
# Using Azure CLI for authentication
use_azure_cli_auth = true
image_offer = "0001-com-ubuntu-server-focal"
image_publisher = "Canonical"
image_sku = "20_04-lts-gen2"
os_type = "Linux"
vm_size = "Standard_B4ms"
os_disk_size_gb = 64
shared_image_gallery_destination {
resource_group = var.gallery_resource_group
gallery_name = var.gallery_name
image_name = "test-ubuntu-20.04"
image_version = "1.0.0"
replication_regions = ["uaenorth"]
storage_account_type = "Standard_LRS"
}
}
build {
sources = [
"source.azure-arm.example"
]
provisioner "shell" {
execute_command = "chmod +x {{ .Path }}; sudo {{ .Vars }} {{ .Path }}"
script = "install.sh"
}
}
- variables.pkr.hcl:
variable "gallery_name" {
type = string
}
variable "gallery_resource_group" {
type = string
}
variable "packer_resource_group" {
type = string
}
variable "location" {
type = string
}
- values.auto.pkrvars.hcl:
gallery_resource_group = "rg-uae1-pkr-demo"
gallery_name = "gal_uae1_pkr_demo"
packer_resource_group = "rg-uae1-pkr-tmp"
location = "uaenorth"
- install.sh:
#!/bin/bash
apt-get update \
&& apt-get upgrade -y \
&& apt-get install -y nginx
Step 3: Authenticate with Azure CLI
az login
Step 4: Create your Azure Compute Gallery and definition
LOCATION=uaenorth
RG_NAME=rg-uae1-pkr-demo
GALLERY_NAME=gal_uae1_pkr_demo
az group create -n $RG_NAME -l $LOCATION
az sig create -g rg-uae1-pkr-demo -r $GALLERY_NAME
# create a definition
az sig image-definition create -g $RG_NAME \
-r $GALLERY_NAME -i test-ubuntu-20.04 \
--publisher GreatPublisher --offer GreatOffer --sku GreatSku \
--os-type linux --os-state Generalized
Step 5: Build The Image
packer init .
packer build .
After running packer build, Packer essentially starts by setting up a temporary ‘kitchen’ (the temporary VM). In this ‘kitchen’, Packer follows your ‘recipe’ (the setup scripts) to prepare the ‘dish’ (the customized image).
Once our scripts have been installed Packer packs it up nicely (generalizes the image), ensuring it’s all set to be replicated or served wherever required.
The last step is to place our image in the display case (Azure Compute Gallery) so it’s available for anyone (or any service) that wants to use it. Here, it’s ready to be deployed as a virtual machine on Azure, or a VMSS! You’ve just created a custom image and pushed it to Azure Compute Gallery.
Remember, with Packer, you can create as many identical images as you want, all made to your specifications, saving you heaps of time and ensuring consistency across your deployments. It’s like having your personal chef in the world of VM images!
That’s it! You have successfully created a custom image with Packer and pushed it to Azure Compute Gallery.
Note: Some Capabilities of HashiCorp Packer
While we focused on a specific use case in this article, Packer is a versatile tool with several capabilities:
- Parallel Builds: Packer is able to create multiple images concurrently, which accelerates the image-building process.
- Extensible: Packer is modular and supports a multitude of platforms, like AWS, Azure, Docker, GCP, and many more.
- Automation-Friendly: It’s designed to fit perfectly into modern automated workflows, making it a great choice for DevOps practices.
- Configuration Management Tool Compatible: It works smoothly with popular configuration management tools like Ansible, Chef, Puppet, etc.
- Supports Custom Scripts: Packer can install and configure software within running VMs using shell scripts, making it highly flexible.
- Environment Variables: Environment variables can be used within your template using user variables. The env function is available only within the default value of a user variable, allowing you to default a user variable to an environment variable. An example is shown below:
Packer’s ability to avoid dependency hell and seamlessly integrate with your existing CI/CD pipeline makes it a powerful tool in a DevOps toolbox.
For more information on Packer, its use cases, and how to leverage its full capabilities, refer to the official documentation.