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.