Technical Guide: The Golden Image Strategy

Technical Guide: The Golden Image Strategy

Don’t install Gentoo. Clone it.

The Concept

Installing Gentoo takes hours. Cloning a disk image takes minutes.

Most people think a “golden image” means a fully-loaded system with everything pre-installed. Apps, configs, desktop environments, the works. That’s wrong—at least for my use case.

My golden image is bare bones. It’s a Stage 3 tarball with SSH, networking, and a working Portage configuration. That’s it.

Why Minimal?

The golden image isn’t the destination. It’s the starting point.

What’s IN the golden image:

  • Base Gentoo (Stage 3)
  • Networking (dhcpcd or NetworkManager)
  • SSH server (for remote access)
  • Portage configured to pull from my binhost
  • Btrfs filesystem with proper subvolume layout
  • GRUB or EFISTUB bootloader (depending on target)

What’s NOT in the golden image:

  • Desktop environment
  • Applications
  • User accounts (except root)
  • Custom configs

Why? Because different machines need different things.

My desktop needs KDE Plasma, NVIDIA drivers, and gaming tools. My build drones need only compilation tools. My Tau-Ceti-Lab needs both—plus the ability to wipe and reinstall quickly.

If I put everything in the golden image, it becomes a bloated mess that’s slow to clone and hard to maintain. Instead, I keep it minimal and let each machine pull what it needs from the binhost.

Clone time: 30 seconds for the golden image. Customization time: 5-15 minutes to pull binary packages for the role.


The Architecture

We maintain a “Golden Image” in a VM. This VM is the “Source of Truth” for the base distribution state.

┌─────────────────────────────────────────────────────────────┐
│                    GOLDEN IMAGE VM                          │
│                    (gentoo-golden.qcow2)                    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  What's Inside:                                             │
│  ├── Base Gentoo (Stage 3)                                  │
│  ├── /etc/portage/ (binhost configured)                     │
│  ├── SSH server (remote access)                             │
│  ├── Btrfs subvolumes (@, @home, @snapshots)                │
│  └── Bootloader (GRUB or EFISTUB)                           │
│                                                             │
│  What's NOT Inside:                                         │
│  ├── Desktop environment                                    │
│  ├── Applications                                           │
│  ├── User accounts                                          │
│  └── Machine-specific configs                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

                         │ Clone

┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│   Desktop    │  │  Build Drone │  │   Tau-Ceti-Lab    │
│              │  │              │  │              │
│ + KDE Plasma │  │ + GCC/Clang  │  │ + Everything │
│ + NVIDIA     │  │ + emerge     │  │ + Wipe often │
│ + Firefox    │  │ + distcc     │  │              │
└──────────────┘  └──────────────┘  └──────────────┘

Creating the Image

We use QEMU/KVM with a qcow2 backing file.

# Create the disk image
qemu-img create -f qcow2 gentoo-golden.qcow2 64G

# Create the VM (using virt-manager or virsh)
virt-install \
  --name gentoo-golden \
  --memory 4096 \
  --vcpus 4 \
  --disk path=gentoo-golden.qcow2,format=qcow2 \
  --cdrom /path/to/gentoo-minimal.iso \
  --os-variant gentoo \
  --network network=default

Then we install Gentoo normally into this VM once.

The Installation Checklist

Partitioning (GPT + UEFI):

/dev/vda1  512MB   EFI System Partition (FAT32)
/dev/vda2  8GB     Swap
/dev/vda3  rest    Btrfs (root)

Btrfs Subvolumes:

mount /dev/vda3 /mnt/gentoo
cd /mnt/gentoo

btrfs subvolume create @
btrfs subvolume create @home
btrfs subvolume create @snapshots
btrfs subvolume create @var-cache
btrfs subvolume create @var-log

Critical make.conf settings:

# /etc/portage/make.conf

# Binary packages from binhost
FEATURES="getbinpkg binpkg-multi-instance"
PORTAGE_BINHOST="ssh://[email protected]/var/cache/binpkgs/stable"

# USE flags (minimal for golden image)
USE="-X -gtk -qt5 -qt6 -kde -gnome"
USE="${USE} bash-completion vim-syntax"

# Accept ~amd64 for fresh packages
ACCEPT_KEYWORDS="~amd64"

Note the -X -gtk -qt5 -qt6 -kde -gnome flags. The golden image doesn’t have a GUI. Machines that need one will override these when they pull packages.


Maintenance Workflow

The golden image needs occasional updates. Here’s the process:

# 1. Boot the VM
virsh start gentoo-golden

# 2. SSH in
ssh root@gentoo-golden

# 3. Sync Portage
emerge --sync

# 4. Update (binaries from binhost)
emerge --update --deep --newuse --usepkg --getbinpkg @world

# 5. Clean cruft
emerge --depclean
eclean-dist
eclean-pkg

# 6. Zero-fill free space (enables better compression)
dd if=/dev/zero of=/zeros bs=1M 2>/dev/null; rm /zeros

# 7. Shutdown
shutdown -h now

Then on the host:

# 8. Compress the image
qemu-img convert -O qcow2 -c gentoo-golden.qcow2 gentoo-golden-$(date +%Y%m%d).qcow2

# 9. Keep the dated backup
mv gentoo-golden-$(date +%Y%m%d).qcow2 /backups/golden-images/

I do this monthly, or after major Portage changes.


Deployment Methods

How do we get a VM image onto a physical SSD?

Method 1: Clonezilla

The “safe” option. Boot Clonezilla, restore image, done.

Pros: GUI, handles partitions automatically Cons: Slow, requires USB boot, clunky

Method 2: DD over SSH (The Dangerous Way)

Fast, elegant, terrifying.

# On host machine (with the image)
qemu-img convert -f qcow2 -O raw gentoo-golden.qcow2 stdout | \
  ssh root@target-machine "dd of=/dev/nvme0n1 bs=4M status=progress"

Warning: This will obliterate whatever is on /dev/nvme0n1. No confirmation, no undo.

Pros: Fast (limited by network speed), no USB needed Cons: Requires target to be booted into a live environment with SSH

Method 3: Rsync (The Preferred Way)

Since we use Btrfs, we can sync file contents instead of raw blocks. This handles partition sizing better.

# On target machine (booted from live USB)

# 1. Partition the target drive
gdisk /dev/nvme0n1
# Create: 512MB EFI, 8GB swap, rest Btrfs

# 2. Format
mkfs.fat -F32 /dev/nvme0n1p1
mkswap /dev/nvme0n1p2
mkfs.btrfs /dev/nvme0n1p3

# 3. Create subvolumes
mount /dev/nvme0n1p3 /mnt
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@snapshots
umount /mnt

# 4. Mount properly
mount -o subvol=@ /dev/nvme0n1p3 /mnt
mkdir -p /mnt/{boot/efi,home,.snapshots}
mount -o subvol=@home /dev/nvme0n1p3 /mnt/home
mount /dev/nvme0n1p1 /mnt/boot/efi

# 5. Rsync from golden image VM
rsync -aAXv --exclude='/sys/*' --exclude='/proc/*' --exclude='/dev/*' \
  --exclude='/tmp/*' --exclude='/run/*' --exclude='/mnt/*' \
  root@gentoo-golden:/ /mnt/

# 6. Chroot and fix bootloader
arch-chroot /mnt
grub-install --target=x86_64-efi --efi-directory=/boot/efi
grub-mkconfig -o /boot/grub/grub.cfg
exit

# 7. Unmount and reboot
umount -R /mnt
reboot

Pros: Target drive can be different size, proper subvolume creation, no raw block concerns Cons: More steps, requires live environment with rsync


Post-Clone Customization

After cloning, each machine needs role-specific setup:

For a Desktop:

# Pull desktop packages (binaries from binhost)
emerge --usepkg --getbinpkg kde-plasma/plasma-meta
emerge --usepkg --getbinpkg www-client/firefox
emerge --usepkg --getbinpkg x11-drivers/nvidia-drivers

# Add user
useradd -m -G wheel,video,audio commander
passwd commander

# Enable services
rc-update add sddm default
rc-update add elogind boot

For a Build Drone:

# Pull build tools only
emerge --usepkg --getbinpkg sys-devel/gcc sys-devel/binutils

# Configure as drone
# (copy build-swarm drone service)

For Tau-Ceti-Lab:

# Pull everything - it's a test machine
emerge --usepkg --getbinpkg @world

The Philosophy

The golden image is infrastructure, not a product.

It’s the Gentoo equivalent of a container base image. You don’t ship ubuntu:latest to production—you build on top of it. Same principle here.

By keeping the golden image minimal:

  • Cloning is fast (30 seconds)
  • Maintenance is simple (one small image to update)
  • Flexibility is maximized (each machine gets what it needs)
  • Storage is efficient (no duplicate desktop environments)

The binhost does the heavy lifting. The golden image just gets machines to a point where they can reach the binhost.


This post is part of the Argo OS Technical Guides series.