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
File structure i have used:
Below two files are commonly used by all the templates. which will be called using packer tool
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
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