Tyler's Site

Abstract

FreeBSD’s Boot Environments feature is a tool that takes some of the fear and uncertainty out of things like upgrades by taking a snapshot of the root file system; in the event that the root file system needs to be rolled back to a known good version, simply changing an option in the boot menu will allow for that without affecting user files. This feature is a massive benefit of using FreeBSD with ZFS-on-root. I recently ran into an issue with upgrading my FreeBSD laptop and had to rely on a previous boot environment, which inspired me to do a small write-up on the topic.

Getting Started with Boot Environments

Getting started with boot environments is very easy these days; all that is needed is a FreeBSD install with ZFS-on-root. Similar systems are available on Linux, however, I do not know of distributions that have an out-of-the-box equivalent that works as well as boot environments. All currently supported FreeBSD systems (13.x, 14.x, as well as 15-CURRENT) will enable boot environments by default when using ZFS for the root file system, no further configuration required. During major and minor version upgrades a boot environment of the previous (the boot environment that was used before upgrading) is created. This will allow the system administrator to rollback the upgrade if something did not work as intended, or if the upgrade left the system completely broken.

Creating and Managing Boot Environments

The automatic backup of a boot environment is great for upgrading a system, however, there are more reasons that you might want to create a backup of the current boot environment. The simplest reason is to make sure that the system is bootable after something (probably an “experiment”) really stupid happens. Working with boot environments is fairly straightforward:

# This will create a boot environment called 'test01'
bectl create test01
# Then the environment can be listed with:
bectl list
# And to activate the boot environment:
bectl activate test01

While this process technically works, it is not an ideal process for several reasons. The first reason is the manageability of the boot environments; theoretically, the name shouldn’t really matter, but it is foreseeable to have half a dozen or more boot environments. No one is going to remember what ‘test01’ is or when it was created. Secondly, what if there is an issue with the boot environment, and you cannot get it boot back? That isn’t a problem if is a local machine, but for remote machines, you’d like it to fail into a known good state, right? Let’s see if we can improve this process a bit.

The first thing is the naming convention, it is silly, but many experienced IT staff will say that creating a following a naming convention is a key point of good IT practices. Names should mean something and be able to communicate important information quickly, so, keeping that in mind for our boot environments a good naming convention might be:

DATE{ACTION}, for example 20240123-UPGRADE. The example name would communicate that the boot environment was created on January 23, 2024 and was created before upgrading the system. Next, let’s see about fixing the failing boot issue:

# Create the boot environment
bectl create 20240927-test
# Set the boot environment to be the snapshot that was just taken (current environment)
bectl activate 20240927-test
# Then set the boot environment to boot the "upgraded" system just once (that is set by the '-t' flag)
bectl activate -t default

Assuming the upgrade worked as intended, the boot environment can be permanently set by running bectl activate default (note the lack of a ‘-t’).

Actually Booting into the Environment

In the event that this boot environment should be re-used, simply reboot the machine and in the FreeBSD bootloader hit the ‘e’ key on the keyboard. This will open another menu in which an alternative boot environment can be selected by simply pressing ‘a’. Pressing ‘a’ will change the environment name from zfs:zroot/ROOT/default, to zfs:zroot/ROOT/${BOOT_ENV_NAME}. From there, press backspace to return to the main section of the bootloader, and press ‘Enter’ to continue booting the computer. Once the computer is booted, the root file system should return to the state in was in before performing the upgrade. It is worth noting that zroot/HOME is not affected by changing boot environments, meaning that any files in /home will remain unaffected.

A Creative Use for Boot Environments

Using boot environments as a method to safely restore a broken system is great, however, there are more creative things that it can be used for. The main one that comes to mind is a method for atomic in-place upgrades that Alan Jude came up with. I first heard the idea on an episode of 2.5 Admins, and it sounded complex, but genius for managing a lot of remote machines. When writing about boot environments I wanted to take a look at the method to actually make this happen, and realized it is slightly more difficult than I originally thought. Because of that, implementing this idea is going to take a bit more time than I have allotted to getting this post out, however, I do want to make it happen in the future. When I do, I am going to come back to this post and describe the method that I used to make it happen. For now, I have some resources in the below section that will give more information on not only this idea, but boot environments in general.

Resources