I just finished the first alpha release of zedenv, ZFS Boot Environment Manager for FreeBSD and Linux. I created the project because I enjoyed having the use of a boot environment manager while using my FreeBSD servers, and missed having access to one when I was on Linux.
zedenv works similarly to the FreeBSD beadm, which is in turn based on the Solaris
zedenv is written completely in Python 3, and is is open source and licensed under the BSD-3-Clause License. If anyone would like to contribute, the code is available on GitHub.
To skip ahead to creating a boot environment, see the next section
First of all, for anyone not familiar with the idea, what does a boot environment manager do? Boot environments are basically a way to have a snapshot of a system, so that changes to a system can be made without having the fear of bringing the system into an unusable state. It’s not a new idea, and they’ve been used on Solaris, FreeBSD, and to some extent on Linux, however not to the amount they have been used on the prior two systems.
While boot environments are not reliant on a specific file system, they do rely on a file system that supports clones, such as ZFS. Using boot environments you are able to have multiple versions of your system going simultaneously, and the beauty of it is you only end up using roughly the same amount of data as a single system.
ZFS lets you create multiple filesystems which are known has datasets. Boot Environments take advantage of how low cost clones can be taken of the current root dataset. These clones are effectively forking points where all prior data is shared between the origin dataset and the clone, and any new data will be stored separately.
After creating a boot environment, when it is ready to be used, it is activated. After activation, once the system is rebooted, all new data will be stored to the new boot environment. This allows a workflow where whenever something dangerous is about to be done, an environment can be created. These boot environments can be integrated into the bootloader so that at any time one of them can be selected right at the boot menu, almost as if they are separate installs of an operating system.
Create a Boot Environment
Lets consider a situation where a large change is going to be made to a system, such as an upgrade.
Our current root file system is the ZFS dataset
vault/ROOT/default. We have a single boot environment, ‘default’.
$ zedenv list Name Active Mountpoint Creation default NR / Wed-May-23-23:48-2018
We can see it’s active from the ‘N’ and ‘R’ in the active column, which represent that we are using the boot environment now, and it will be used on reboot.
To keep our current working system in its present state, let’s create and activate a new boot environment called
# zedenv create default-1
If we take a look at our ZFS datasets at this point, we have a new clone taking up almost no used space.
$ zfs list -r vault/ROOT NAME USED AVAIL REFER MOUNTPOINT vault/ROOT 114G 349G 96K none vault/ROOT/default 114G 349G 15.5G / vault/ROOT/default-1 8K 349G 15.5G /
Listing our boot environments now we see the new
Name Active Mountpoint Creation default NR / Wed-May-23-23:48-2018 default-1 - Tue-May-29-10:31-2018
Let’s activate the new boot environment.
# zedenv activate default-1
Now listing them shows that on reboot our new boot environment would be active.
Name Active Mountpoint Creation default N / Wed-May-23-23:48-2018 default-1 R - Tue-May-29-10:31-2018
After reboot we can see if that our root file system is the newly-created boot environment.
Name Active Mountpoint Creation default - Wed-May-23-23:48-2018 default-1 NR / Tue-May-29-10:31-2018
We can now do our large upgrade, and if our system is hosed, we select the original boot environment from our bootloader, and we are back in the original working system.
If we have chosen ‘default’ from the boot menu, we can activate it if we want to continue using it:
$ zedenv activate default
If we want to inspect the broken boot environment, we can even mount it:
# zedenv mount --verbose default-1 Mounting boot environment 'default-1'. No mountpoint given, using a temporary directory /tmp/zedenv-wk1jzdcx-default-1. Mounted dataset to '/tmp/zedenv-wk1jzdcx-default-1'.
If we take a look:
$ ls /tmp/zedenv-wk1jzdcx-default-1 total 59K drwxr-xr-x 19 root root 23 Mar 13 10:22 . drwxrwxrwt 16 root root 400 May 29 11:00 .. lrwxrwxrwx 1 root root 7 Jan 5 11:17 bin -> usr/bin drwxr-xr-x 2 root root 2 Aug 31 2017 boot drwxr-xr-x 2 root root 2 Aug 31 2017 dev drwxr-xr-x 105 root root 216 May 24 23:57 etc drwxr-xr-x 2 root root 2 Aug 31 2017 home lrwxrwxrwx 1 root root 7 Jan 5 11:17 lib -> usr/lib lrwxrwxrwx 1 root root 7 Jan 5 11:17 lib64 -> usr/lib drwxr-xr-x 6 root root 6 May 24 16:23 mnt dr-xr-xr-x 2 root root 2 Sep 6 2017 net drwxr-xr-x 11 root root 11 Apr 12 00:22 opt dr-xr-xr-x 2 root root 2 Aug 31 2017 proc drwxr-x--- 19 root root 31 May 24 23:57 root drwxr-xr-x 2 root root 2 Aug 31 2017 run lrwxrwxrwx 1 root root 7 Jan 5 11:17 sbin -> usr/bin drwxr-xr-x 6 root root 6 Dec 16 02:27 srv dr-xr-xr-x 2 root root 2 Aug 31 2017 sys drwxrwxrwt 2 root root 2 Aug 31 2017 tmp drwxr-xr-x 10 root root 12 May 24 22:14 usr drwxr-xr-x 13 root root 17 May 21 13:33 var
And when we are done, we can destroy it.
# zedenv destroy -v default-1
I have also written posts in the past regarding using ZFS on Arch Linux, which go into more detail about a dataset setup and installation.
If anyone would like to contribute, the code is available on GitHub.