Packer

The Oxide multi-component Packer plugin can be used with HashiCorp (IBM) Packer to create custom Oxide images.

The plugin launches a temporary instance from an existing source image, connects to the instance using its external IP, provisions the instance, and then creates a new Oxide image from the instance’s boot disk. The resulting image can be used to launch new instances on Oxide.

This guide demonstrates how to use the Oxide Packer plugin to create an Oxide image. Refer to the Oxide Packer plugin documentation for more information on how to use the plugin and its components.

Install Packer

Follow the instructions at Install Packer to download and install Packer on your machine. Verify your installation once finished.

$ packer version
Packer v1.13.1

Install the Oxide Packer Plugin

Create a Packer configuration file named oxide.pkr.hcl with the following content. Update the version argument to use the latest stable version of the Oxide Packer plugin, which can be found in the plugin documentation.

packer {
required_plugins {
oxide = {
source = "github.com/oxidecomputer/oxide"
version = ">= 0.3.0"
}
}
}

Initialize the configuration to download and install the Oxide Packer plugin.

$ packer init oxide.pkr.hcl
Installed plugin github.com/oxidecomputer/oxide v0.3.0 in "/home/oxide/.config/packer/plugins/github.com/oxidecomputer/oxide/packer-plugin-oxide_v0.3.0_x5.0_linux_amd64"

For other installation methods, such as building from source, refer to the documentation in the oxidecomputer/packer-plugin-oxide repository.

Build an Oxide Image

Note the following requirements before proceeding.

  • An existing image must be present on Oxide that the temporary instance will boot from. See Images for instructions on how to upload an image to Oxide.

  • The machine running Packer must have network access to the temporary instance in order to connect to its external IP and provision it.

Create a Packer configuration file named oxide.pkr.hcl with the following content. Update the variable blocks with values appropriate for your environment.

packer {
required_plugins {
oxide = {
version = ">= 0.3.0"
source = "github.com/oxidecomputer/oxide"
}
}
}

variable "project" {
type = string
description = "Name or ID of the Oxide project used to create the temporary instance and resulting image."
default = "packer-example"
}

variable "source_image_name" {
type = string
description = "Name of the source image to boot the temporary instance from."
default = "ubuntu"
}

variable "ssh_username" {
type = string
description = "Username to use when connecting to the temporary instance over SSH."
default = "ubuntu"
}

data "oxide-image" "example" {
name = var.source_image_name
project = var.project
}

source "oxide-instance" "example" {
project = var.project
boot_disk_image_id = data.oxide-image.example.image_id

ssh_username = var.ssh_username
}

build {
sources = [
"source.oxide-instance.example",
]

provisioner "shell" {
inline = [
"sudo apt-get update",
"sudo apt-get install -y ca-certificates",
]
}

# Packer recommends using a 2-step workflow for uploading files.

# 1) Upload the file to a location the provisioning user has access to.
provisioner "file" {
content = "Hello from Packer!"
destination = "/tmp/hello.txt"
}

# 2) Use the shell provisioner to move the files and set permissions.
provisioner "shell" {
inline = [
"sudo cp /tmp/hello.txt /opt/hello.txt",
"sudo chmod 0644 /opt/hello.txt",
]
}

# Reboot the instance to flush any buffered data to its storage devices.
#
# https://github.com/oxidecomputer/packer-plugin-oxide/issues/33
provisioner "shell" {
# Required so Packer doesn't error when the SSH connection terminates.
expect_disconnect = true
inline = [
"sudo reboot",
]
}
}

Don’t be alarmed with the length of this configuration. It’s meant to showcase real world use cases such as installing packages and uploading files.

If you haven’t already, initialize your Packer configuration to download and install the Oxide Packer plugin.

$ packer init oxide.pkr.hcl
Installed plugin github.com/oxidecomputer/oxide v0.3.0 in "/home/oxide/.config/packer/plugins/github.com/oxidecomputer/oxide/packer-plugin-oxide_v0.3.0_x5.0_linux_amd64"

Optionally, validate the Packer configuration to check for configuration errors.

$ packer validate oxide.pkr.hcl
The configuration is valid.

Run Packer to build the Oxide image.

$ packer build oxide.pkr.hcl
oxide-instance.example: output will be in this color.

==> oxide-instance.example: Creating Oxide instance
==> oxide-instance.example: Created Oxide instance: aba579de-251c-45c3-be6f-7fe549ca2ac0
...
==> oxide-instance.example: Creating Oxide image
==> oxide-instance.example: Created Oxide image: 502adbad-aa79-4866-8fd2-bfaa959e581e
Build 'oxide-instance.example' finished after 1 minute 37 seconds.

==> Wait completed after 1 minute 37 seconds

==> Builds finished. The artifacts of successful builds are:
--> oxide-instance.example: ubuntu-1751924554 (502adbad-aa79-4866-8fd2-bfaa959e581e)

Take note of the name and ID of the built image.

--> oxide-instance.example: ubuntu-1751924554 (502adbad-aa79-4866-8fd2-bfaa959e581e)

Launch an instance using the built image and connect to it to verify that the customizations are present.

$ ssh -l ubuntu packer-example
ubuntu@packer-example:~$ cat /opt/hello.txt
Hello from Packer!

Congratulations! You’ve successfully used the Oxide Packer plugin to build a custom Oxide image.