-
Notifications
You must be signed in to change notification settings - Fork 93
Building in Containers
ZFSBootMenu is developed primarily on Void Linux. It is guaranteed to work well with the tools provided therein and is officially packaged for the distribution. On other distributions, the experience is not always as smooth. System packages for ZFSBootMenu or its requirements may be missing entirely. Tooling may be outdated and missing features that ZFSBootMenu uses to provide an enhanced user experience. (Where possible, ZFSBootMenu will test for features and work around their absence.) Fortunately, the proliferation of Linux containers provides a means to work around limitations of particular distributions and provide all users with first-class ZFSBootMenu support.
ZFSBootMenu provides a build container image,
ghcr.io/zbm-dev/zbm-builder, based on a Void Linux image that uses an LTS
kernel and relatively recent version of ZFS. When run, the container entrypoint
will:
-
Fetch a specified or default version of the ZFSBootMenu source repository (or use a local copy that is bind-mounted into the container)
-
Perform an "installation" of this repository into the container instance
-
Optionally run some scripts to customize the container instance
-
Merge default and build-specific ZFSBootMenu configurations
-
Produce a ZFSBootMenu image
To facilitate interaction with the host, the container should be run with a build directory (along with the output directory, if it is not a child of the build directory) bind-mounted into the container.
The zbm-builder.sh helper script provides a simplified
frontend for control of ZFSBootMenu build containers. The script coordinates
volume mounts necessary to read configurations from and write output to the
host and ensure host data (the hostid and ZFS pool cache) are passed through.
The script also supports a simple configuration file that allows options to be
recorded for repeated use.
zbm-builder.sh mounts a build directory (by default, the current working
directory) into the container to provide a path to inject custom configuration
into the container. If the system will manage ZFSBootMenu images exclusively
via a build container, an obvious location for the build directory is
/etc/zfsbootmenu. Start by creating this directory and populating a simple
config.yaml for container builds:
mkdir -p /etc/zfsbootmenu
cat > /etc/zfsbootmenu/config.yaml <<EOF
Global:
InitCPIO: true
Components:
Enabled: false
EFI:
Enabled: true
Versions: false
Kernel:
Prefix: zfsbootmenu
CommandLine: zfsbootmenu ro quiet loglevel=4 nomodeset
EOF
curl -L -O /etc/zfsbootmenu/zbm-builder.sh https://raw.githubusercontent.com/zbm-dev/zfsbootmenu/master/zbm-builder.sh
chmod 755 /etc/zfsbootmenu/zbm-builder.shIn this configuration, mkinitcpio will be used instead of dracut. Component
generation is disabled, so generate-zbm will produce only a UEFI bundle. That
bundle has numeric versioning disabled, so generate-zbm will produce an
unversioned zfsbootmenu.EFI; if the generator detects an existing
zfsbootmenu.EFI in the output directory, it will make a single backup of that
file as zfsbootmenu-backup.EFI before overwriting it. A simple kernel
command-line is specified and may be overridden as necessary.
For some systems, it is necessary to tear down USB devices before ZFSBootMenu
launches a boot environment. Even when this is not needed, it is generally
harmless. The ZFSBootMenu repository offers contrib/xhci-teardown.sh
for this purpose, and it is possible to instruct mkinitcpio to include this
teardown hook straight from the version of ZFSBootMenu inside the container:
mkdir -p /etc/zfsbootmenu/mkinitcpio.conf.d
echo "zfsbootmenu_teardown=( /zbm/contrib/xhci-teardown.sh )" \
> /etc/zfsbootmenu/mkinitcpio.conf.d/teardown.confThe default mkinitcpio.conf in the container, which should generally not be
overridden, will source all files in /etc/zfsbootmenu/mkinitcpio.conf.d.
On high-resolution screens, the Linux kernel does not always do a good job
choosing a console font. A nice font can be explicitly specified in the
ZFSBootMenu configuration for mkinitcpio. The container entrypoint must be
told to install the desired font and the mkinitcpio configuration should
include the necessary module and executable to set the font:
echo "BUILD_ARGS+=( -p terminus-font )" >> /etc/zfsbootmenu/zbm-builder.conf
cat > /etc/zfsbootmenu/mkinitcpio.conf.d/consolefont.conf <<EOF
BINARIES+=(setfont)
HOOKS+=(consolefont)
EOFThis approach uses the configuration file capability of zbm-builder.sh to
specify build options without requiring that they be included on the command
line.
As configured, mkinitcpio will not see a configured console font and will
omit the font from generated images. To make mkinitcpio aware of the desired
font, it must be specified in /etc/rc.conf within the container. The
"terraform" capabilities of the container entrypoint can be used to accomplish
this:
mkdir -p /etc/zfsbootmenu/rc.d
cat > /etc/zfsbootmenu/rc.d/consolefont <<EOF
#!/bin/sh
sed -e '/FONT=/a FONT="ter-132n"' -i /etc/rc.conf
EOF
chmod 755 /etc/zfsbootmenu/rc.d/consolefontWhen the container entrypoint finds an rc.d subdirectory in the build root,
it will run each executable file therein before generating a ZFSBootMenu image.
If any of these executable should fail, image generation is aborted.
By default, zbm-builder.sh will copy the /etc/hostid and
/etc/zfs/zpool.cache from the host to the build directory so that the
container can include these host-specific files in ZFSBootMenu images. This is
often desirable for customized builds, but it would be undesirable for copies
of these files in /etc/zfsbootmenu to fall out of synchronization with the
host versions. To avoid this issue, tell zbm-builder.sh to remove any copies
in /etc/zfsbootmenu before determining whether the host versions should be
copied in for image creation:
echo "REMOVE_HOST_FILES=yes" >> /etc/zfsbootmenu/zbm-builder.confIf you would rather not see those files at all, it is possible to instruct
generate-zbm to remove them after they are used. Edit the configuration at
/etc/zfsbootmenu/config.yaml and add the following key:
Global:
PostHooksDir: /build/cleanup.dAlternatively, tell the build container to add this option dynamically:
echo "BUILD_ARGS+=( -e '.Global.PostHooksDir=\"/build/cleanup.d\"' )" \
>> /etc/zfsbootmenu/zbm-builder.confNext, create a post-generation hook to remove the files:
mkdir -p /etc/zfsbootmenu/cleanup.d
cat > /etc/zfsbootmenu/cleanup.d/hostfiles <<EOF
#!/bin/sh
rm -f /build/zpool.cache /build/hostid
EOF
chmod 755 /etc/zfsbootmenu/cleanup.d/hostfilesAt this point, it should be possible to generate images by running
cd /etc/zfsbootmenu && ./zbm-builder.shHowever, these images will reside in /etc/zfsbootmenu/build and will require
manual management. A better alternative is to let generate-zbm manage the
ZFSBootMenu output directory directly. Assuming that ZFSBootMenu images should
be installed in /boot/efi/EFI/zfsbootmenu, tell zbm-builder.sh to mount the
directory inside the container, and tell the container that it should write its
images to the mounted directory:
cat >> /etc/zfsbootmenu/zbm-builder.conf <<EOF
RUNTIME_ARGS+=( -v /boot/efi/EFI/zfsbootmenu:/output )
BUILD_ARGS+=( -o /output )
EOFNow, running
cd /etc/zfsbootmenu && ./zbm-builder.shshould create images directly in /boot/efi/EFI/zfsbootmenu and create a
backup of any existing zfsbootmenu.EFI.
Manipulating files in /etc/zfsbootmenu and /boot/efi/EFI/zfsbootmenu may
require root privileges, which means that zbm-builder.sh and the build
container will need to run as root. In some configurations, podman may not
provide working networking for rootfull containers by default. A simple fix is
to allow the containers to use the host network stack, which can be
accomplished by running
echo "RUTNIME_ARGS+=( --net=host )" >> /etc/zfsbootmenu/zbm-builder.conf