173 lines
4.6 KiB
ReStructuredText
173 lines
4.6 KiB
ReStructuredText
.. highlight:: sh
|
|
|
|
Create a Boot Environment
|
|
==========================
|
|
|
|
This page is tested for Alpine, Arch Linux, Fedora and
|
|
RHEL guides. Not useful for NixOS since system rollback
|
|
is already managed by Nix.
|
|
|
|
With Root on ZFS, it is possible to take snapshots of
|
|
existing root file systems, which is a read-only copy of
|
|
that file system. A new, full-fledged file system --
|
|
clones -- can be then created from this snapshot. This
|
|
bootable clone of the current system is then called a
|
|
"Boot Environment".
|
|
|
|
This could be useful if you are performing a major
|
|
system upgrade and wish to have the option to go back to
|
|
a previous state if the upgrade fails.
|
|
|
|
#. Identify which dataset is currently mounted as root
|
|
``/`` and boot ``/boot``::
|
|
|
|
findmnt /
|
|
# output
|
|
TARGET SOURCE FSTYPE OPTIONS
|
|
/ rpool/archlinux/root zfs rw,relatime,xattr,posixacl
|
|
|
|
findmnt /boot
|
|
# output
|
|
TARGET SOURCE FSTYPE OPTIONS
|
|
/boot bpool/archlinux/root zfs rw,relatime,xattr,posixacl
|
|
|
|
#. Identify your distribution in the dataset (file system) path::
|
|
|
|
DISTRO=archlinux # or `fedora', `alma', `alpinelinux'
|
|
|
|
#. Choose a name for the new boot environment::
|
|
|
|
BE_NAME=backup
|
|
|
|
#. Take snapshots of the ``/`` and ``/boot`` datasets::
|
|
|
|
zfs snapshot rpool/$DISTRO/root@$BE_NAME
|
|
zfs snapshot bpool/$DISTRO/root@$BE_NAME
|
|
|
|
#. Create clones from read-only snapshots::
|
|
|
|
zfs clone -o canmount=noauto \
|
|
-o mountpoint=/ \
|
|
rpool/$DISTRO/root@$BE_NAME \
|
|
rpool/$DISTRO/$BE_NAME
|
|
|
|
zfs clone -o canmount=noauto \
|
|
-o mountpoint=legacy \
|
|
bpool/$DISTRO/root@$BE_NAME \
|
|
bpool/$DISTRO/$BE_NAME
|
|
|
|
#. Mount clone and update file system table (fstab) ::
|
|
|
|
mount -t zfs -o zfsutil rpool/$DISTRO/$BE_NAME /mnt
|
|
mount -t zfs bpool/$DISTRO/$BE_NAME /mnt/boot
|
|
|
|
sed -i "s|rpool/$DISTRO/root|rpool/$DISTRO/$BE_NAME|g" /mnt/etc/fstab
|
|
sed -i "s|bpool/$DISTRO/root|bpool/$DISTRO/$BE_NAME|g" /mnt/etc/fstab
|
|
|
|
If legacy mountpoint is used, omit ``-o zfsutil``
|
|
from mount command.
|
|
|
|
#. Create GRUB menu for new clone::
|
|
|
|
m='/dev /proc /sys'
|
|
for i in $m; do mount --rbind $i /mnt/$i; done
|
|
chroot /mnt /usr/bin/env sh <<EOF
|
|
if which grub-mkconfig; then
|
|
grub-mkconfig -o /boot/grub.cfg
|
|
else
|
|
grub2-mkconfig -o /boot/grub.cfg
|
|
fi
|
|
EOF
|
|
|
|
GRUB menu contains information on kernel version and initramfs.
|
|
|
|
#. Unmount clone::
|
|
|
|
umount -Rl /mnt
|
|
|
|
#. Add new boot environment as GRUB menu entry::
|
|
|
|
tee -a new_entry <<EOF
|
|
menuentry 'ZFS Clone of ${DISTRO}: ${BE_NAME}' { configfile (hd0,gpt2)/${DISTRO}/${BE_NAME}@/grub.cfg }
|
|
EOF
|
|
|
|
find /boot/efis/ -name "grub.cfg" \
|
|
| while read i; do
|
|
if grep -q "${DISTRO}" $i; then
|
|
cat $i new_entry > grub.cfg
|
|
cp grub.cfg $i
|
|
fi
|
|
done
|
|
|
|
rm new_entry
|
|
|
|
#. After reboot, select boot environment entry from GRUB
|
|
menu to boot from the clone. Press ESC inside
|
|
submenu to return to the previous menu.
|
|
|
|
#. Steps above can also be used to create a new clone
|
|
from an existing snapshot.
|
|
|
|
#. To set a boot environment as default, replace
|
|
existing ``grub.cfg`` inside EFI system partition
|
|
with the one from the boot environment::
|
|
|
|
mount -t zfs bpool/$DISTRO/$BE_NAME /mnt
|
|
|
|
# backup existing grub.cfg inside EFI
|
|
# then replace it with menu from clone
|
|
|
|
mkdir -p /mnt/grub_menu_backup
|
|
menu_counter=1
|
|
find /boot/efis/ -name "grub.cfg" \
|
|
| while read i; do
|
|
if grep -q "${DISTRO}" $i; then
|
|
cp $i /mnt/grub_menu_backup/grub_${menu_counter}.cfg
|
|
echo $i > /mnt/grub_menu_backup/grub_${menu_counter}_path.txt
|
|
cp /mnt/grub.cfg $i
|
|
menu_counter=$(($menu_counter + 1))
|
|
fi
|
|
done
|
|
|
|
umount -Rl /mnt
|
|
|
|
#. To delete the boot environment, check with
|
|
``findmnt`` that the boot environment is not
|
|
currently used::
|
|
|
|
findmnt /
|
|
findmnt /boot
|
|
|
|
Set variables::
|
|
|
|
DISTRO=archlinux
|
|
|
|
Then check the origin snapshot::
|
|
|
|
zfs get origin rpool/archlinux/backup
|
|
# rpool/archlinux/root@backup
|
|
zfs get origin bpool/archlinux/backup
|
|
# bpool/archlinux/root@backup
|
|
|
|
RM_BE=backup
|
|
RM_SNAPSHOT=root@backup
|
|
|
|
Finally, destroy clone (boot environment) and its
|
|
origin snapshot::
|
|
|
|
zfs destroy rpool/${DISTRO}/${RM_BE}
|
|
zfs destroy rpool/${DISTRO}/${RM_SNAPSHOT}
|
|
|
|
zfs destroy bpool/${DISTRO}/${RM_BE}
|
|
zfs destroy bpool/${DISTRO}/${RM_SNAPSHOT}
|
|
|
|
Remove GRUB entry::
|
|
|
|
find /boot/efis/ -name "grub.cfg" \
|
|
| while read i; do
|
|
if grep -q "${DISTRO}/${RM_BE}@/grub.cfg" $i; then
|
|
head -n -1 $i > grub.cfg
|
|
cp grub.cfg $i
|
|
fi
|
|
done
|