zedenv Boot Environment Manager¶
zedenv
is a utility to manage Boot Environments using ZFS. zedenv
is
still in the alpha stage on Linux and FreeBSD. Take caution when using.
Documentation¶
Install¶
zedenv
requires python 3.6+, pyzfscmds, and ZFS running as the root
filesystem.
It can be installed a few ways:
- From the
setup.py
directly. - From the
Makefile
. - From the Arch AUR.
First, clone the git repos.
git clone https://github.com/johnramsden/pyzfscmds
git clone https://github.com/johnramsden/zedenv
Makefile and setup.py¶
To install without poluting your system, you can also create a directory somewhere
and install in a venv
, otherwise install to the system.
Optionally, create a venv
and activate.
python3.6 -m venv venv
. venv/bin/activate
setup.py¶
Enter the repos and install.
cd pyzfscmds
python setup.py install
cd ../zedenv pyzfscmds
python setup.py install
Makefile¶
Enter the packaging
directory in the repos run make
, pyzfscmds
must
be installed first.
cd pyzfscmds/packaging
make
cd ../../zedenv/packaging
make
System Setup¶
In order to use boot environments your system needs to be set up in a certain manner.
The main dataset that is used for your root file system, can also be thought of as your boot environment. Anything in this dataset, or in a dataset under it, is what constitutes a boot environment.
Dataset Configuration¶
To put your system in a compatible configuration, your boot environments for
your system should be kept in a ‘Boot Environment root’. In most configurations
this would be <pool>/ROOT
. However its location is not important, and it
can be located anywhere within a pool. What’s important is that it does not
have any child datasets that are not in a boot environment.
The common practice is to start with a ‘default’ boot environment. This would
be the dataset <pool>/ROOT/default
. If a system is setup in this
manner, it would be the most basic boot environment compatible system.
This ‘default’ dataset could have the entire system installed into it. Upon creating new boot environments, it would be cloned and the entire system would be in the new boot environment. A better practice would be to keep some datasets separate from the boot environment. Putting parts of the system that can be shared between boot environments, in these separate datasets is good practice. For example, one might want to keep their log, or home directories separate.
Examples¶
Here are a few examples of possible setups with a few different systems.
FreeBSD¶
The default FreeBSD configuration is a great example of a hierarchy that is setup to use boot environments by default. After a root on ZFS install, the system has a new boot environment, that is usable by default.
Any dataset that is set to canmount=off
, means it will not be mounted and
its data will be stored in the boot environment.
In the default setup this means the data of /usr
, and /var
will change
between boot environments, but any dataset set canmount=on
, will not be
in the boot environment, and the data will be persistent between every boot environment.
NAME CANMOUNT MOUNTPOINT
zroot on /zroot
zroot/ROOT on none
zroot/ROOT/default noauto /
zroot/tmp on /tmp
zroot/usr off /usr
zroot/usr/home on /usr/home
zroot/usr/ports on /usr/ports
zroot/usr/src on /usr/src
zroot/var off /var
zroot/var/audit on /var/audit
zroot/var/crash on /var/crash
zroot/var/log on /var/log
zroot/var/mail on /var/mail
zroot/var/tmp on /var/tmp
Arch Linux¶
Here is an Arch Linux system, with an extensive dataset setup.
NAME CANMOUNT MOUNTPOINT
vault/ROOT on none
vault/ROOT/default-3 noauto /
vault/ROOT/default-4 noauto /
vault/home on legacy
vault/usr off /usr
vault/usr/local on legacy
vault/var off /var
vault/var/cache on legacy
vault/var/cache/pacman on legacy
vault/var/lib off /var/lib
vault/var/lib/docker on legacy
vault/var/lib/libvirt on legacy
vault/var/lib/systemd off /var/lib/systemd
vault/var/lib/systemd/coredump on legacy
vault/var/log on legacy
vault/var/log/journal on legacy
In this example, while it looks like /var
, /var/lib
/var/lib/systemd
, and /usr
are outside of the boot environment, they
have actually been set to canmount=off
meaning they’re not mounted and
are only there to create the ZFS dataset structure. This will put their data in
the boot environment dataset. Their properties will be inherited by any child
datasets.
This allows us to take any datasets we would like to share between boot
environments, and create them under these datasets in hierarchy that is clear
and easy to understand. It means the user’s /home
, /usr/local
and
/var/log
directories, among others, data will stay the same when switching
between boot environments.
Basic Usage¶
zedenv
can be used to manage boot environments using ZFS. If your system
is set up in a way compatible with boot environments, you can start using
them right away.
Create and activate a new Boot Environment.
$ zedenv create default-0
$ zedenv activate default-0
This will make it the Boot Environment used on reboot.
$ zedenv list
Name Active Mountpoint Creation
default N - Wed-May-23-23:48-2018
default-0 R / Thu-May-24-23:54-2018
This can be shown with a list, command. The boot environment currently being used will have a ‘N’ in the active column signifying the boot environment is being used now. An ‘R’ in the active column means this environment will be used on reboot.
In order to integrate with a bootloader, an extra flag
‘-b/--bootloader
’ must be used to specify a bootloader plugin. The plugin will make
the necessary changes to boot from the new Boot Environment.
If you expect you will always be using a certain bootloader, you can set the
org.zedenv:bootloader
property on your boot environments, and the
bootloader plugin will be used without you having to specify.
$ zedenv set org.zedenv:bootloader=<bootloader plugin>
Plugins available for your system can be listed with zedenv --plugins
.
If you’re using zedenv
to activate a boot environment, and a plugin isn’t available, you
may need to edit some config files to specify the new dataset, depending on
your bootloader.
Usage information can be given at any time by running zedenv --help
.
Usage: zedenv [OPTIONS] COMMAND [ARGS]...
ZFS boot environment manager cli
Options:
--version
--plugins List available plugins.
--help Show this message and exit.
Commands:
activate Activate a boot environment.
create Create a boot environment.
destroy Destroy a boot environment or snapshot.
get Get boot environment properties.
list List all boot environments.
mount Mount a boot environment temporarily.
rename Rename a boot environment.
set Set boot environment properties.
umount Unmount a boot environment.
More specific information about a specific subcommand can be requested as well.
zedenv create --help
Usage: zedenv create [OPTIONS] BOOT_ENVIRONMENT
Create a boot environment.
Options:
-v, --verbose Print verbose output.
-e, --existing TEXT Use existing boot environment as source.
--help Show this message and exit.
Commands¶
The following commands are available
activate
- Activate a boot environment.create
- Create a boot environment.destroy
- Destroy a boot environment or snapshot.get
- Print boot environment properties.list
- List all boot environments.mount
- Mount a boot environment temporarily.rename
- Rename a boot environment.set
- Set boot environment properties.umount
- Unmount a boot environment.
Activate¶
The activate
is used to enable an already created boot environment. After
activation, the boot environment will be used upon reboot.
zedenv activate [OPTIONS] BOOT_ENVIRONMENT
Option | Description |
---|---|
-v , --verbose |
Print verbose output. |
-b , --bootloader TEXT |
Use bootloader type. |
-y , --noconfirm |
Assume yes in situations where confirmation is needed. |
-n , --noop |
Print what would be destroyed but don’t apply. |
--help |
Show this message and exit. |
Create¶
Create a new boot environment.
zedenv create [OPTIONS] BOOT_ENVIRONMENT
Option | Description |
---|---|
-v , --verbose |
Print verbose output. |
-e , --existing TEXT |
Use existing boot environment as source. |
--help |
Show this message and exit. |
Destroy¶
Destroy a boot environment or snapshot.
zedenv destroy [OPTIONS] BOOT_ENVIRONMENT
Option | Description |
---|---|
-v , --verbose |
Print verbose output. |
-b , --bootloader TEXT |
Use bootloader type. |
-y , --noconfirm |
Assume yes in situations where confirmation is needed. |
-n , --noop |
Print what would be destroyed but don’t apply. |
--help |
Show this message and exit. |
List¶
List all boot environments.
zedenv list [OPTIONS]
Option | Description |
---|---|
-v , --verbose |
Print verbose output. |
-D , --spaceused |
Display the full space usage for each boot environment. |
-H , --scripting |
Scripting output. |
-O , --origin |
Display origin. |
--help |
Show this message and exit. |
Mount¶
Mount a boot environment temporarily.
zedenv mount [OPTIONS] BOOT_ENVIRONMENT [MOUNTPOINT]
Option | Description |
---|---|
-v , --verbose |
Print verbose output. |
--help |
Show this message and exit. |
Rename¶
Rename a boot environment.
zedenv rename [OPTIONS] BOOT_ENVIRONMENT NEW_BOOT_ENVIRONMENT
Option | Description |
---|---|
-v , --verbose |
Print verbose output. |
--help |
Show this message and exit. |
Set¶
Set boot environment properties.
zedenv set [OPTIONS] BOOT_ENVIRONMENT
Option | Description |
---|---|
-v , --verbose |
Print verbose output. |
--help |
Show this message and exit. |
Umount¶
Unmount a boot environment.
zedenv umount [OPTIONS] BOOT_ENVIRONMENT
Option | Description |
---|---|
-v , --verbose |
Print verbose output. |
--help |
Show this message and exit. |
Plugins¶
As of now plugins for the following bootloaders exist:
- FreeBSD’s loader -
freebsdloader
- systemdboot -
systemdboot
In order to integrate with a bootloader, an extra flag ‘-b/--bootloader
’
must be used to specify a bootloader plugin. The plugin will make the necessary
changes to boot from the new Boot Environment.
If you expect you will always be using a certain bootloader, you can set the
org.zedenv:bootloader
property on your boot environments, and the
bootloader plugin will be used without you having to specify.
$ zedenv set org.zedenv:bootloader=<bootloader plugin>
Plugins available for your system can be listed with zedenv --plugins
.
freebsdloader¶
The freebsdloader
plugin is quite simple. During activation, it will
respect /etc/rc.d/zfsbe
if it exists, and set, all datasets to
canmount=noauto
, otherwise the datasets will be set canmount=on
.
It will also change the root dataset to mount from in /boot/loader.conf
,
and /boot/loader.conf.local
.
The current /boot/zfs/zpool.cache
will also be copied into the newly
activated boot environment.
systemdboot¶
Multiple kernels can be managed with this plugin and systemd-boot, but it will require changing the mountpoint of the esp (EFI System Partition).
Problem With Regular Mountpoint¶
Usually the $esp
would get mounted at /boot
or /boot/efi
. The
kernels would sit in the root of the $esp
, and the configs for systemdboot
in $esp/loader/
.
$esp
.
├── initramfs-linux-fallback.img
├── initramfs-linux.img
├── intel-ucode.img
├── vmlinuz-linux
│
└── loader/
├── entries/
│ └── arch.conf
└── loader.conf
The configs would then reference kernels in the root directory.
title Arch Linux
linux vmlinuz-linux
initrd intel-ucode.img
initrd initramfs-linux.img
options zfs=bootfs rw
The problem with this method, is multiple kernels cannot be kept at the same time. Therefore this hierarchy is not conducive to boot environments.
Alternate Mountpoint¶
First, remount the $esp
to a new location, the default is /mnt/efi
.
If you would like to explicitly specify the mountpoint used, you can set the
org.zedenv.systemdboot:esp
property on your current boot environment, and the plugin
will use the specified location:
zfs set org.zedenv.systemdboot:esp='/mnt/efi' zpool/ROOT/default
Don’t forget to change the mount point in /etc/fstab
.
UUID=9F8A-F566 /mnt/efi vfat rw,defaults,errors=remount-ro 0 2
Now, make a subdirectory $esp/env
, kernels will be kept in a subdirectory
of this location.
The bootloader configuration can now use a different path for each boot environment.
So the ‘default’ boot environment config, located at
$esp/loader/entries/zedenv-default.conf
, would look something like:
title Arch Linux
linux /env/zedenv-default/vmlinuz-linux
initrd /env/zedenv-default/intel-ucode.img
initrd /env/zedenv-default/initramfs-linux.img
options zfs=zpool/ROOT/default rw
To make the system happy when it looks for kernels at /boot
, this directory
should be bindmounted to /boot
.
Bindmount /mnt/efi/env/zedenv-default
to /boot
in /etc/fstab
.
/mnt/efi/env/zedenv-default /boot none rw,defaults,errors=remount-ro,bind 0 0
If this directory is not here, the kernels will not be updated when the system rebuilds the kernel.
Once our system is set up in the proper configuration, zedenv
will update
the bootloader, and fstab - if requested - when a new boot environment is
activated.
It will also update the configuration described above, asking you if the modifications that made are correct. You will have a chance to inspect and change them if they are not.
If you are confident and the changes it is making, and do not wish to inspect
them, adding the --noconfirm/-y
flag will run the command without asking
for confirmation.