Setting up a VM on TrueNAS Scale using cloud-init

How to use cloud-init under TrueNAS Scale to spin up preconfigured virtual machines.

Setting up a VM on TrueNAS Scale using cloud-init
Photo by SpaceX / Unsplash

1-Download a cloud-init image

https://cloud-images.ubuntu.com/releases/22.04/

Download the .img version of the latest cloud image.

2-Prepare the VM disk

Create the Zvol for the VM

Or from the command line:

zfs create -V 20G vms/cloud-init-test

Copy the cloud image into the Zvol

qemu-img convert -O raw /downloads/ISOs/ubuntu-22.04-server-cloudimg-amd64.img /dev/zvol/vms/cloud-init-test

3-Create the cloud-init seed image

Use a different system (or the same TrueNAS system if the cloud-image-utils package is installed).

Create the user-data.yaml file

#cloud-config
chpasswd:
  list: |
    ubuntu:12345
  expire: False

hostname: cloud-init-test

ssh_authorized_keys:
  - ssh-rsa AAAAB3Nza...
  - ssh-rsa AAAAB3Nza... 

Create cloud-init seed image

cloud-localds --verbose --vendor-data cloud-init-test-seed.qcow2 user-data.yaml

Copy the cloud-init seed image to TrueNAS

scp cloud-init-test-seed.qcow2 root@truenas:/mnt/vms/

4-Create the VM

Add cloud-init seed image as a CDROM

Set as order 1004 to avoid attempting to boot from the CDROM.

The same process of creating the VM and attaching the devices using the command line:

#!/bin/sh

# Create the VM
RESULT=`midclt call vm.create '{"name": "cloud_init_test", "cpu_mode": "HOST-MODEL", "bootloader": "UEFI_CSM", "threads": 2, "memory": 1024}'`

VM_ID=`echo ${RESULT} | jq '.id'`

# Add the display
midclt call vm.device.create '{"vm": '${VM_ID}', "dtype": "DISPLAY", "order": 1002, "attributes": {"web": true, "type": "VNC", "bind": "0.0.0.0", "wait": false}}'

# Obtain a random MAC address
MAC_ADDRESS=`midclt call vm.random_mac`

# Add the NIC
midclt call vm.device.create '{"vm": '${VM_ID}', "dtype": "NIC", "order": 1003, "attributes": {"type": "VIRTIO", "nic_attach": "br0", "mac": "'${MAC_ADDRESS}'"}}'

# Add the disk
midclt call vm.device.create '{"vm": '${VM_ID}', "dtype": "DISK", "order": 1001, "attributes": {"path": "/dev/zvol/vms/cloud-init-test","type": "VIRTIO"}}'

# Add the CDROM
midclt call vm.device.create '{"vm": '${VM_ID}', "dtype": "CDROM", "order": 1004, "attributes": {"path":"/mnt/vms/cloud-init-test-seed.qcow2"}}'

5-Start VM

Or using the command line:

midclt call vm.start '{"vm": '${VM_ID}'}'