Building a Gentoo Minimal LiveCD with ZFS support

2013-12-18 21:51 - Linux

Background

I've been using Gentoo for 20 years or more (I mention it in a post from 2004). I've been using encrypted drives for at least 15 of those years, and ZFS almost as long. I first wrote this post in 2013 (as the date above shows), before ZFS native encryption was a thing. (See earlier versions of this post at archive.org.)

So for the last decade plus, ZFS-on-LUKS is just how I've done things. I want to have a live ISO I can use to boot the ZFS-on-LUKS machines I already have, for recovery scenarios. (E.g. "Whoops, that new kernel I built doesn't boot the machine!") I have large existing data sets that I don't want to migrate. This is how I make the Gentoo live ISOs I use, for recovery of (and more rarely anymore, installation of) my Gentoo systems using LUKS encryption to host a root ZFS drive. Since early 2023 (per the wiki history) the Catalyst/Custom Media Image page has documented almost exactly this process. You might want to follow that. Or just use the gentoo LiveGUI ISO instead, which does (last I checked) come with ZFS built in. (But is over 3GiB.)

This post is oriented around making my live ISO. As slim as possible to get the job done, for me and my hardware. Being able to quickly attach my ISO as a virtual drive to a remote server, via slow IPMI, is of value to me. So I trim out everything I don't need. (And add in a few small helpful tools.)

How To

We need the releng (release engineering) tools, which are used by Catalyst. Catalyst is the tool that builds several low level Gentoo artifacts including the bootable ISO.

The catalyst process for building the ISO is split into two stages or phases. Let's prepare some prerequisites, and start stage one.

# emerge-webrsync
# echo 'dev-util/catalyst ~amd64' > /etc/portage/package.accept_keywords/catalyst
# emerge --autounmask-write dev-vcs/git catalyst pixz
# dispatch-conf
# emerge dev-vcs/git catalyst pixz
# cd /root
# git clone https://github.com/gentoo/releng.git

Due do the dependency tree involved, this step takes at least 15 minutes. (I wrote this from commit 6c41968d6bd47c99498f82c263feb9a37de9f431. If you're playing along, consider starting there.)

We need a stage file for a starting point, just like when installing Gentoo. Open Gentoo's downloads page. Use the amd64 stage3 URL found there in the wget step.

# mkdir -p /var/tmp/catalyst/builds/23.0-default
# wget https://.../stage3-amd64-....tar.xz -O /var/tmp/catalyst/builds/23.0-default/stage3-amd64-openrc.tar.xz

Before we start the long running parts, to make this as fast as is practical be sure to:

If you're using a small VM like me, picking values here that don't cause OOM crashes might be tricky. In the past, I've found that found 4G ram plus 1G swap was not enough. This depends on the settings you used above for parallelism and which packages you include/exclude.

Additionally we create a portage snapshot, which is based on the emerge-webrsync from above.

# catalyst --snapshot stable
# TREEISH="$(ls -t /var/tmp/catalyst/snapshots/*.sqfs | head -n 1 | cut -b 36-75)"
# echo $TREEISH
e64612f87c9646c567552eebde09a0395e171a66
# DATESTAMP="$(date '+%Y%m%d')"
# echo $DATESTAMP
20241218

Catalyst Stage 1

# cat > common.sed <<EOF
> s#@REPO_DIR@#/root/releng#g
/version_stamp:/s#:.*#: $DATESTAMP.zfs#
s/@TIMESTAMP@/$DATESTAMP/
s/@TREEISH@/$TREEISH/
EOF
# cat > stage1.sed <<EOF
> # Match the downloaded stage name we used.
s#source_subpath: .*#source_subpath: 23.0-default/stage3-amd64-openrc#

# Skip use flags.
/	alsa/d
/	portaudio/d
/	socks5/d
/	xml/d
# Skip packages I don't need/plan to use.
/app-accessibility/d
/app-admin/d
/app-crypt/d
/app-editors/d  # Add vim instead below.
/amm-misc.tmux/d
/app-text.wgetpaste/d
/media-/d
/net-dialup/d
/net-fs/d
/net-irc/d
/net-misc.vconfig/d
/net-proxy/d
/net-wireless/d
/sys-block.partimage/d
/sys-firmware/d
/sys-fs.b/d
/sys-fs.dmraid/d
/sys-fs.jfs/d
/sys-fs.mac/d
/sys-fs.mdadm/d
/sys-fs.multipath/d
/sys-fs.ntfs/d
/sys-fs.reiser/d
/sys-fs.xfs/d
/sys-kernel.linux-firmware/d

# Add extra packages useful in recovery scenarios.
/livecd.packages/ {
  a	app-editors/vim
  a	net-analyzer/netcat
  a	net-analyzer/mtr
  a	net-analyzer/nmap
  a	net-analyzer/tcpdump
  a	net-dns/bind-tools
  a	sys-apps/hwinfo
  a	sys-apps/smartmontools
  a	sys-process/htop
}
EOF
# cp releng/releases/specs/amd64/installcd-stage1.spec .
# sed -f stage1.sed -i installcd-stage1.spec
# sed -f common.sed -i installcd-stage1.spec

We're going to need lvm2 (included by default in the stage 1 spec). It's where the device mapper tools come from, which we need for interacting with the LUKS wrapper disks. However by default the thin use flag is enabled which causes a tree of dependencies that includes (at time of writing) both llvm-core/llvm-18.1.8-r6 and llvm-core/llvm-19.1.4. Each take a long long time to compile, and tend to OOM my little VM. Since I don't want the features this provides, before running catalyst (so before it copies this file into the chroot) I edit releng/releases/portage/isos/package.use/lvm to specify -thin instead.

# catalyst -f installcd-stage1.spec 

This step creates a new chroot and then effectively sets up an entire Gentoo install there. This will emerge about 125 (all changes above) to nearly 200 packages (by default), it takes quite a while. (My time: just over 100 minutes.)

Catalyst stage 2

# cat > stage2.sed  <<EOF
> s/.iso$/.zfs.iso/
/source_subpath/s/livecd-stage1-amd64-latest/livecd-stage1-amd64-@TIMESTAMP@.zfs/
/livecd.volid/s/:.*/: gentoo-@TIMESTAMP@-zfs/

# Rename the iso.
/livecd.iso/s/install/gentoo/

# Add the ZFS package!  (Replacing the broadcom firmware package.)
/boot.kernel.gentoo.packages:/s/:.*/: sys-fs/zfs/

# Remove dracut options we've excluded in stage1.
/dracut_args/{
  s/-a mdraid //
  s/-o btrfs //
}
EOF
# cp releng/releases/specs/amd64/installcd-stage2-minimal.spec .
# sed -f stage2.sed -i installcd-stage2-minimal.spec
# sed -f common.sed -i installcd-stage2-minimal.spec
# catalyst -f installcd-stage2-minimal.spec

This extracts the image file built in stage one, builds the kernel, cleans up to reduce ISO size, then creates the final ISO image (my time: around 95 minutes), which will be located at /var/tmp/catalyst/builds/23.0-default/gentoo-amd64-minimal-$DATESTAMP.zfs.iso. You're done!

Finally, I'm making the fully built ISO image I created available for download. See this salient note on licensing. See comments below for the most up-to-date version.

Comments:

zfs on linux
2019-12-30 00:33 - kimux

Does this ISO support UEFI startup?

New Build
2020-06-06 20:14 - arantius

ZFS 0.8 reached stable some time ago. Here's an updated install CD image, built with ZFS 0.8.3: gentoo-install-amd64-minimal-20200605.zfs.iso. Its MD5 is 79a70df3956da193a73f220535a74157 and SHA1 is 37b960b58df5620919f3671e45d27516906ce2b3.

(And, belatedly: I don't know if it supports UEFI. I think that's a complicated topic, requiring support at many layers.)

New build, ZFS 2.0
2021-07-15 22:13 - arantius

ZFS 2.0.5 stabilized this month, the first 2.0.x to do so. Here's a new installer image, built with ZFS 2.0.5:

gentoo-install-amd64-minimal-20210715.zfs.iso MD5: 2351c88542acb851a14c75fe6c341656 SHA1: 86622ec0cd4d3ac0cd5df75be3ff1c5222df5966

New Build
2023-04-28 09:13 - arantius

Here's a new build again. This time it's ballooned to 561 meg (!). It has kernel version 6.1.19 and ZFS version 2.1.9.

MD5: 8f9a122aaab83ab5a27f30d9e4b4b8e2 SHA1: 3e9aa327d591d5f4c0b06c048aadc60c63e2bad5

New build with ZFS 2.2.5
2024-12-18 12:17 - arantius

I've rewritten the above post. It focuses now not just on supporting LUKS+ZFS, but doing so with a small ISO. This one is 271 MiB. Excluding wireless network support and linux-firmware seems to account for most of that savings (relative to the previous ISO, over twice the size). Here's the latest version:

Post a comment:

Username
Password
  If you do not have an account to log in to yet, register your own account. You will not enter any personal info and need not supply an email address.
Subject:
Comment:

You may use Markdown syntax in the comment, but no HTML. Hints:

If you are attempting to contact me, ask me a question, etc, please send me a message through the contact form rather than posting a comment here. Thank you. (If you post a comment anyway when it should be a message to me, I'll probably just delete your comment. I don't like clutter.)