Update Alpine, Arch, Fedora and RHEL root on ZFS guides
Signed-off-by: Maurice Zhou <jasper@apvc.uk>
This commit is contained in:
committed by
George Melikov
parent
a0c149af5b
commit
a69befb2ce
@@ -26,9 +26,9 @@ Preparation
|
||||
|
||||
List available disks with::
|
||||
|
||||
ls /dev/disk/by-id/*
|
||||
find /dev/disk/by-id/
|
||||
|
||||
If using virtio as disk bus, use ``/dev/disk/by-path/*``.
|
||||
If using virtio as disk bus, use ``/dev/disk/by-path/``.
|
||||
|
||||
Declare disk array::
|
||||
|
||||
@@ -40,11 +40,10 @@ Preparation
|
||||
|
||||
#. Set partition size:
|
||||
|
||||
Set swap size. It's `recommended <https://chrisdown.name/2018/01/02/in-defence-of-swap.html>`__
|
||||
to setup a swap partition. If you intend to use hibernation,
|
||||
the minimum should be no less than RAM size. Skip if swap is not needed::
|
||||
Set swap size, set to 1 if you don't want swap to
|
||||
take up too much space::
|
||||
|
||||
INST_PARTSIZE_SWAP=8
|
||||
INST_PARTSIZE_SWAP=4
|
||||
|
||||
Root pool size, use all remaining disk space if not set::
|
||||
|
||||
@@ -54,7 +53,7 @@ Preparation
|
||||
|
||||
curl -L https://archzfs.com/archzfs.gpg | pacman-key -a -
|
||||
pacman-key --lsign-key $(curl -L https://git.io/JsfVS)
|
||||
curl -L https://git.io/Jsfw2 > /etc/pacman.d/mirrorlist-archzfs
|
||||
curl -L https://raw.githubusercontent.com/openzfs/openzfs-docs/master/docs/Getting%20Started/Arch%20Linux/archzfs-repo/mirrorlist-archzfs > /etc/pacman.d/mirrorlist-archzfs
|
||||
|
||||
tee -a /etc/pacman.conf <<- 'EOF'
|
||||
|
||||
@@ -77,12 +76,26 @@ Preparation
|
||||
* https://archzfs.com/archive_archzfs/
|
||||
* https://archzfs.com/archzfs/x86_64/
|
||||
|
||||
::
|
||||
curl -L https://archzfs.com/archive_archzfs/ \
|
||||
| grep zfs-linux-[0-9] \
|
||||
| grep -v src.tar \
|
||||
| grep "5.18.7"
|
||||
# ...<a href="zfs-linux-2.1.5_5.18.7.arch1.1-1-x86_64.pkg.tar.zst">...
|
||||
|
||||
Result: https/.../archive_archzfs/zfs-linux-2.1.5_5.18.7.arch1.1-1-x86_64.pkg.tar.zst
|
||||
|
||||
#. Find compatible zfs-utils package:
|
||||
|
||||
Search ZFS version string (e.g. 2.1.5) in both pages above.
|
||||
|
||||
::
|
||||
curl -L https://archzfs.com/archzfs/x86_64/ \
|
||||
| grep zfs-utils-2.1.5 \
|
||||
| grep -v src.tar
|
||||
# ...<a href="zfs-utils-2.1.5-1-x86_64.pkg.tar.zst">...
|
||||
|
||||
|
||||
Result: https/.../archzfs/x86_64/zfs-utils-2.1.5-2-x86_64.pkg.tar.zst
|
||||
|
||||
#. Download both then install::
|
||||
|
||||
@@ -10,13 +10,18 @@ System Installation
|
||||
|
||||
for i in ${DISK}; do
|
||||
|
||||
# wipe flash-based storage device to improve
|
||||
# performance.
|
||||
# ALL DATA WILL BE LOST
|
||||
# blkdiscard -f $i
|
||||
|
||||
sgdisk --zap-all $i
|
||||
|
||||
sgdisk -n1:1M:+1G -t1:EF00 $i
|
||||
|
||||
sgdisk -n2:0:+4G -t2:BE00 $i
|
||||
|
||||
test -z $INST_PARTSIZE_SWAP || sgdisk -n4:0:+${INST_PARTSIZE_SWAP}G -t4:8200 $i
|
||||
sgdisk -n4:0:+${INST_PARTSIZE_SWAP}G -t4:8200 $i
|
||||
|
||||
if test -z $INST_PARTSIZE_RPOOL; then
|
||||
sgdisk -n3:0:0 -t3:BF00 $i
|
||||
@@ -25,6 +30,12 @@ System Installation
|
||||
fi
|
||||
|
||||
sgdisk -a1 -n5:24K:+1000K -t5:EF02 $i
|
||||
|
||||
sync && udevadm settle && sleep 3
|
||||
|
||||
cryptsetup open --type plain --key-file /dev/random $i-part4 ${i##*/}-part4
|
||||
mkswap /dev/mapper/${i##*/}-part4
|
||||
swapon /dev/mapper/${i##*/}-part4
|
||||
done
|
||||
|
||||
#. Create boot pool::
|
||||
@@ -84,9 +95,7 @@ System Installation
|
||||
|
||||
If not using a multi-disk setup, remove ``mirror``.
|
||||
|
||||
#. This section implements dataset layout as described in `overview <1-preparation.html>`__.
|
||||
|
||||
Create root system container:
|
||||
#. Create root system container:
|
||||
|
||||
- Unencrypted::
|
||||
|
||||
@@ -108,18 +117,34 @@ System Installation
|
||||
-o keyformat=passphrase \
|
||||
rpool/archlinux
|
||||
|
||||
Create system datasets::
|
||||
You can automate this step (insecure) with: ``echo POOLPASS | zfs create ...``.
|
||||
|
||||
zfs create -o canmount=on -o mountpoint=/ rpool/archlinux/root
|
||||
zfs create -o canmount=on -o mountpoint=/home rpool/archlinux/home
|
||||
zfs create -o canmount=off -o mountpoint=/var rpool/archlinux/var
|
||||
zfs create -o canmount=on rpool/archlinux/var/lib
|
||||
zfs create -o canmount=on rpool/archlinux/var/log
|
||||
Create system datasets, let Archlinux declaratively
|
||||
manage mountpoints with ``mountpoint=legacy``::
|
||||
|
||||
Create boot dataset::
|
||||
zfs create -o mountpoint=legacy rpool/archlinux/root
|
||||
mount -t zfs rpool/archlinux/root /mnt/
|
||||
zfs create -o mountpoint=legacy rpool/archlinux/home
|
||||
mkdir /mnt/home
|
||||
mount -t zfs rpool/archlinux/home /mnt/home
|
||||
zfs create -o mountpoint=legacy rpool/archlinux/var
|
||||
zfs create -o mountpoint=legacy rpool/archlinux/var/lib
|
||||
zfs create -o mountpoint=legacy rpool/archlinux/var/log
|
||||
zfs create -o mountpoint=none bpool/archlinux
|
||||
zfs create -o mountpoint=legacy bpool/archlinux/root
|
||||
mkdir /mnt/boot
|
||||
mount -t zfs bpool/archlinux/root /mnt/boot
|
||||
|
||||
#. zfs-mkinitcpio requires root dataset to have a mountpoint
|
||||
other than legacy::
|
||||
|
||||
umount -Rl /mnt
|
||||
zfs set canmount=noauto rpool/archlinux/root
|
||||
zfs set mountpoint=/ rpool/archlinux/root
|
||||
mount -t zfs -o zfsutil rpool/archlinux/root /mnt
|
||||
mount -t zfs rpool/archlinux/home /mnt/home
|
||||
mount -t zfs bpool/archlinux/root /mnt/boot
|
||||
|
||||
zfs create -o canmount=off -o mountpoint=none bpool/archlinux
|
||||
zfs create -o canmount=on -o mountpoint=/boot bpool/archlinux/root
|
||||
|
||||
#. Format and mount ESP::
|
||||
|
||||
@@ -131,14 +156,3 @@ System Installation
|
||||
|
||||
mkdir -p /mnt/boot/efi
|
||||
mount -t vfat $(echo $DISK | cut -f1 -d\ )-part1 /mnt/boot/efi
|
||||
|
||||
#. Install packages::
|
||||
|
||||
pacstrap /mnt base vi mandoc grub efibootmgr mkinitcpio
|
||||
|
||||
CompatibleVer=$(pacman -Si zfs-linux | grep 'Depends On' | sed "s|.*linux=||" | awk '{ print $1 }')
|
||||
pacstrap -U /mnt https://archive.archlinux.org/packages/l/linux/linux-${CompatibleVer}-x86_64.pkg.tar.zst
|
||||
|
||||
pacstrap /mnt zfs-linux zfs-utils
|
||||
|
||||
pacstrap /mnt linux-firmware intel-ucode amd-ucode
|
||||
|
||||
@@ -8,13 +8,28 @@ System Configuration
|
||||
|
||||
#. Generate fstab::
|
||||
|
||||
mkdir -p /mnt/var/log
|
||||
mkdir -p /mnt/var/lib
|
||||
mount -t zfs rpool/archlinux/var/lib /mnt/var/lib
|
||||
mount -t zfs rpool/archlinux/var/log /mnt/var/log
|
||||
mkdir -p /mnt/etc/
|
||||
for i in ${DISK}; do
|
||||
echo UUID=$(blkid -s UUID -o value ${i}-part1) /boot/efis/${i##*/}-part1 vfat \
|
||||
umask=0022,fmask=0022,dmask=0022 0 1 >> /mnt/etc/fstab
|
||||
done
|
||||
echo $(echo $DISK | cut -f1 -d\ )-part1 /boot/efi vfat \
|
||||
noauto,umask=0022,fmask=0022,dmask=0022 0 1 >> /mnt/etc/fstab
|
||||
genfstab -t PARTUUID /mnt | grep -v swap > /mnt/etc/fstab
|
||||
sed -i "s|vfat.*rw|vfat rw,x-systemd.idle-timeout=1min,x-systemd.automount,noauto,nofail|" /mnt/etc/fstab
|
||||
|
||||
#. Install packages::
|
||||
|
||||
pacstrap /mnt base mg mandoc grub efibootmgr mkinitcpio
|
||||
|
||||
CompatibleVer=$(pacman -Si zfs-linux \
|
||||
| grep 'Depends On' \
|
||||
| sed "s|.*linux=||" \
|
||||
| awk '{ print $1 }')
|
||||
|
||||
pacstrap -U /mnt https://archive.archlinux.org/packages/l/linux/linux-${CompatibleVer}-x86_64.pkg.tar.zst
|
||||
|
||||
pacstrap /mnt zfs-linux zfs-utils
|
||||
|
||||
pacstrap /mnt linux-firmware intel-ucode amd-ucode
|
||||
|
||||
#. Configure mkinitcpio::
|
||||
|
||||
@@ -28,19 +43,10 @@ System Configuration
|
||||
hwclock --systohc
|
||||
systemctl enable systemd-timesyncd --root=/mnt
|
||||
|
||||
#. Set locale, keymap, timezone, hostname and root password::
|
||||
|
||||
rm -f /mnt/etc/localtime
|
||||
systemd-firstboot --root=/mnt --prompt --force
|
||||
|
||||
#. Generate host id::
|
||||
|
||||
zgenhostid -f -o /mnt/etc/hostid
|
||||
|
||||
#. Enable ZFS services::
|
||||
|
||||
systemctl enable zfs-import-scan.service zfs-mount zfs-import.target zfs-zed zfs.target --root=/mnt
|
||||
|
||||
#. Add archzfs repo::
|
||||
|
||||
curl -L https://archzfs.com/archzfs.gpg | pacman-key -a - --gpgdir /mnt/etc/pacman.d/gnupg
|
||||
@@ -66,3 +72,16 @@ System Configuration
|
||||
|
||||
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
|
||||
locale-gen
|
||||
|
||||
#. Generate initrd::
|
||||
|
||||
mkinitcpio -P
|
||||
|
||||
#. Import from by-id::
|
||||
|
||||
echo GRUB_CMDLINE_LINUX=\"zfs_import_dir=/dev/disk/by-id/\" >> /etc/default/grub
|
||||
|
||||
#. Set locale, keymap, timezone, hostname and root password::
|
||||
|
||||
rm -f /etc/localtime
|
||||
systemd-firstboot --prompt --force
|
||||
|
||||
@@ -6,15 +6,6 @@ Bootloader
|
||||
.. contents:: Table of Contents
|
||||
:local:
|
||||
|
||||
#. Create empty cache file and generate initrd::
|
||||
|
||||
rm -f /etc/zfs/zpool.cache
|
||||
touch /etc/zfs/zpool.cache
|
||||
chmod a-w /etc/zfs/zpool.cache
|
||||
chattr +i /etc/zfs/zpool.cache
|
||||
|
||||
mkinitcpio -P
|
||||
|
||||
#. Apply GRUB workaround::
|
||||
|
||||
echo 'export ZPOOL_VDEV_NAME_PATH=YES' >> /etc/profile.d/zpool_vdev_name_path.sh
|
||||
@@ -23,14 +14,11 @@ Bootloader
|
||||
# GRUB fails to detect rpool name, hard code as "rpool"
|
||||
sed -i "s|rpool=.*|rpool=rpool|" /etc/grub.d/10_linux
|
||||
|
||||
echo GRUB_CMDLINE_LINUX=\"zfs_import_dir=/dev/disk/by-id/\" >> /etc/default/grub
|
||||
|
||||
This workaround needs to be applied for every GRUB update, as the
|
||||
update will overwrite the changes.
|
||||
|
||||
#. Install GRUB::
|
||||
|
||||
export ZPOOL_VDEV_NAME_PATH=YES
|
||||
mkdir -p /boot/efi/arch/grub-bootdir/i386-pc/
|
||||
mkdir -p /boot/efi/arch/grub-bootdir/x86_64-efi/
|
||||
for i in ${DISK}; do
|
||||
@@ -40,11 +28,8 @@ Bootloader
|
||||
grub-install --target x86_64-efi --boot-directory \
|
||||
/boot/efi/arch/grub-bootdir/x86_64-efi/ --efi-directory \
|
||||
/boot/efi --bootloader-id arch --removable
|
||||
|
||||
#. Generate GRUB menu::
|
||||
|
||||
grub-mkconfig -o /boot/efi/arch/grub-bootdir/x86_64-efi/grub/grub.cfg
|
||||
grub-mkconfig -o /boot/efi/arch/grub-bootdir/i386-pc/grub/grub.cfg
|
||||
grub-mkconfig -o /boot/efi/arch/grub-bootdir/x86_64-efi/grub/grub.cfg
|
||||
grub-mkconfig -o /boot/efi/arch/grub-bootdir/i386-pc/grub/grub.cfg
|
||||
|
||||
#. For both legacy and EFI booting: mirror ESP content::
|
||||
|
||||
@@ -70,3 +55,7 @@ Finish Installation
|
||||
#. Reboot::
|
||||
|
||||
reboot
|
||||
|
||||
#. You can create a snapshot of the newly installed
|
||||
system for later rollback,
|
||||
see `this page <https://openzfs.github.io/openzfs-docs/Getting%20Started/Arch%20Linux/Root%20on%20ZFS/6-create-boot-environment.html>`__.
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
.. 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
|
||||
Reference in New Issue
Block a user