Last Updated on May 18, 2024 by Arnav Sharma
Packer is an open-source tool that enables you to create identical machine images for multiple platforms from a single source template. A common use case is creating “golden images” that teams across an organization can use in cloud infrastructure.
Ref. : Packer by HashiCorp
For customization of Azure, refer: Azure arm – Builders | Packer by HashiCorp
Getting Started:
Download Packer: Downloads | Packer by HashiCorp
Packer has used a JSON template for its configuration in past, but now Packer is transitioning to a new format that uses HCL2. HCL is the same language that is used in Terraform.
Packer Template
- Source Block: This contains the source (azure, AWS, GCP, VMWare etc) , configuration block and plugins.
There are 50-100 different settings to customize the image and process which are documented here:
Azure arm – Builders | Packer by HashiCorp
2. Build block: Contains builders, provisioners, and post-processors used to create a specific image artifact. There are builders specific to the image being built as well as the target environment.
3. Variable block: Similar to terraform, these are the variable to be used and can be specified in a different file.
In the above example, I have placed the code on the .pkl.hcl file and then have two more files – one PowerShell script and the second one to pass values for variables.
Some common commands:
- packer version : Output of packer version
- packer fmt tmpl.pkr.hcl: Template file formatting
- packer validate tmpl.pkr.hcl : Template file validation
- packer build tmpl.pkr.hcl: Build image
- packer build -debug tmpl.pkr.hcl: Build & debug
Running/building the image:
Command:
Packer creates a temp resource group, a VM with required resources (IP, NIC, vNET etc etc) and then captures the image for it.
Resource Group (temp) with resources:
Once the image is created, the image is placed in the RG specified in the code.
The image can then be used to create a VM or can be registered in the gallery.
Sample Code that I used:
image.pkr.hcl
variable "subid"{
type = string
default = null
}
variable "tenant" {
type = string
default = null
}
variable "rgname" {
type = string
default = null
}
variable "username" {
type = string
default = null
}
variable "password" {
type = string
default = null
}
variable "capturenamename" {
type = string
default = null
}
variable "location" {
type = string
default = "australiaeast"
}
source "azure-arm" "windows-image" {
# Basics authentication
subscription_id = var.subid
tenant_id = var.tenant
# Image Settings
os_type = "Windows"
image_publisher = "MicrosoftWindowsServer"
image_offer = "WindowsServer"
image_sku = "2016-Datacenter"
# Temp location / config
location = var.location
vm_size = "Standard_D2_v2"
# Created Image Name
managed_image_name = var.capturenamename
managed_image_resource_group_name = var.rgname
# Communication (WinRM) and settings
communicator = "winrm"
winrm_insecure = "true"
winrm_use_ssl = "true"
winrm_timeout = "3m"
winrm_username = var.username
winrm_password = var.password
}
build {
# Build the Image
sources = ["azure-arm.windows-image"]
# Script for windows settings - powershell
provisioner "powershell" {
script = "Configuration.ps1"
execution_policy = "bypass"
elevated_user = var.username
elevated_password = var.password
}
}
Configuration.ps1
<powershell>
write-output "Running User Data Script"
write-host "(host) Running User Data Script"
Set-ExecutionPolicy Unrestricted -Scope LocalMachine -Force -ErrorAction Ignore
# Don't set this before Set-ExecutionPolicy as it throws an error
$ErrorActionPreference = "stop"
# Remove HTTP listener
Remove-Item -Path WSMan:Localhostlistenerlistener* -Recurse
$Cert = New-SelfSignedCertificate -CertstoreLocation Cert:LocalMachineMy -DnsName "packer"
New-Item -Path WSMan:LocalHostListener -Transport HTTPS -Address * -CertificateThumbPrint $Cert.Thumbprint -Force
# WinRM
write-output "Setting up WinRM"
write-host "(host) setting up WinRM"
cmd.exe /c winrm quickconfig -q
cmd.exe /c winrm set "winrm/config" '@{MaxTimeoutms="1800000"}'
cmd.exe /c winrm set "winrm/config/winrs" '@{MaxMemoryPerShellMB="1024"}'
cmd.exe /c winrm set "winrm/config/service" '@{AllowUnencrypted="true"}'
cmd.exe /c winrm set "winrm/config/client" '@{AllowUnencrypted="true"}'
cmd.exe /c winrm set "winrm/config/service/auth" '@{Basic="true"}'
cmd.exe /c winrm set "winrm/config/client/auth" '@{Basic="true"}'
cmd.exe /c winrm set "winrm/config/service/auth" '@{CredSSP="true"}'
cmd.exe /c winrm set "winrm/config/listener?Address=*+Transport=HTTPS" "@{Port=`"5986`";Hostname=`"packer`";CertificateThumbprint=`"$($Cert.Thumbprint)`"}"
cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes
cmd.exe /c netsh firewall add portopening TCP 5986 "Port 5986"
cmd.exe /c net stop winrm
cmd.exe /c sc config winrm start= auto
cmd.exe /c net start winrm
</powershell>
variables.pkvar.hcl
subid = "b83ba8f2-XXXXXXXXXXXX-8ea3710e139aXX"
tenant = "e034d95f-XXXXXXXXXXXXXXXXXXXXXXXXXX"
rgname = "DefaultResourceGroup"
capturenamename = "myimage"
location = "australiaeast"
username = "myadminusername"
password = "Password@thislocation"