Appearance
Running an unattended Ubuntu Server VM on a Talos hypervisor node: the 2 GiB cdrom limit and the netboot workaround
Talos Linux v1.15.0-alpha.2, a pre-release published on 2026-10-27, adds a hypervisor that runs virtual machines declared as VirtualMachineConfig documents in the host's machine configuration, on top of the siderolabs/libvirtd system extension. I run that build on a Mac mini Late 2012 (Intel i5-3210M, 16 GiB RAM) as a K8s-less node (cluster: {}), where the extension provides libvirtd 12.7.0 and QEMU 11.1. On 2026-11-10 I installed Ubuntu Server 26.04.1 LTS on that node as a VM named ubuntu-vm2, fully unattended, from a ~117 MB netboot mini-ISO plus a NoCloud CIDATA seed. The VM booted, took 192.168.1.131 from DHCP, and accepted ssh pas@192.168.1.131 with the ed25519 key from the seed, with password login disabled. This note records the procedure that worked and the gotchas that actually cost time, all verified live on that date.
The task, precisely
The goal was to declare the VM in the node's machine configuration, install Ubuntu Server end to end with zero interactive input, and end up with a guest that answers SSH by key, reports its IP to Talos, and offers a serial login. The constraints on this host: 16 GiB of host RAM (house rule: at most 2 VMs at a time), guest firmware limited to BIOS by the extension, K8s-less mode, one Ethernet link (enp1s0f0, up at 1 Gbps) for macvtap networking, and about 450 GiB free on the EPHEMERAL volume. All node commands below go through talosctl --nodes 192.168.1.117; the talosconfig with the admin credentials stays local and is never published.
Host prerequisites, all verified live on the node:
- Hardware virtualization:
vmxandeptCPU flags,kvm/kvm_intelmodules loaded,/dev/kvmpresent. The host is amd64 and guests need x86-64-v2 (sse4_2andpopcntare present on the i5-3210M). - Talos v1.15+ with the
siderolabs/libvirtdextension baked into the image (schematic84feec1f502dbb1340c6a832821754ae5b4386d7349e86e8ae0b862bc9148197here). After boot,ext-virtqemud,ext-virtstoraged,ext-virtlockdandext-virtlogdall report Running. talosctlv1.15+ on the Mac, because thetalosctl hypervisor ...subcommands (console, vnc, content-library, start/stop/reboot) only exist in v1.15.- Node configuration documents:
EtcFileConfigentries for/etc/passwdand/etc/group(qemu uid/gid 107, kvm gid 36), because Talos does not create those files and the libvirt extension services need the qemu user; aUserVolumeConfig+ContentLibraryConfigpair namedimagesfor ISOs and seeds; and aUserVolumeConfig+StoragePoolConfigpair namedpool1for VM disks.
Finding 1: the hypervisor works without Kubernetes
With cluster: {} in the v1alpha1 machine config (container mode), the whole VM machinery still reconciles: the content library, the storage pool and the VM documents all work without any Kubernetes API. The hidden requirement is the /etc/passwd and /etc/group entries above, because without them the ext-virt* services cannot resolve the qemu user and the VMs never start.
Finding 2: content-library files larger than 2 GiB cannot be attached as cdroms
The live-server ISO (ubuntu-26.04.1-live-server-amd64.iso, 2.7G as listed on releases.ubuntu.com) attached as a cdrom makes DomainCreateXML fail with a bare invalid argument on this host. I bisected the threshold on 2026-11-10 with a healthy host: a 3 GB zero-filled dummy file failed the same way, while a 922 kB seed ISO and disk-only VMs started fine. The failure tracks the file size at 2^31 bytes instead of the content, the labeling, or the file locks (SELinux labels and locks were ruled out), which points at a 32-bit overflow somewhere in the extension (libvirt 12.7.0 / QEMU 11.1). The workaround: never attach the big ISO directly. Boot a small netboot mini-ISO that downloads the full ISO over HTTP at boot.
Finding 3: the netboot mini-ISO that fetches the installer over HTTP
I built it on the Mac from the Ubuntu netboot tarball and syslinux:
sh
curl -LO https://releases.ubuntu.com/resolute/ubuntu-26.04.1-netboot-amd64.tar.gz
tar xzf ubuntu-26.04.1-netboot-amd64.tar.gz # -> netboot-amd64/{linux,initrd,...}
curl -LO https://mirrors.edge.kernel.org/pub/linux/utils/boot/syslinux/syslinux-6.03.tar.gz
tar xzf syslinux-6.03.tar.gz
mkdir -p mini-iso
cp netboot-amd64/linux netboot-amd64/initrd mini-iso/
cp syslinux-6.03/bios/core/isolinux.bin mini-iso/
cp syslinux-6.03/bios/com32/elflink/ldlinux/ldlinux.c32 mini-iso/mini-iso/isolinux.cfg:
text
DEFAULT install
LABEL install
KERNEL /linux
INITRD /initrd
APPEND root=/dev/ram0 ramdisk_size=7340032 ip=dhcp iso-url=https://releases.ubuntu.com/26.04.1/ubuntu-26.04.1-live-server-amd64.iso autoinstall console=ttyS0,115200n8 ---Then build the ISO with xorriso: xorriso -as mkisofs -o ubuntu-26.04.1-mini3.iso -b isolinux.bin -c boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -J -R -V UBUNTU-NETBOOT mini-iso/. The result lands at about 117 MB. The iso-url= parameter makes the netboot initrd download the full live-server ISO over HTTP into RAM and mount it as the install source.
Finding 4: the ramdisk and the VM RAM must fit the downloaded ISO
With the default ~1.5 GiB ramdisk, the kernel panics with deadlocked on memory during the netboot, because the ~2.7 GB ISO does not fit in RAM. Two fixes work together: ramdisk_size=7340032 (KiB, about 7 GiB) in the APPEND line above, and memory.size: 8GiB on the VM during the install. On a 16 GiB host that still leaves room for one more small VM, consistent with the 2-VM rule. Shrink the VM memory after the install, and only while the VM is stopped.
Finding 5: unattended means the autoinstall kernel parameter plus a CIDATA seed
Subiquity stops at a "Continue with autoinstall?" prompt unless the kernel command line carries autoinstall (see the APPEND line above). The seed is a second tiny cdrom whose volume label is exactly CIDATA and whose root holds user-data and meta-data:
sh
hdiutil makehybrid -iso -joliet -o ubuntu-vm2-seed.iso -volid CIDATA seed-dir/The sanitized user-data:
yaml
#cloud-config
autoinstall:
version: 1
identity:
hostname: ubuntu-vm2
username: pas
realname: pas
password: "$6$<your-own-sha512-crypt-hash>" # generate with: openssl passwd -6
ssh:
install-server: true
authorized-keys:
- ssh-ed25519 AAAA...<your-ed25519-public-key>...
allow-pw: false
storage:
layout:
name: direct
network:
version: 2
ethernets:
any:
match:
name: "en*"
dhcp4: true
packages:
- qemu-guest-agent
late-commands:
- curtin in-target -- sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="[^"]*"/GRUB_CMDLINE_LINUX_DEFAULT="console=ttyS0,115200n8"/' /etc/default/grub
- curtin in-target -- update-grub
- curtin in-target -- systemctl enable serial-getty@ttyS0.service
- curtin in-target -- systemctl enable qemu-guest-agent.service
- curtin in-target -- sh -c "echo 'pas ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/99-pas-nopasswd && chmod 0440 /etc/sudoers.d/99-pas-nopasswd"Three details each cost an iteration:
identity.passwordis required by subiquity since 24.04 even when SSH keys are set; the autoinstall reference states the encrypted password "is required for use withsudo, even if SSH access is configured". Generate your own hash withopenssl passwd -6and never publish it.packages: [qemu-guest-agent]is what makestalosctl get virtualmachinestatusesshow the guest IP in ADDRESSES, because Talos reads it through the guest agent channel. Without it you fall back to scanning the LAN and matching the VM MAC.- The
late-commandsenable the serial console and passwordless sudo in the installed system, sotalosctl hypervisor console ubuntu-vm2gives a login prompt after the install.
Finding 6: firmware is BIOS-only and cdroms go on the scsi bus
The libvirtd extension ships no OVMF firmware, so firmware.type: uefi fails with invalid argument; use firmware.type: bios. A cdrom on bus: sata produced EINVAL on this host; use bus: scsi. And provision.fromImage is only valid on cdrom disks, while a writable disk needs pool, size and provision.blank. The working disk layout:
yaml
disks:
- name: sys
pool: pool1
size: 40GiB
format: qcow2
bootOrder: 1
provision:
blank: {}
- name: install
type: cdrom
bus: scsi
bootOrder: 2
provision:
fromImage:
library: images
file: ubuntu-26.04.1-mini3.iso
digest: sha256:1cf59c34dfdc1a3e32909d90d9868c94a88dd75ebf43d4a75057946bd571fdbf
- name: seed
type: cdrom
bus: scsi
provision:
fromImage:
library: images
file: ubuntu-vm2-seed.iso
digest: sha256:59dd506f2738770efa1f1532a5fb43650746235d43ad06c5fc601891dadc9e1fplus cpu.count: 2, memory.size: 8GiB, firmware.type: bios, console.serial.enabled: true, console.vnc.enabled: true, one interface net0 on link: enp1s0f0 (macvtap, DHCP on the LAN), and guest.agent.enabled: true.
Finding 7: digests must match between the upload and the VM document
Upload both files with the sha256 from shasum -a 256, and reference the same digest in the VirtualMachineConfig:
sh
talosctl hypervisor content-library upload images ubuntu-26.04.1-mini3.iso \
--name ubuntu-26.04.1-mini3.iso \
--digest sha256:1cf59c34dfdc1a3e32909d90d9868c94a88dd75ebf43d4a75057946bd571fdbf
talosctl get contentlibrarystatuses # images -> ready
talosctl patch machineconfig --patch @vm-ubuntu2.yaml
talosctl get virtualmachinestatuses # ubuntu-vm2 -> running / readyThe node verifies integrity on upload. A stale digest kept by a strategic-merge patch on a list field surfaces later as digest mismatch at VM start; the fix is to edit the YAML file and re-apply the whole document instead of patching piecemeal.
Finding 8: never patch or destroy a running VM, and how I recovered a poisoned host
On 2026-11-09, destroying a running domain crashed ext-virtqemud (alpha bug), and the crash left stale /var/lib/libvirt/qemu/domain-N-* directories on EPHEMERAL. After that, every DomainCreateXML failed with a bare invalid argument, for any VM and any pool, surviving node reboots and talosctl service ext-virtqemud restart. Talos has no shell to remove those directories. The recovery that worked, verified on 2026-11-10: talosctl reset --reboot --system-labels-to-wipe EPHEMERAL, then re-create the pools and library and re-upload the files. The machine config, the PKI and the talosconfig live in the STATE partition and survive the wipe, so the node stays manageable, and a fresh disk-only VM ran immediately after. The rule of thumb: stop gracefully first (talosctl hypervisor stop <vm>), or edit the file, apply, and reboot the node.
Finding 9: consoles, and the VNC quirks
The serial console is the reliable one: talosctl hypervisor console ubuntu-vm2, ideally inside tmux so it survives disconnects. For VNC, run talosctl hypervisor vnc ubuntu-vm2 --port 5901 and point a viewer at 127.0.0.1:5901. Port 5900 is macOS Screen Sharing ("cannot control own machine" means you hit it). QEMU allows one viewer only, and a canceled stream can leave a ghost client on the node's vnc.sock that silently drops new viewers; check with talosctl read /proc/net/unix | grep vnc and restart the domain to clear it. No VNC password exists, and the tunnel listener lives until Ctrl-C. Lifecycle commands are talosctl hypervisor start|stop|reboot ubuntu-vm2. Removing the VM later is a delete patch ($patch: delete on the VirtualMachineConfig), and library files can only be deleted once no VM references them.
Key takeaways
- The Talos v1.15 hypervisor runs VMs from machine-config documents and works in K8s-less mode, provided the node has the qemu passwd/group entries plus an
imagescontent library and apool1storage pool. - On the
siderolabs/libvirtdextension build tested (libvirt 12.7.0, QEMU 11.1), any content-library file over 2^31 bytes failsDomainCreateXMLwith a bareinvalid argumentwhen attached as a cdrom, so large installer ISOs must be fetched at boot withiso-url=instead of being attached. - A fully unattended Ubuntu Server install needs the
autoinstallkernel parameter plus a CIDATA NoCloud seed; the seed also installs qemu-guest-agent (for IP reporting invirtualmachinestatuses) and enables the serial console and passwordless sudo vialate-commands. - The netboot path loads the whole ISO into guest RAM, so set
ramdisk_size=7340032and give the VM 8 GiB during the install on a 16 GiB host. - Guest firmware is BIOS-only with this extension (no OVMF), cdroms attach on
bus: scsi, and thedigestmust match between the upload and the VM document. - Stop a VM before patching or destroying it. On this alpha, a destroy crash left stale libvirt domain dirs that made every VM create fail until an EPHEMERAL wipe; STATE (machine config, PKI, talosconfig) survives that wipe.
- Two upstream issues worth reporting on siderolabs/talos: the over-2^31-byte cdrom failure and the destroy-crash/stale-dir EINVAL cascade. I searched the tracker on 2026-11-10 and found no matching issue; related merged PRs around the VM work are #14518, #14495 and #14541.
FAQ
Why not attach the full live-server ISO as a cdrom?
Files over 2^31 bytes fail with a bare invalid argument in this extension build. I confirmed the threshold with a 3 GB zero-filled dummy file, which fails the same way, so the failure tracks the size instead of the content or the labeling.
Can I boot the guest with UEFI?
The libvirtd extension bundles no OVMF, so firmware.type: uefi fails with invalid argument. Use firmware.type: bios.
How do I get the VM's IP without scanning the LAN?
Install qemu-guest-agent through the seed's packages; Talos reads the guest IPs through the agent channel and shows them in the ADDRESSES column of talosctl get virtualmachinestatuses. Fallback: nmap -sn 192.168.1.0/24 and match the VM's MAC.
Can I change the VM's RAM after the install?
Only while the VM is stopped, or by editing the file, applying, and rebooting the node. Patching a running VM's document is what crashed the host on 2026-11-09.
What survives talosctl reset --system-labels-to-wipe EPHEMERAL?
The machine config, the PKI and the talosconfig (STATE partition). Pools, libraries and VM disks live under /var on EPHEMERAL and must be re-created and re-uploaded.
Is the install really zero-touch?
Yes: with autoinstall on the kernel command line, the "Continue with autoinstall?" prompt is skipped and subiquity runs the CIDATA seed to completion. Watch it anyway over VNC or the serial console, because a wrong digest or a missing autoinstall flag fails at boot without an obvious error.
Read more
- Talos v1.15.0-alpha.2 release notes (2026-10-27)
- Talos Hypervisor overview
- Configure a virtual machine (
VirtualMachineConfig) - Upload and manage images (content library, digest pinning)
VirtualMachineConfigreference, Talos v1.15siderolabs/libvirtdsystem extension- Ubuntu 26.04.1 LTS release files: live-server ISO (2.7G), netboot tarball (112M)
- Ubuntu autoinstall configuration reference
- cloud-init NoCloud datasource
- QEMU guest agent
- Talos issue tracker
- Ensuring resilience from day one: building gzip.cloud
- How to think about backups: gzip.cloud design choices and rationales