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 beadm
.
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.
Boot Environments Link to heading
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 Link to heading
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 default-1
# 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 default-1
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
More information Link to heading
This is just a very simple look at how boot environments are used and more information can be found at the zedenv documentation and on GitHub.
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.