How to Create Rocky Linux Template in vSphere - using Packer

Overview

Packer uses the HashiCorp Configuration Language - HCL - designed to allow concise descriptions of the required steps to get to a build file. This page describes the features of HCL2 exhaustively

HCL Templates reference

File structure i have used:

img placeholder


Below two files are commonly used by all the templates. which will be called using packer tool

img placeholder

1. common.pkrvars.hcl
 1// Virtual Machine Settings
 2common_vm_version           = 19
 3common_tools_upgrade_policy = true
 4common_remove_cdrom         = true
 5
 6// Template and Content Library Settings
 7common_template_conversion         = false
 8common_content_library_name        = "vm_library"
 9common_content_library_ovf         = false
10common_content_library_destroy     = false
11common_content_library_skip_export = false
12
13// Removable Media Settings
14common_iso_datastore = "OS_ISO"
15
16// Boot and Provisioning Settings
17common_data_source       = "http"
18common_http_ip           = null
19common_http_port_min     = 8000
20common_http_port_max     = 8099
21common_ip_wait_timeout   = "20m"
22common_ip_settle_timeout = "5s"
23common_shutdown_timeout  = "15m"
2. vsphere.pkrvars.hcl
 1// vSphere Credentials - replace with your configuration
 2vsphere_endpoint            = "vcsa.cloudbricks.local"
 3vsphere_username            = "Administrator@vsphere.local"
 4vsphere_password            = "SuperSecretPassword"
 5vsphere_insecure_connection = false
 6
 7// vSphere Settings
 8vsphere_datacenter                     = "Lab"
 9//vsphere_cluster                      = "Cluster"
10vsphere_host                           = "esx-base.cloudbricks.local"
11vsphere_datastore                      = "SSD"
12vsphere_network                        = "cloudbricks"
13vsphere_folder                         = "Templates"
14
15vsphere_set_host_for_datastore_uploads = false

Below files are used for Rocky Linux 9 template

img placeholder


1. variables.pkr.hcl

Contains all input variables to which you assign values. Any explicit values in this file will override the declared default values (these are found in the following file). The auto extension enables Packer to use this file automatically. It does not require you to reference or pass it in the command line explicitly

  1variable "vsphere_endpoint" {
  2  type        = string
  3  description = "The fully qualified domain name or IP address of the vCenter Server instance."
  4}
  5
  6variable "vsphere_username" {
  7  type        = string
  8  description = "The username to login to the vCenter Server instance."
  9  sensitive   = true
 10}
 11
 12variable "vsphere_password" {
 13  type        = string
 14  description = "The password for the login to the vCenter Server instance."
 15  sensitive   = true
 16}
 17
 18variable "vsphere_insecure_connection" {
 19  type        = bool
 20  description = "Do not validate vCenter Server TLS certificate."
 21}
 22
 23// vSphere Settings
 24
 25variable "vsphere_datacenter" {
 26  type        = string
 27  description = "The name of the target vSphere datacenter."
 28  default     = ""
 29}
 30
 31variable "vsphere_cluster" {
 32  type        = string
 33  description = "The name of the target vSphere cluster."
 34  default     = ""
 35}
 36
 37variable "vsphere_host" {
 38  type        = string
 39  description = "The name of the target ESXi host."
 40  default     = ""
 41}
 42
 43variable "vsphere_datastore" {
 44  type        = string
 45  description = "The name of the target vSphere datastore."
 46}
 47
 48variable "vsphere_network" {
 49  type        = string
 50  description = "The name of the target vSphere network segment."
 51}
 52
 53variable "vsphere_folder" {
 54  type        = string
 55  description = "The name of the target vSphere folder."
 56  default     = ""
 57}
 58
 59variable "vsphere_resource_pool" {
 60  type        = string
 61  description = "The name of the target vSphere resource pool."
 62  default     = ""
 63}
 64
 65variable "vsphere_set_host_for_datastore_uploads" {
 66  type        = bool
 67  description = "Set this to true if packer should use the host for uploading files to the datastore."
 68  default     = false
 69}
 70
 71// Virtual Machine Settings
 72
 73variable "vm_guest_os_language" {
 74  type        = string
 75  description = "The guest operating system lanugage."
 76  default     = "en_US"
 77}
 78
 79variable "vm_guest_os_keyboard" {
 80  type        = string
 81  description = "The guest operating system keyboard input."
 82  default     = "us"
 83}
 84
 85variable "vm_guest_os_timezone" {
 86  type        = string
 87  description = "The guest operating system timezone."
 88  default     = "UTC"
 89}
 90
 91variable "vm_guest_os_family" {
 92  type        = string
 93  description = "The guest operating system family. Used for naming and VMware Tools."
 94}
 95
 96variable "vm_guest_os_name" {
 97  type        = string
 98  description = "The guest operating system name. Used for naming."
 99}
100
101variable "vm_guest_os_version" {
102  type        = string
103  description = "The guest operating system version. Used for naming."
104}
105
106variable "vm_guest_os_type" {
107  type        = string
108  description = "The guest operating system type, also know as guestid."
109}
110
111variable "vm_firmware" {
112  type        = string
113  description = "The virtual machine firmware."
114  default     = "efi"
115}
116
117variable "vm_cdrom_type" {
118  type        = string
119  description = "The virtual machine CD-ROM type."
120  default     = "sata"
121}
122
123variable "vm_cpu_count" {
124  type        = number
125  description = "The number of virtual CPUs."
126}
127
128variable "vm_cpu_cores" {
129  type        = number
130  description = "The number of virtual CPUs cores per socket."
131}
132
133variable "vm_cpu_hot_add" {
134  type        = bool
135  description = "Enable hot add CPU."
136  default     = false
137}
138
139variable "vm_mem_size" {
140  type        = number
141  description = "The size for the virtual memory in MB."
142}
143
144variable "vm_mem_hot_add" {
145  type        = bool
146  description = "Enable hot add memory."
147  default     = false
148}
149
150variable "vm_disk_size" {
151  type        = number
152  description = "The size for the virtual disk in MB."
153}
154
155variable "vm_disk_controller_type" {
156  type        = list(string)
157  description = "The virtual disk controller types in sequence."
158  default     = ["pvscsi"]
159}
160
161variable "vm_disk_thin_provisioned" {
162  type        = bool
163  description = "Thin provision the virtual disk."
164  default     = true
165}
166
167variable "vm_network_card" {
168  type        = string
169  description = "The virtual network card type."
170  default     = "vmxnet3"
171}
172
173variable "common_vm_version" {
174  type        = number
175  description = "The vSphere virtual hardware version."
176}
177
178variable "common_tools_upgrade_policy" {
179  type        = bool
180  description = "Upgrade VMware Tools on reboot."
181  default     = true
182}
183
184variable "common_remove_cdrom" {
185  type        = bool
186  description = "Remove the virtual CD-ROM(s)."
187  default     = true
188}
189
190// Template and Content Library Settings
191
192variable "common_template_conversion" {
193  type        = bool
194  description = "Convert the virtual machine to template. Must be 'false' for content library."
195  default     = false
196}
197
198variable "common_content_library_name" {
199  type        = string
200  description = "The name of the target vSphere content library, if used."
201  default     = null
202}
203
204variable "common_content_library_ovf" {
205  type        = bool
206  description = "Export to content library as an OVF template."
207  default     = true
208}
209
210variable "common_content_library_destroy" {
211  type        = bool
212  description = "Delete the virtual machine after exporting to the content library."
213  default     = true
214}
215
216variable "common_content_library_skip_export" {
217  type        = bool
218  description = "Skip exporting the virtual machine to the content library. Option allows for testing/debugging without saving the machine image."
219  default     = false
220}
221
222// OVF Export Settings
223
224variable "common_ovf_export_enabled" {
225  type        = bool
226  description = "Enable OVF artifact export."
227  default     = false
228}
229
230variable "common_ovf_export_overwrite" {
231  type        = bool
232  description = "Overwrite existing OVF artifact."
233  default     = true
234}
235
236// Removable Media Settings
237
238variable "common_iso_datastore" {
239  type        = string
240  description = "The name of the source vSphere datastore for the guest operating system ISO."
241}
242
243variable "iso_path" {
244  type        = string
245  description = "The path on the source vSphere datastore for the guest operating system ISO."
246}
247
248variable "iso_file" {
249  type        = string
250  description = "The file name of the guest operating system ISO."
251}
252
253// Boot Settings
254
255variable "common_data_source" {
256  type        = string
257  description = "The provisioning data source. One of `http` or `disk`."
258}
259
260variable "common_http_ip" {
261  type        = string
262  description = "Define an IP address on the host to use for the HTTP server."
263  default     = null
264}
265
266variable "common_http_port_min" {
267  type        = number
268  description = "The start of the HTTP port range."
269}
270
271variable "common_http_port_max" {
272  type        = number
273  description = "The end of the HTTP port range."
274}
275
276variable "vm_boot_order" {
277  type        = string
278  description = "The boot order for virtual machines devices."
279  default     = "disk,cdrom"
280}
281
282variable "vm_boot_wait" {
283  type        = string
284  description = "The time to wait before boot."
285}
286
287variable "common_ip_wait_timeout" {
288  type        = string
289  description = "Time to wait for guest operating system IP address response."
290}
291
292variable "common_ip_settle_timeout" {
293  type        = string
294  description = "Time to wait for guest operating system IP to settle down."
295  default     = "5s"
296}
297
298variable "common_shutdown_timeout" {
299  type        = string
300  description = "Time to wait for guest operating system shutdown."
301}
302
303// Communicator Settings and Credentials
304
305
306
307variable "communicator_proxy_host" {
308  type        = string
309  description = "The proxy server to use for SSH connection. (Optional)"
310  default     = null
311}
312
313variable "communicator_proxy_port" {
314  type        = number
315  description = "The port to connect to the proxy server. (Optional)"
316  default     = null
317}
318
319variable "communicator_proxy_username" {
320  type        = string
321  description = "The username to authenticate with the proxy server. (Optional)"
322  default     = null
323}
324
325variable "communicator_proxy_password" {
326  type        = string
327  description = "The password to authenticate with the proxy server. (Optional)"
328  sensitive   = true
329  default     = null
330}
331
332variable "communicator_port" {
333  type        = string
334  description = "The port for the communicator protocol."
335}
336
337variable "communicator_timeout" {
338  type        = string
339  description = "The timeout for the communicator protocol."
340}
2. linux-rocky.pkr.hcl

This file contains the blocks as mentioned in the refernece, from declared variables, build and source blocks. Packer uses this to automate the VM template creation.

  1
  2//  BLOCK: packer config
  3
  4
  5packer {
  6  required_version = ">= 1.9.4"
  7  required_plugins {
  8    vsphere = {
  9      source  = "github.com/hashicorp/vsphere"
 10      version = ">= 1.2.1"
 11    }
 12
 13  }
 14}
 15
 16//  BLOCK: data
 17//  Defines the data sources
 18
 19//  BLOCK: locals
 20//  Defines the local variables.
 21
 22locals {
 23  iso_paths         = ["[${var.common_iso_datastore}] ${var.iso_path}/${var.iso_file}"]
 24  ovf_export_path   = "${path.cwd}/artifacts/${local.vm_name}"
 25  data_source_content = {
 26    "/ks.cfg" = templatefile("${abspath(path.root)}/data/ks.pkrtpl.hcl", {
 27      vm_guest_os_language     = var.vm_guest_os_language
 28      vm_guest_os_keyboard     = var.vm_guest_os_keyboard
 29      vm_guest_os_timezone     = var.vm_guest_os_timezone
 30    })
 31  }
 32  data_source_command = var.common_data_source == "http" ? "inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg" : "inst.ks=cdrom:/ks.cfg"
 33  vm_name             = "${var.vm_guest_os_name}9"
 34
 35}
 36
 37//  BLOCK: source
 38//  Defines the builder configuration blocks.
 39
 40source "vsphere-iso" "linux-rocky" {
 41
 42  // vCenter Server Endpoint Settings and Credentials
 43  vcenter_server      = var.vsphere_endpoint
 44  username            = var.vsphere_username
 45  password            = var.vsphere_password
 46  insecure_connection = var.vsphere_insecure_connection
 47
 48  // vSphere Settings
 49  datacenter                     = var.vsphere_datacenter
 50  cluster                        = var.vsphere_cluster
 51  host                           = var.vsphere_host
 52  datastore                      = var.vsphere_datastore
 53  folder                         = var.vsphere_folder
 54  resource_pool                  = var.vsphere_resource_pool
 55  set_host_for_datastore_uploads = var.vsphere_set_host_for_datastore_uploads
 56
 57  // Virtual Machine Settings
 58  vm_name              = local.vm_name
 59  guest_os_type        = var.vm_guest_os_type
 60  firmware             = var.vm_firmware
 61  CPUs                 = var.vm_cpu_count
 62  cpu_cores            = var.vm_cpu_cores
 63  CPU_hot_plug         = var.vm_cpu_hot_add
 64  RAM                  = var.vm_mem_size
 65  RAM_hot_plug         = var.vm_mem_hot_add
 66  cdrom_type           = var.vm_cdrom_type
 67  disk_controller_type = var.vm_disk_controller_type
 68  storage {
 69    disk_size             = var.vm_disk_size
 70    disk_thin_provisioned = var.vm_disk_thin_provisioned
 71  }
 72  network_adapters {
 73    network      = var.vsphere_network
 74    network_card = var.vm_network_card
 75  }
 76  vm_version           = var.common_vm_version
 77  remove_cdrom         = var.common_remove_cdrom
 78  tools_upgrade_policy = var.common_tools_upgrade_policy
 79
 80
 81  // Removable Media Settings
 82  iso_paths    = local.iso_paths
 83  http_content = var.common_data_source == "http" ? local.data_source_content : null
 84  cd_content   = var.common_data_source == "disk" ? local.data_source_content : null
 85
 86  // Boot and Provisioning Settings
 87  http_ip       = var.common_data_source == "http" ? var.common_http_ip : null
 88  http_port_min = var.common_data_source == "http" ? var.common_http_port_min : null
 89  http_port_max = var.common_data_source == "http" ? var.common_http_port_max : null
 90  boot_order    = var.vm_boot_order
 91  boot_wait     = var.vm_boot_wait
 92  boot_command = [
 93    // This sends the "up arrow" key, typically used to navigate through boot menu options.
 94    "<up>",
 95    // This sends the "e" key. In the GRUB boot loader, this is used to edit the selected boot menu option.
 96    "e",
 97    // This sends two "down arrow" keys, followed by the "end" key, and then waits. This is used to navigate to a specific line in the boot menu option's configuration.
 98    "<down><down><end><wait>",
 99    // This types the string "text" followed by the value of the 'data_source_command' local variable.
100    // This is used to modify the boot menu option's configuration to boot in text mode and specify the kickstart data source configured in the common variables.
101    "text ${local.data_source_command}",
102    // This sends the "enter" key, waits, turns on the left control key, sends the "x" key, and then turns off the left control key. This is used to save the changes and exit the boot menu option's configuration, and then continue the boot process.
103    "<enter><wait><leftCtrlOn>x<leftCtrlOff>"
104  ]
105  ip_wait_timeout   = var.common_ip_wait_timeout
106  ip_settle_timeout = var.common_ip_settle_timeout
107  shutdown_command  = "echo '' | sudo -S -E shutdown -P now"
108  shutdown_timeout  = var.common_shutdown_timeout
109
110  // Communicator Settings and Credentials
111  communicator       = "ssh"
112  ssh_proxy_host     = var.communicator_proxy_host
113  ssh_proxy_port     = var.communicator_proxy_port
114  ssh_proxy_username = var.communicator_proxy_username
115  ssh_proxy_password = var.communicator_proxy_password
116  ssh_username       = "root"
117  ssh_password       = "VMware1!"
118  ssh_port           = var.communicator_port
119  ssh_timeout        = var.communicator_timeout
120
121  // Template and Content Library Settings
122  convert_to_template = true
123}
124
125//  BLOCK: build
126
127build {
128  sources = ["source.vsphere-iso.linux-rocky"]
129
130}
3. linux-rocky.auto.pkrvars.hcl

Once a variable is declared in the configuration, we can set it as individual or using *.auto.pkrvars.hcl

Individually, with the -var foo=bar command line option.

In variable definitions files, either specified on the command line with the -var-files values.pkrvars.hcl or automatically loaded (*.auto.pkrvars.hcl).

 1/*
 2    DESCRIPTION:
 3    Rocky Linux 9 build variables.
 4    Packer Plugin for VMware vSphere: 'vsphere-iso' builder.
 5*/
 6
 7// Guest Operating System Metadata
 8vm_guest_os_language = "en_US"
 9vm_guest_os_keyboard = "us"
10vm_guest_os_timezone = "UTC"
11vm_guest_os_family   = "linux"
12vm_guest_os_name     = "rocky"
13vm_guest_os_version  = "9.2"
14
15// Virtual Machine Guest Operating System Setting
16vm_guest_os_type = "other5xLinux64Guest"
17
18// Virtual Machine Hardware Settings
19vm_firmware              = "efi"
20vm_cdrom_type            = "sata"
21vm_cpu_count             = 2
22vm_cpu_cores             = 1
23vm_cpu_hot_add           = false
24vm_mem_size              = 2048
25vm_mem_hot_add           = false
26vm_disk_size             = 307200
27vm_disk_controller_type  = ["pvscsi"]
28vm_disk_thin_provisioned = true
29vm_network_card          = "vmxnet3"
30
31// Removable Media Settings
32iso_path = "ISO"
33iso_file = "Rocky-9.2-minimal.iso"
34
35// Boot Settings
36vm_boot_order = "disk,cdrom"
37vm_boot_wait  = "2s"
38
39// Communicator Settings
40communicator_port    = 22
41communicator_timeout = "30m"
4. ks.pkrtpl.hcl under data folder

All Packer can do without a kickstart file is provision the virtual machine and destroy it in vCenter (the build will time out as it has no connectivity to the VM itself). The kickstart automates the installation of the operating system, in this case, Rocky Linux.

 1# Generated by Anaconda 34.25.2.10
 2# Generated by pykickstart v3.32
 3#version=RHEL9
 4# Use graphical install
 5text
 6repo --name="minimal" --baseurl=file:///run/install/sources/mount-0000-cdrom/minimal
 7
 8%addon com_redhat_kdump --disable
 9
10%end
11
12# Keyboard layouts
13keyboard --xlayouts='gb'
14# System language
15lang en_GB.UTF-8
16
17# Network information
18network  --bootproto=dhcp --device=ens33 --noipv6 --activate
19network  --hostname=rocky9.cloudbricks.local
20
21# Use CDROM installation media
22cdrom
23
24%packages
25@^minimal-environment
26
27%end
28
29# Run the Setup Agent on first boot
30firstboot --enable
31
32# Generated using Blivet version 3.6.0
33ignoredisk --only-use=sda
34# Partition clearing information
35clearpart --none --initlabel
36# Disk partitioning information
37part /boot/efi --fstype="efi" --ondisk=sda --size=600 --fsoptions="umask=0077,shortname=winnt"
38part pv.111 --fstype="lvmpv" --ondisk=sda --size=305574
39part /boot --fstype="xfs" --ondisk=sda --size=1024
40volgroup rl --pesize=4096 pv.111
41logvol swap --fstype="swap" --size=4045 --name=swap --vgname=rl
42logvol /home --fstype="xfs" --size=40960 --name=home --vgname=rl
43logvol / --fstype="xfs" --size=260564 --name=root --vgname=rl
44
45# System timezone
46timezone Europe/London --utc
47
48# Root password
49rootpw --iscrypted --allow-ssh $6$f10cpjmfQjn8vdWA$2AxHqJT5AQYBk5y/PIoKvQCU5IoYWbbTlO3OA9jYB1/lzxov9bAM416wwlOog7IK94sZpxghG8IOkxZkysAXy.
50
51
52
53### Post-installation commands.
54%post
55dnf makecache
56dnf install epel-release -y
57dnf makecache
58dnf install -y sudo open-vm-tools perl
59%end
60
61### Reboot after the installation is complete.
62### --eject attempt to eject the media before rebooting.
63reboot --eject

Now that we have all the required configurations in place, will process with build.

To start the build, enter the following command from /opt/code/packer folder

1packer build -var-file=common.pkrvars.hcl -var-file=vsphere.pkrvars.hcl linux/rocky/9/

it took, approximately 13 minutes for me to complete the template creation

Watch the video on How to:


Posts in this Series