Creating and Using Named VM Images
Golden images in Cozystack allow administrators to prepare named operating system images that users can later reuse when creating virtual machines.
This guide explains the benefits of golden images, how to create them, and how to use them when deploying VMs.
By default, every time a user creates a virtual machine, Cozystack downloads the required image from its source URL.
This can become a bottleneck when multiple VMs are created in quick succession.
Golden images solve this problem by caching the image locally, eliminating repeated downloads and speeding up deployment.
Naming Conventions (Important)
Cozystack automatically adds prefixes to internal Kubernetes resources:
| User-visible name | Resource Kind | Actual resource name |
|---|---|---|
<image> | DataVolume in cozy-public (golden image) | vm-default-images-<image> |
<disk> | DataVolume created from VMDisk | vm-disk-<disk> |
<vm> | VirtualMachine created from VMInstance | vm-instance-<vm> |
This means if you create a VMInstance named ubuntu, the VirtualMachine in Kubernetes will be vm-instance-ubuntu.
Default Image Collection (opt-in package)
Cozystack ships an optional package, vm-default-images, that provisions a curated collection of pre-built Golden Images (Ubuntu, Rocky Linux, AlmaLinux, Debian, CentOS Stream, openSUSE, Alpine) in the cozy-public namespace. The package is disabled by default and must be explicitly enabled.
Storage requirements
The default image set requests roughly 320Gi of storage (16 images × 20Gi each). Trim the image list or shrink per-image storage sizes to match your cluster capacity before enabling.The default collection includes:
| Image name | Description |
|---|---|
ubuntu-20.04 | Ubuntu 20.04 LTS (Focal Fossa) |
ubuntu-22.04 | Ubuntu 22.04 LTS (Jammy Jellyfish) |
ubuntu-24.04 | Ubuntu 24.04 LTS (Noble Numbat) |
debian-12 | Debian 12 (Bookworm) |
debian-13 | Debian 13 (Trixie) |
rocky-8 | Rocky Linux 8 |
rocky-9 | Rocky Linux 9 |
rocky-10 | Rocky Linux 10 |
almalinux-8 | AlmaLinux 8 |
almalinux-9 | AlmaLinux 9 |
almalinux-10 | AlmaLinux 10 |
centos-stream-9 | CentOS Stream 9 |
centos-stream-10 | CentOS Stream 10 |
opensuse-leap-15.6 | openSUSE Leap 15.6 |
opensuse-leap-16.0 | openSUSE Leap 16.0 |
alpine-3.21 | Alpine Linux 3.21 |
You can list all available images with:
kubectl -n cozy-public get dv -l app.kubernetes.io/managed-by=cozystack
Enable the package
Add cozystack.vm-default-images to bundles.enabledPackages in the
Platform Package:
kubectl patch packages.cozystack.io cozystack.cozystack-platform --type=json \
-p '[{"op": "add", "path": "/spec/components/platform/values/bundles/enabledPackages/-", "value": "cozystack.vm-default-images"}]'
Wait a minute for the platform chart to reconcile, then verify the HelmRelease and the DataVolumes:
kubectl get helmrelease -n cozy-system vm-default-images
kubectl -n cozy-public get dv
DataVolumes provisioned by the package are named vm-default-images-<image> and are exposed to tenants as Golden Images named <image> (e.g. ubuntu-24.04, debian-12).
Configure the image list
Override the default list by editing the cozystack.vm-default-images Package and setting values under spec.components.vm-default-images.values. The schema is defined in the chart’s
values.yaml:
storageClass— default StorageClass for all images; falls back to the cluster default when empty.images[]— list of Golden Image entries. Each entry has:name— image name as exposed to users (e.g.ubuntu-24.04).url— HTTP(S) URL of the image source.storage— storage size to allocate (e.g.20Gi).storageClass— per-image override of the global StorageClass.os.family,os.name,os.version,architecture,description— optional metadata surfaced in the UI.
Example: trim the default list down to two images and pin the StorageClass:
apiVersion: cozystack.io/v1alpha1
kind: Package
metadata:
name: cozystack.vm-default-images
spec:
variant: default
components:
vm-default-images:
values:
storageClass: replicated
images:
- name: ubuntu-24.04
url: https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
storage: 20Gi
os:
family: Linux
name: Ubuntu
version: "24.04"
architecture: amd64
description: "Ubuntu 24.04 LTS (Noble Numbat) cloud image"
- name: debian-12
url: https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2
storage: 20Gi
os:
family: Linux
name: Debian
version: "12"
architecture: amd64
description: "Debian 12 (Bookworm) generic cloud image"
To drop an image after the package is installed, remove it from images[] and delete the orphaned DataVolume:
kubectl -n cozy-public delete dv vm-default-images-<name>
Adding Custom Golden Images
Creating additional named VM images requires an administrator account in Cozystack.
The simplest way to add a custom image is by using the CLI script.
The
cdi_golden_image_create.sh script can be downloaded from the Cozystack v1.4.0 release tag:
wget https://raw.githubusercontent.com/cozystack/cozystack/v1.4.0/hack/cdi_golden_image_create.sh
chmod +x cdi_golden_image_create.sh
This script uses your kubectl configuration.
Before running it, ensure that your configuration points to the target Cozystack cluster.
To add a custom image, run the script with the image name and its URL:
cdi_golden_image_create.sh '<name>' 'https://<image-url>'
For example, to add a Talos image:
cdi_golden_image_create.sh 'talos' 'https://github.com/siderolabs/talos/releases/download/v1.7.6/nocloud-amd64.raw.xz'
Internally, the script creates a Kubernetes resource of kind: DataVolume in the cozy-public namespace.
The resource name is the image name prefixed with vm-default-images-.
For example, the resource vm-default-images-talos creates an image accessible as talos.
You can track progress with:
kubectl -n cozy-public get dv
kubectl -n cozy-public describe dv vm-default-images-talos
Using Golden Images
Creating a VMDisk from a Golden Image
To use a golden image as the source for a VM disk, create a VMDisk with source.image.name referencing the image name:
kubectl -n tenant-root create -f- <<EOF
apiVersion: apps.cozystack.io/v1alpha1
kind: VMDisk
metadata:
name: ubuntu
spec:
source:
image:
name: ubuntu-24.04
storage: 20Gi
EOF
You can monitor the process using the following commands:
kubectl -n tenant-root get vmdisk
kubectl -n tenant-root get dv
kubectl -n tenant-root describe dv vm-disk-ubuntu
Attaching the Disk to a VM
Next, create a VMInstance that uses the disk:
kubectl -n tenant-root create -f- <<EOF
apiVersion: apps.cozystack.io/v1alpha1
kind: VMInstance
metadata:
name: ubuntu
spec:
disks:
- name: ubuntu
EOF
You can check the status of the VirtualMachine with:
kubectl get vm -n tenant-root
To connect to the VM, run:
virtctl console vm-instance-ubuntu -n tenant-root