How to Create ESXi 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 ESXi template (This template I'm using to crete nested VMware Lab)

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. esxi.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  vm_name             = "${var.vm_guest_os_name}${var.vm_guest_os_version}"
 25
 26}
 27
 28//  BLOCK: source
 29//  Defines the builder configuration blocks.
 30
 31source "vsphere-iso" "esxi" {
 32
 33  // vCenter Server Endpoint Settings and Credentials
 34  vcenter_server      = var.vsphere_endpoint
 35  username            = var.vsphere_username
 36  password            = var.vsphere_password
 37  insecure_connection = var.vsphere_insecure_connection
 38
 39  // vSphere Settings
 40  datacenter                     = var.vsphere_datacenter
 41  cluster                        = var.vsphere_cluster
 42  host                           = var.vsphere_host
 43  datastore                      = var.vsphere_datastore
 44  folder                         = var.vsphere_folder
 45  resource_pool                  = var.vsphere_resource_pool
 46  set_host_for_datastore_uploads = var.vsphere_set_host_for_datastore_uploads
 47
 48  // Virtual Machine Settings
 49  vm_name              = local.vm_name
 50  guest_os_type        = var.vm_guest_os_type
 51  firmware             = var.vm_firmware
 52  CPUs                 = var.vm_cpu_count
 53  cpu_cores            = var.vm_cpu_cores
 54  NestedHV             = true
 55  CPU_hot_plug         = var.vm_cpu_hot_add
 56  RAM                  = var.vm_mem_size
 57  RAM_hot_plug         = var.vm_mem_hot_add
 58  cdrom_type           = var.vm_cdrom_type
 59  disk_controller_type = var.vm_disk_controller_type
 60  storage {
 61    disk_size             = var.vm_disk_size
 62    disk_thin_provisioned = var.vm_disk_thin_provisioned
 63  }
 64  network_adapters {
 65    network      = var.vsphere_network
 66    network_card = var.vm_network_card
 67  }
 68  vm_version           = "21"
 69  remove_cdrom         = var.common_remove_cdrom
 70  tools_upgrade_policy = var.common_tools_upgrade_policy
 71
 72
 73  // Removable Media Settings
 74  iso_paths    = local.iso_paths
 75
 76  // Boot and Provisioning Settings
 77  http_ip       = var.common_data_source == "http" ? var.common_http_ip : null
 78  http_port_min = var.common_data_source == "http" ? var.common_http_port_min : null
 79  http_port_max = var.common_data_source == "http" ? var.common_http_port_max : null
 80  boot_order    = var.vm_boot_order
 81  boot_wait     = var.vm_boot_wait
 82  http_directory = "/opt/code/packer/vmware/esxi8/data"
 83  boot_command  = ["<leftShift>O ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/esx-ks.cfg<enter>"]
 84  ip_wait_timeout   = var.common_ip_wait_timeout
 85  ip_settle_timeout = var.common_ip_settle_timeout
 86  shutdown_command  = "esxcli system maintenanceMode set -e true -t 0 ; esxcli system shutdown poweroff -d 10 -r 'Packer Shutdown' ; esxcli system maintenanceMode set -e false -t 0 "
 87  shutdown_timeout  = var.common_shutdown_timeout
 88
 89  // Communicator Settings and Credentials
 90  communicator       = "ssh"
 91  ssh_proxy_host     = var.communicator_proxy_host
 92  ssh_proxy_port     = var.communicator_proxy_port
 93  ssh_proxy_username = var.communicator_proxy_username
 94  ssh_proxy_password = var.communicator_proxy_password
 95  ssh_username       = "root"
 96  ssh_password       = "VMware1!"
 97  ssh_port           = var.communicator_port
 98  ssh_timeout        = var.communicator_timeout
 99
100  // Template and Content Library Settings
101  convert_to_template = true
102}
103
104//  BLOCK: build
105
106build {
107  sources = ["source.vsphere-iso.esxi"]
108
109}
3. esxi.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// Guest Operating System Metadata
 2vm_guest_os_language = "en_US"
 3vm_guest_os_keyboard = "us"
 4vm_guest_os_timezone = "UTC"
 5vm_guest_os_family   = "esxi"
 6vm_guest_os_name     = "esxi"
 7vm_guest_os_version  = "8"
 8
 9// Virtual Machine Guest Operating System Setting
10vm_guest_os_type = "vmkernel8Guest"
11
12// Virtual Machine Hardware Settings
13vm_firmware              = "efi"
14vm_cdrom_type            = "sata"
15vm_cpu_count             = 2
16vm_cpu_cores             = 2
17vm_cpu_hot_add           = false
18vm_mem_size              = 8192
19vm_mem_hot_add           = false
20vm_disk_size             = 40960
21vm_disk_controller_type  = ["pvscsi"]
22vm_disk_thin_provisioned = true
23vm_network_card          = "vmxnet3"
24
25// Removable Media Settings
26iso_path = "ISO"
27iso_file = "esxi8_u2.iso"
28
29// Boot Settings
30vm_boot_wait  = "1s"
31
32// Communicator Settings
33communicator_port    = 22
34communicator_timeout = "30m"
4. esx-ks.cfg 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#
 2# Sample scripted installation file
 3#
 4# Accept EULA
 5vmaccepteula
 6# Set root password
 7rootpw VMware1!
 8#Install on local disk overwriting any existing VMFS datastore
 9install --firstdisk --overwritevmfs
10# Network configuration
11network --bootproto=dhcp --device=vmnic0
12#Reboot after installation completed
13reboot
14
15%firstboot --interpreter=busybox
16#esx/ssh
17vim-cmd hostsvc/enable_ssh
18vim-cmd hostsvc/start_ssh
19esxcli system settings advanced set -o /UserVars/SuppressShellWarning -i 1
20#esxi/ssh end

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 vmware/esxi8/

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

Watch the video on How to:


Posts in this Series