IMAGE-GARDEN(1)

πŸ“¦
version 0.4.2 Β· 3 versions
, in ubuntu resolute, ubuntu stonking

πŸ’– IMAGE-GARDEN(1) β€” the manual, but make it slay πŸ’–

local · untitled · bestie edition ✨

okay so. <rainbow>image-garden</rainbow> is a whole entire tool for constructing and operating test virtual machines, and ngl it eats. It's from the <pink>LOCAL</pink> manual section, it's filed under <purple>UNTITLED()</purple> (iconic of it tbh), and this is the page that tells you literally everything. Let's go πŸ’…


✨ NAME ✨

image-garden β€” construct and operate test virtual machines πŸ–₯️🌸


✨ SYNOPSIS ✨

image-garden make [-n] [GOAL]
image-garden allocate [--premade] [--nice] SYSTEM.ARCH
image-garden rebase SYSTEM.ARCH
image-garden discard ADDRESS
image-garden version
image-garden news N
image-garden download-with-sha512sums URL [SHA512SUMS_URL
             [DIRECTORY_PREFIX [FILENAME]]]
image-garden download-with-sha256sums URL [SHA256SUMS_URL
             [DIRECTORY_PREFIX [FILENAME]]]
image-garden download-with-sha256sum URL [SHA256SUM [DIRECTORY_PREFIX
             [FILENAME]]]
image-garden download URL [DIRECTORY_PREFIX [FILENAME]]

like. look at all those sub-commands. she's versatile πŸ’–


✨ DESCRIPTION ✨

So image-garden downloads, initializes, and optionally operates virtual machine images for a bunch of popular operating systems. πŸ¦‹

Every single system in here is built for testing, and they all come pre-configured with a well-known username and password β€” which usually matches the name of the system. iykyk. πŸ”‘


options that image-garden make recognizes

  • -n β€” Display commands instead of actually executing them. This one is genuinely so useful if you're trying to learn how individual disk images get made. Like, it shows you the receipts instead of doing the thing. πŸ‘€

options that image-garden allocate recognizes

  • --premade β€” Assume pre-made disk images are already sitting there and do not re-generate them, even if they're out-of-date. This is the move for making sure your CI/CD jobs don't re-build disk images just because some timestamps are acting like they know something. β°πŸ’€
  • --nice β€” Wraps the execution of virtual machines with nice, so it doesn't fight other applications for CPU. Bestie behaviour fr fr 🫢. This is implicitly set when XDG_SESSION_TYPE is either wayland or x11.

πŸŽ€ Make Goals πŸŽ€

The image-garden make sub-command lets you build one or more goals corresponding to virtual machine images and their support files. very build-a-bear of her πŸ’–

Here are the documented goals. Heads up: ARCH and SYSTEM are placeholders β€” ARCH is a CPU architecture as named by the Linux kernel, and SYSTEM is a standardized distribution name. For the complete list of valid SYSTEM-ARCH combos, please see the table. πŸ“‹

  • help β€” Display a help message specific to the set of make rules contained within image-garden.
  • all β€” Build all of the images for the native CPU architecture. everything. the whole closet. πŸ‘‘
  • fetch β€” Fetch all the base cloud images or installers, so that further work can be done mostly offline. The only exception is installation if packages described by per-project cloud-init profiles. πŸ“₯
  • clean β€” Remove all the generated disk images from the current directory. bye bye 🧹
  • distclean β€” Remove all the base cloud images and installer images from the per-user cache directory. the deep clean 😭
  • $SYSTEM.$ARCH.qcow2 β€” qemu disk image of operating system $SYSTEM for CPU architecture $ARCH. Cloud disks contain an internal reference to the base image stored in the per-user cache directory. Both files are required at runtime. ⚠️
  • $SYSTEM.$ARCH.qcow2.log β€” Serial console output collected during the first boot of the machine. the birth vlog πŸ“Ό
  • $SYSTEM.$ARCH.run β€” Shell script for running the virtual machine. This script supports extensive customization through environment variables and command line arguments. Command line arguments are passed directly to image-garden qemu-system-$ARCH. The recognized environment variables are described in a dedicated section below. πŸ”§
  • $SYSTEM.$ARCH.efi-code.img β€” Symbolic link to efi-code.$ARCH.img.
  • $SYSTEM.$ARCH.efi-vars.img β€” Disk image with the current state of the boot firmware corresponding to $SYSTEM.$ARCH.qcow2.
  • $SYSTEM.$ARCH.seed.iso β€” ISO 9660 disk image with cloud-init files used during first boot.
  • $SYSTEM.$ARCH.user-data β€” Text of the cloud-init user data. This file exists briefly as a prerequisite for $SYSTEM.$ARCH.seed.iso.
  • $SYSTEM.$ARCH.meta-data β€” Text of the cloud-init meta data. This file exists briefly as a prerequisite for $SYSTEM.$ARCH.seed.iso.
  • efi-code.riscv64.img β€” Disk image of EFI firmware for riscv64 CPU architecture.
  • efi-vars.riscv64.img β€” Disk image with the unmodified state of EFI firmware for the riscv64 CPU architecture.
  • efi-code.aarch64.img β€” Disk image of EFI firmware for aarch64 CPU architecture.
  • efi-vars.aarch64.img β€” Disk image with the unmodified state of EFI firmware for the aarch64 CPU architecture.
  • efi-code.x86_64.img β€” Disk image of EFI firmware for the x86_64 CPU architecture.
  • efi-vars.x86_64.img β€” Disk image with the unmodified state of EFI firmware for the x86_64 CPU architecture.

🌸 System Names 🌸

Systems are identifiers for a particular operating system, variant, release and CPU architecture. The following list contains all the systems recognized by image-garden. get comfy, it's a long one πŸ›‹οΈβœ¨

  • almalinux-cloud-{8,9,10} β€” Alma Linux cloud images.
  • alpine-cloud-3 β€” Alpine Linux cloud image.
  • amazonlinux-cloud-{2,2023} β€” Amazon Linux cloud images.
  • archlinux-cloud β€” Arch Linux cloud image. This system is only supported on the x86_64 CPU architecture. btw 🫢
  • centos-cloud-{9,10} β€” CentOS cloud images (usually CentOS stream).
  • debian-cloud-{10,11,12,13,sid} β€” Debian cloud images.
  • fedora-cloud-{38,39,40,41,42,43} β€” Fedora cloud images. Fedora 42, only, is also supported on the riscv64 CPU architecture. Fedora 42 and 43 are also supported on the s390x CPU architecture. πŸŒ€
  • opensuse-cloud-{15.4,15.5,15.16,tumbleweed} β€” openSUSE cloud images.
  • oracle-cloud-{7,8,9} β€” Oracle Linux cloud images. Oracle Linux 7 is only supported on the x86_64 CPU architecture.
  • rocky-cloud-{8,9} β€” Rocky Linux cloud images.
  • ubuntu-cloud-{14,16,18,20,22,24,26}.04 β€” Ubuntu Long Term Support (LTS) cloud images. 🧑
  • ubuntu-cloud-{25.04,25.10} β€” Ubuntu development releases cloud images. Ubuntu 24.04, 25.04 and 25.10 are also supported for riscv64 CPU architecture. Ubuntu 18.04, 20.04, 22.04, 24.04, 25.04, 25.10 and 26.04 are also supported for s390x CPU architecture. Ubuntu 14.04, 16.04, 18.04, 20.04, 22.04, 24.04, 25.04, 25.10 and 26.04 are also supported for ppc64 CPU architecture.
  • ubuntu-core-{16,18,20,22,24} β€” Ubuntu Core images. Core 16, 18 and 20 are only supported on the x86_64 CPU architecture.

πŸ¦‹ FILES πŸ¦‹

  • .image-garden β€” Sub-directory containing all image, log and lock files. If this directory does not exist, then all such files are placed in the directory where image-garden is invoked from. πŸ—‚οΈ
  • .image-garden.mk β€” Makefile implicitly included by image-garden make. This file is designed for defining cloud-init user-data templates with project-specific build and test dependencies.
  • $HOME/.cache/image-garden/dl β€” Directory with downloaded, unmodified virtual machine images. The files are organized into sub-directories specific to each distribution. Inside, symbolic links provide a unified naming scheme regardless of the naming scheme used by a particular distributor. πŸ”—

🌱 ENVIRONMENT 🌱

okay bestie, so like β€” the env vars are split into little sections so you know which sub-command is actually out here reading them. very organized, very demure πŸ’…


✨ Environment for image-garden make ✨

  • XDG_CACHE_HOME β€” the directory holding your per-user cache files that you can delete whenever, no biggie, they're safe to yeet. Per the spec, the default is "$HOME/.cache".
  • GARDEN_CACHE_DIR β€” the directory with non-essential files that get reused across different projects. Default is "$XDG_CACHE_HOME/image-garden"… except when it's running as a snap, where the default becomes "$SNAP_USER_COMMON/cache".
  • GARDEN_DL_DIR β€” where the downloaded OS images live. These can be big, so please be mindful and don't gobble up your whole disk. Every image in here is used in read-only mode and gets automatically shared between the different projects made by the same user. Default is "$GARDEN_CACHE_DIR/dl".
  • QEMU_ENV_QUIRKS β€” a list of environment variables to set before qemu gets invoked. This exists so you can say stuff like "this system literally cannot boot with a virtio disk, it needs SCSI disks instead."
  • QEMU_MEM_SIZE β€” how much memory, in megabytes, each virtual machine gets. This value gets copied straight into the generated $SYSTEM.run scripts. Default is "2048" (that's 2GB of runtime memory). ⚠️ do not confuse it with the similarly-named QEMU_MEM_OPTION.
  • QEMU_IMG_SIZE β€” the size of the virtual disk image that qemu-img(1) creates when it's called from image-garden. Default is "64G". heads up: these images use a format with an internal representation of sparse areas, so the actual disk space needed is way smaller than this number. 🫢
  • QEMU_SMP_X86_64 β€” number of virtual CPU cores for VMs emulating the x86_64 CPU architecture. Default is "4" when the host and guest CPU architectures match, or "1" otherwise. And ngl, don't confuse it with the similarly-named QEMU_SMP_OPTION.
  • QEMU_SMP_AARCH64 β€” number of virtual CPU cores for VMs emulating the aarch64 CPU architecture. Default is "4" when host and guest CPU architectures match, or "1" otherwise. Again: not the same as QEMU_SMP_OPTION, bestie.
  • QEMU_SMP_RISCV64 β€” number of virtual CPU cores for VMs emulating the riscv64 CPU architecture. Default is "4" when host and guest CPU architectures match, or "1" otherwise. Yes, same warning: not to be confused with QEMU_SMP_OPTION. 😭
  • QEMU_SYSTEM_X86_64 β€” full path of the qemu-system-x86_64 program to use instead of whatever one is found on PATH.
  • QEMU_SYSTEM_AARCH64 β€” full path of the qemu-system-aarch64 program to use instead of the one found on PATH.
  • QEMU_SYSTEM_RISCV64 β€” full path of the qemu-system-riscv64 program to use instead of the one found on PATH.
  • QEMU_CPU_RISCV64 β€” the virtual CPU type to use for systems on the riscv64 CPU architecture. Default is max.
  • QEMU_CPU_X86_64 β€” the virtual CPU type for systems on the x86_64 CPU architecture. Default is max.
  • QEMU_CPU_AARCH64 β€” the virtual CPU type for systems on the aarch64 CPU architecture. Default is max. But the amazonlinux-cloud-2 and amazonlinux-cloud-2023 systems use the value neoverse-n1 instead. 🌸
  • QEMU_IMG β€” full path of the qemu-img program to use instead of the one found on PATH.
  • MKPASSWD β€” full path of the mkpasswd program to use instead of the one found on PATH.
  • XORRISO β€” full path of the xorriso program to use instead of the one found on PATH.
  • WGET β€” full path of the wget program to use instead of the one found on PATH.

✨ Environment for image-garden allocate ✨

  • XDG_RUNTIME_DIR β€” directory with per-user runtime files that do not survive a reboot. Per the spec, the default is "/run/user/$UID". When image-garden is used as a back-end for the spread(1) test system, it uses this directory to keep track of running virtual machines and their TCP port numbers. 🧚
  • QEMU_SNAPSHOT_OPTION β€” overrides the in-memory snapshot option. Set it to the empty string if you want to allocate a machine that persists all its changes on disk. (yes, this is the "commit to it" switch πŸ’€)

✨ Environment for .run scripts. ✨

The following environment variables are used by the generated .run scripts. πŸ‘‘

  • QEMU_MEM_OPTION β€” memory configuration options passed to qemu. An example value is "-m 1024".
  • QEMU_SMP_OPTION β€” CPU topology options passed to qemu. When it's unset, the default value is "-smp $QEMU_SMP_$(uname -m)". An example value is "-smp $(nproc)".
  • QEMU_DISPLAY_OPTION β€” graphical display options passed to qemu. When unset, the default value is "-nographic". An example value is "-display gtk".
  • QEMU_BOOT_FIRMWARE_OPTION β€” boot firmware options passed to qemu. The default value depends on what the booted system requires. For systems booting with EFI, a pair of "-drive pflash" arguments is used to represent EFI code and EFI variables. For systems booting with legacy BIOS, no options are provided at all.
  • QEMU_RNG_OPTION β€” random-number configuration options passed to qemu. When unset, the default value is "-device virtio-rng-pci".
  • QEMU_NET_OPTION_X86_64
  • QEMU_NET_OPTION_AARCH64
  • QEMU_NET_OPTION_RISCV64 β€” network configuration options passed to qemu. When unset, the default value is:
-netdev user,id=netdev0${QEMU_NETDEV_USER_EXTRA:-} -device virtio-net-pci,netdev=netdev0,id=net0

For x86_64 and aarch64 CPU architectures the value also includes the suffix:

-smbios type=41,designation=Virtual-LAN,instance=1,kind=ethernet,pcidev=net0

🌈 EXAMPLES 🌈

Wanna make a bootable image of the cloud variant of Debian 13 (trixie) for the x86_64 architecture? say less:

image-garden make debian-cloud-13.x86_64.run

To use image-garden together with spread(1), drop this little snippet into your spread.yaml file. And psst β€” using exec lets image-garden automatically do the equivalent of calling the spread shell functions ADDRESS, FATAL or ERROR. iconic behaviour honestly:

backends:
  garden:
    type: adhoc
    allocate: exec image-garden allocate "$SPREAD_SYSTEM"."$(uname -m)"
    discard: exec image-garden discard "$SPREAD_SYSTEM_ADDRESS"
    systems:
      - debian-cloud-13:
          username: debian
          password: debian

To customize the virtual machine for a particular project, create a .image-garden.mk file at the root of the project and define one or more cloud-init user-data templates containing the list of packages to install or commands to run. Just make sure you include the default template, because it is essential for image-garden to actually work. You can assume the default template ends with a section that runs one or more commands, and you can append your commands as a YAML list. Any other cloud-init features have to be used explicitly. no shortcuts bestie πŸ’…

# Cloud-init template for Debian 13 (Trixie).
define DEBIAN_13_CLOUD_INIT_USER_DATA_TEMPLATE
$(CLOUD_INIT_USER_DATA_TEMPLATE)
packages:
- build-essential
- libfoo-dev
endef
# Cloud-init user-data template for all versions of Ubuntu.
define UBUNTU_CLOUD_INIT_USER_DATA_TEMPLATE
$(CLOUD_INIT_USER_DATA_TEMPLATE)
packages:
- build-essential
- libfoo-dev
endef

πŸ¦‹ SEE ALSO πŸ¦‹


πŸ“œ HISTORY πŸ“œ

Image garden was developed in stages throughout late 2023, with the first commits showing up in early 2024. a little glow-up arc, we love to see it ✨


πŸ’€ BUGS πŸ’€

You can browse the known bugs by looking at the GitLab issues: https://gitlab.com/zygoon/image-garden/-/issues.


πŸ‘‘ AUTHORS πŸ‘‘

Zygmunt Krynicki <me@zygoon.pl>


and that's the whole page, bestie!! πŸŽ€ this is image-garden version 0.4.2, dated Jan 19, 2026 β€” go forth and garden those images, you absolute main character 🫢✨

πŸ“¦ where this page comes from