Getting Started with Packer

This article was written as a short primer on Packer and a quick introduction to how it works.

“Give me a place to stand and with a lever I will move the whole world. ” Archimedes



Introduction

This article was written as a short primer on Packer and a quick introduction to how it works. For more specific detail, please check the documentation listed here: Packer Documentation

Packer is a tool that lets you build multiple machine images from a single template. It’s the tool I’ve found best used for creating golden images.

Packer uses either HCL or JSON-based templates as input data for the image build. Packer uses the template as an instruction manual to communicate with the provider, build the specified image, and run additional provisioning steps.

From version 1.7.0 and on, HCL2 is the de-facto standard and preferred way to build packer configurations.
Packer Templates


Helpful Terms

Some helpful terms to keep in mind when working with Packer:

Templates

JSON or HCL2 coded files that detail how your build will execute, very much like a cooking recipe. A bakingrecipe might say to bake something at 400F for 20 minutes, and a template will tell Packer to use the vSphere builder to create a VM with 2GB of RAM.

Artifacts

An Artifact is specific data left over from a builder during a run, and It can be unique to the builder used. For instance, the vSphere builder artifact is a directory of files detailing the VM built, while an EC2 builder artifact is a resultant set of AMI IDs.

Builds

The overall packer execution run. “The packer build creates an Ubuntu 20 vSphere VM."

Builders

Think of these as modules or plugins tasked with building the specific image on the platform, i.e., the execution engine that communicates with vSphere and creates the VM.

Commands

These are simply the commands you can run against the packer executable, i.e.: packer build, which executes a build command.

Data sources

These components allow Packer to fetch specific data from a provider and use it in a build, i.e., getting an AMI ID from amazon during the build process by telling Packer you want the latest ubuntu x86 image.

Provisioners

Provisioners work similar to builders, except they interact with the machine during run-time before converting to a static image. For example, an Ansible provisioner would configure and run ansible-related tasks.

Post Processors

After the provisioner and builders have finished, Post-processors can complete operations against the build artifacts. For example, the Manifest Post-processor writes a JSON file with a list of the artifacts created during a run.


The Packer Process

How it all comes together when you run  packer build

packer-process-image


Example Template

Below are several code examples of sections in a packer template. The full template is available at the following link: Kalen Arndt - packer-vsphere-cloud-init template

In this block, we define the required packer version and the builder plugins and versions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
//  BLOCK: packer
//  The Packer configuration.

packer {
  required_version = ">=1.7.4"
  required_plugins {
    vsphere = {
      version = ">=v1.0.1"
      source  = "github.com/hashicorp/vsphere"
    }
  }
}

Locals

In this section, we define local variables, and in this example, we are using a build time variable used for logging.

1
2
3
4
5
6
//  BLOCK: locals
//  Defines the local variables.

locals {
  buildtime = formatdate("YYYY-MM-DD hh:mm ZZZ", timestamp())
}

Source

This section defines everything that the builder will need when communicating and instructing the provider to create the machine.

This section can be pretty large, so I’ve only included a small example selection.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//  BLOCK: source
//  Defines the builder configuration blocks.

source "vsphere-iso" "linux-ubuntu-server" {

  // vCenter Server Endpoint Settings and Credentials
  vcenter_server      = var.vsphere_endpoint
  username            = var.vsphere_username
  password            = var.vsphere_password
  insecure_connection = var.vsphere_insecure_connection

  // vSphere Settings
  datacenter = var.vsphere_datacenter
  cluster    = var.vsphere_cluster
  datastore  = var.vsphere_datastore
  folder     = var.vsphere_folder

  // Virtual Machine Settings
  guest_os_type        = var.vm_guest_os_type
  vm_name              = "${var.vm_guest_os_family}-${var.vm_guest_os_vendor}-${var.vm_guest_os_member}-${var.vm_guest_os_version}"
  firmware             = var.vm_firmware
  CPUs                 = var.vm_cpu_sockets
  cpu_cores            = var.vm_cpu_cores
  CPU_hot_plug         = var.vm_cpu_hot_add
  RAM                  = var.vm_mem_size
  RAM_hot_plug         = var.vm_mem_hot_add
  cdrom_type           = var.vm_cdrom_type
  disk_controller_type = var.vm_disk_controller_type

Build

In this block, we identify the builder, along with the provisioner and post-processor configurations.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
//  BLOCK: build
//  Defines the builders to run, provisioners, and post-processors.

build {
  sources = ["source.vsphere-iso.linux-ubuntu-server"]

  provisioner "shell" {
    execute_command = "echo '${var.build_password}' | {{.Vars}} sudo -E -S sh -eux '{{.Path}}'"
    environment_vars = [
      "BUILD_USERNAME=${var.build_username}",
      "BUILD_KEY=${var.build_key}",

    ]
    scripts = var.scripts
  }

  post-processor "manifest" {
    output     = "${path.cwd}/logs/${local.buildtime}-${var.vm_guest_os_family}-${var.vm_guest_os_vendor}-${var.vm_guest_os_member}.json"
    strip_path = false
  }
}

Closing thoughts

This article has been a quick primer on Packer, the process, and fundamentals. If you want to learn more, I suggest looking at Hashicorp’s Packer tutorials and documentation.

The example HCL template shown is part of ubuntu on vSphere packer build, which I will cover in future posts.

Thanks for reading!



Acknowledgements


Back to Top