From a1195ebf022cb72e8e49c2e248ce18b7f3db7425 Mon Sep 17 00:00:00 2001 From: Nguyễn Gia Phong Date: Sun, 14 Nov 2021 12:15:48 +0700 Subject: Write up about butter transition --- _assets/let-it-go.png | Bin 0 -> 177041 bytes blog/butter.md | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 _assets/let-it-go.png create mode 100644 blog/butter.md diff --git a/_assets/let-it-go.png b/_assets/let-it-go.png new file mode 100644 index 0000000..3e18fd4 Binary files /dev/null and b/_assets/let-it-go.png differ diff --git a/blog/butter.md b/blog/butter.md new file mode 100644 index 0000000..40c188c --- /dev/null +++ b/blog/butter.md @@ -0,0 +1,224 @@ ++++ +rss = "Reinstalling and backing up NixOS on Btrfs+tmpfs" +date = Date(2021, 11, 14) ++++ +@def tags = ["fun", "nixos", "btrfs", "tmpfs", "backup", "luks"] + +# Reinstalling and backing up NixOS on Btrfs+tmpfs + +In 2018, dad bought me a new laptop to replace the good ole Compaq nx7010 +whose screen unfortunately got infected by some sort of microbe and dieded +shortly afterwards. The new one, whilst having a considerably worse build +quality (like all other late-2010s ones when compared to mid-2000s models), +had 12.5 times as much storage: a 250 GB M.2 SSD and a 500 GB SATA HDD. + +My data hoarding habit has grown exponentially ever since. Initially, +I used to back up the data from the SSD to the HDD but after a few years, +I ran out of space and decided to get some more storage. Instead of buying +a portable hard disk like a normal person would, I went for an SATA SSD, +as it was rather difficult to find a 7200 rpm 2.5-inch[^metric] HDD +in the market at the time. + +I then asked my father for a spare SATA-to-USB case (he switched to using +a dock a while ago, and like other dads, nothing is ever thrown away) +and prepared to swap the drives. As cloning the data would have been too easy, +I decided to *spice things up* by reinstalling the OS. Back then I was +dual-booting Debian and NixOS, but the former had hardly been ever booted +for months so it was time to let it go: + +![Elsa rolling on the floor crying](/assets/let-it-go.png) + +In addition, I wanted to jump on the new and shinny[^new] train of Btrfs. +It has compression, snapshots and subvolumes, what's not to love? Let's +replace something I'd been using for nearly a decade with a file system +I had absolutely zero experience with, what could possibly go wrong, right? + +\toc + +## Reinstallation + +I was going to reinstall NixOS with an ephemeral root, +which had been covered to death in the following brilliant resources: + +* [Erase your darlings: immutable infrastructure for mutable systems][grahamc] +* [NixOS ❄: tmpfs as root][elis] +* [Nix community's impermanence modules][impermanence] +* [Paranoid NixOS Setup][christine] + +The only twist here is that I was using Btrfs instead of ZFS or ext4 like in +other guides. This choice would influence how to back up in the later section. + +### Preparation + +First of all, I temporarily copied data to the SATA SSD from the M.2, +including [my Nix configurations]. Using either `cp` or `rsync` didn't +seem to have any effect on the performance, and in the mean time I also +went ahead and grabbed a [NixOS unstable live image] and `dd`'ed it to +a flash drive. As I'm tracking unstable, installing from the same version +would allowed me to skip switching the channel and a lot of downloading. + +### Partitioning + +After booting up the live image, I opened up a root shell with `sudo -i`. +As expected, `fdisk` reports the M.2 SSD as `/dev/nvme0n1`. Paranoid as always, +I decided to give the EFI system partition a whole gibibyte, swap eight +to match memory[^memory] and the rest as a single chonky Btrfs partition: + +```sh +parted /dev/nvme0n1 -- mklabel gpt +parted /dev/nvme0n1 -- mkpart ESP fat32 1MiB 1GiB +parted /dev/nvme0n1 -- set 1 boot on + +parted /dev/nvme0n1 -- mkpart Swap linux-swap 1GiB 9GiB +mkswap -L Swap /dev/nvme0n1p2 +swapon /dev/nvme0n1p2 + +parted /dev/nvme0n1 -- mkpart primary 9GiB 100% +mkfs.btrfs -L Butter /dev/nvme0n1p3 +``` + +As I typed this, I realized that I should have set up encryption +for the last partition so I would probably need to reinstall in the near future +to fix this mistake. Anyway, with the target system's root mounted as tmpfs, +I would need to persist `/nix` (obviously), `/etc` (mostly for authentication +and other secret stuff not included in `configuration.nix` that I was too lazy +to opt in individually), `/var/log`, `/root` and `/home`: + +```sh +mount /dev/nvme0n1p3 /mnt +btrfs subvolume create /mnt/nix +btrfs subvolume create /mnt/etc +btrfs subvolume create /mnt/log +btrfs subvolume create /mnt/root +btrfs subvolume create /mnt/home +umount /mnt +``` + +Most subvolumes can be mounted with `noatime`, except for `/home` +where I frequently need to sort files by modification time. All of them +should have forced compression though: + +```sh +mount -t tmpfs -o mode=755 none /mnt +mkdir -p /mnt/{boot,nix,etc,var/log,root,home} +mount /dev/nvme0n1p1 /mnt/boot +mount -o subvol=nix,compress-force=zstd,noatime /dev/nvme0n1p3 /mnt/nix +mount -o subvol=etc,compress-force=zstd,noatime /dev/nvme0n1p3 /mnt/etc +mount -o subvol=log,compress-force=zstd,noatime /dev/nvme0n1p3 /mnt/var/log +mount -o subvol=root,compress-force=zstd,noatime /dev/nvme0n1p3 /mnt/root +mount -o subvol=home,compress-force=zstd /dev/nvme0n1p3 /mnt/home +``` + +### Configuration + +With everything mounted, `nixos-generate-config --root /mnt` could be run +to generate a basic configuration. But wait, didn't I say something +about my dot files? That's correct, but it's not easy to handcraft +the `hardware-configuration.nix`. After making sure all are mounted +with the right options and `services.fstrim.enable` is `true`, I copied +other configuration files to `/etc/nixos` and finished this step. + +### Installation + +NixOS installation is as simple as running `nixos-install`. But my job was +not done after setting the root password and rebooting into the new system. +It was working, but not functional. There was nothing meaningful for me +to do on it, so I had to log in (as root), `passwd`'ed the user and copied +the home folder back from the temporary drive. + +After freeing the new SATA SSD, I also filled it with butter. Yes, +all the way, no GPT, no MBR, just Btrfs, whose subvolumes were used +in place of partitions: + +```sh +mkfs.btrfs -f -L Fly /dev/sdb +mkdir -p /mnt +mount /dev/sdb /mnt +btrfs subvolume create /mnt/movies +``` + +At that time the only disposable data I had were my movies collection. +The HDD also contained other data but they were rebalanced at `/home` +(on the M.2). After swapping the SATA SSD inside the laptop, I logged in +as the normal user and get the exact same environment before the reinstallation. + +### Profits + +Thanks to subvolumes and compression, the free spaces were no longer fragmented +and I think I gained like 100 GB (not counting the old Debian's root). Backup +would also be less painful with Btrfs snapshots (instead of plain `rsync` +like I used to) as shown as follows. + +## Backup + +With all data migrated, the HDD could be used for backing up. First, +some legacy data I no longer access were moved there, then I started to back up +my `/home` partition: + +### Initialization + +Having learned my lesson, I did not forget to set up [LUKS] this time: + +```sh +cryptsetup luksFormat /dev/sdb +cryptsetup luksOpen /dev/sdb backup +``` + +To make use of snapshots, the backup drive gotta be Btrfs as well. +The compression level was turned up to 14 this time (default was 3): + +```sh +mkfs.btrfs -L Backup /dev/mapper/backup +mkdir /backup +mount -o noatime,compress-force=zstd:14 /dev/mapper/backup /backup +``` + +Following [Btrfs Wiki], I made the first `/home` snapshot and sent it +to the backup drive: + +```sh +btrfs subvolume create /backup/home +today=$(date --iso-8601) +btrfs subvolume snapshot -r /home /home/$today +sync +btrfs send /home/$today | btrfs receive /backup/home +``` + +### Repetition + +For next backups, I also mounted the drive and created a snapshot: + +```sh +cryptsetup luksOpen /dev/sdb backup +mount -o noatime,compress-force=zstd:14 /dev/mapper/backup /backup +today=$(date --iso-8601) +btrfs subvolume snapshot -r /home /home/$today +sync +``` + +Say the latest snapshot was on the `$previous` day, I only needed to send +the difference between the old and new backup. Afterwards, it is safe +to delete the local `$previous` snapshot to save some space. + +```sh +btrfs send -p /home/$previous /home/$today | btrfs receive /backup/home +btrfs subvolume delete /home/$previous +``` + +Is this more complicated than good ole `rsync`? Yes. Is it safer? Also yes, +thanks to copy-on-write. Would I bother using one of the tools suggested +in the wiki? Probably not, I've already documented everything in this article +in case I forget anything. + +[^metric]: 63.5 mm for those outside of the land of guns and burgers +[^new]: OK, maybe not new, but certainly shinny +[^memory]: Slightly larger since some of the memory is dedicated to graphics + +[grahamc]: https://grahamc.com/blog/erase-your-darlings +[elis]: https://elis.nu/blog/2020/05/nixos-tmpfs-as-root +[impermanence]: https://github.com/nix-community/impermanence +[christine]: https://christine.website/blog/paranoid-nixos-2021-07-18 +[my Nix configurations]: https://git.sr.ht/~cnx/dotfiles/tree/master/item/nix +[NixOS unstable live image]: https://channels.nixos.org/nixos-unstable +[LUKS]: https://gitlab.com/cryptsetup/cryptsetup +[Btrfs Wiki]: https://btrfs.wiki.kernel.org/index.php/Incremental_Backup -- cgit 1.4.1