Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save AndrewJDR/f6d8fa6823e13b232f699c810e0cbd88 to your computer and use it in GitHub Desktop.
Save AndrewJDR/f6d8fa6823e13b232f699c810e0cbd88 to your computer and use it in GitHub Desktop.
patch against zfs wiki repo - DigitalOcean root on zfs guide (Ubuntu 18.04)
From 7cfaf9dcc917ae3d48b4929ff9bdfe4ce3dcb86c Mon Sep 17 00:00:00 2001
From: Andrew Johnson <ajohnson@draster.com>
Date: Fri, 18 May 2018 22:07:14 -0700
Subject: [PATCH] Add DigitalOcean root on zfs guide (Ubuntu 18.04).
---
DigitalOcean-Ubuntu-18.04-Root-on-ZFS.md | 183 +++++++++++++++++++++++++++++++
1 file changed, 183 insertions(+)
create mode 100644 DigitalOcean-Ubuntu-18.04-Root-on-ZFS.md
diff --git a/DigitalOcean-Ubuntu-18.04-Root-on-ZFS.md b/DigitalOcean-Ubuntu-18.04-Root-on-ZFS.md
new file mode 100644
index 0000000..8eb2a7f
--- /dev/null
+++ b/DigitalOcean-Ubuntu-18.04-Root-on-ZFS.md
@@ -0,0 +1,183 @@
+Create an Ubuntu 18.04 droplet, and use the smallest SSD/HDD size. This way you can make a snapshot of the droplet and have the ability to later deploy that snapshot into a droplet of any size.
+
+In this example, I use the "Optimized Droplet" that is 20GB, since that's the smallest one currently available.
+
+After creating the droplet, power it down and open a ticket with DigitalOcean support, and ask to enable the Ubuntu 18.04 recovery ISO. It can take an hour or two before they do this. By the time you read this guide, hopefully they will have an automated way of doing it.
+
+Once they get back to you, power your droplet back up and choose the recovery ISO's terminal/console option to get a shell.
+Now shrink the ext4 root to make room for the zfs root:
+```
+e2fsck -f /dev/vda1
+resize2fs /dev/vda1 1600M
+```
+
+The ext4 shrinking process is done, but you still need to resize the partition table entry using parted. To do this properly, you'll need the block size/count of the disk, sector size of the disk, and the start sector of the ext4 partition.
+
+Get the block size and block count using this command:
+```
+tune2fs -l /dev/vda1 | grep "Block"
+```
+
+Also run this command:
+```
+parted -m /dev/vda unit s print
+```
+to get the sector size and start sector of the ext4 partition. I've \*\*double starred\*\* the sector size and start sector in the output below:
+```
+/dev/vda:52428800s:virtblk:**512**:512:gpt:Virtio Block Device:;
+14:2048s:10239s:8192s:::bios_grub;
+15:10240s:227327s:217088s:fat32::msftdata;
+1:**227328s**:3504127s:3276800s:ext4::;
+```
+
+Now plug the correct values from the `tune2fs` and `parted` commands above into the first 4 lines of the python script below and run the python script:
+```
+block_count = 409600
+block_size = 4096
+sector_size = 512
+start_sector = 227328
+fs_size = block_count * block_size
+fs_sectors = fs_size/sector_size
+part_sectors = ((fs_sectors-1)/2048+1)*2048
+end_sector = start_sector + part_sectors - 1
+print "Partition start: %d end: %d size: %d"%(start_sector,end_sector,part_sectors)
+print "Resize in parted with: \nresizepart <number> %ds"%(end_sector)
+```
+
+This will tell you the exact command to run to change the partition table entry.
+
+When I run this, this script outputted `resizepart <number> 3504127s`, so I run it like below. For `<number>`, use the partition number of the ext4 partition, which should be `1`:
+```
+resizepart 1 3504127s
+```
+Your ext4 partition should now be shrunk down, leaving you plenty (18GB or so) of empty space for your zfs root.
+
+Now make the zfs partition. I've noticed that DO may just revert the ext4 partition to its full size again if we don't do this now.
+```
+sgdisk -n2:0:0 -t1:BF01 /dev/vda
+```
+
+Now let's stop using the recovery ISO and boot back into the ext4 root to make sure it still works. We can also finish the rest of the zfs-on-root process there.
+
+To stop using the Recovery ISO and boot back into the ext4 root, you have a choice:
+a. Open a DO support ticket and ask to get off of the recovery ISO. Power down and boot back up and you'll be back into your ext4 root, albeit a shrunken one. With this method, you'll need to wait the 1-2 hours for DO to respond to your ticket.
+b. Power down, create a snapshot, and spin up a new droplet based on that snapshot. The new droplet won't have the recovery ISO mounted anymore, but will still contain your work so far. At that point you can just destroy the old droplet. This saves some time, so it's what I do, but if you're not familiar with DigitalOcean snapshot creation and deployment, it might be trickier.
+
+You should now be booted up to your droplet and have a shrunken (1.6GB) ext4 root partition. 'parted -l' should show something like:
+```
+Model: Virtio Block Device (virtblk)
+Disk /dev/vda: 21.5GB
+Sector size (logical/physical): 512B/512B
+Partition Table: gpt
+Disk Flags:
+
+Number Start End Size File system Name Flags
+14 1049kB 5243kB 4194kB bios_grub
+15 5243kB 116MB 111MB fat32 msftdata
+ 1 116MB 1794MB 1678MB ext4
+ 2 1794MB 21.5GB 19.7GB
+```
+
+Now install the zfs packages, create the pool/dataset, copy the existing Ubuntu 18.04 installation into the new zfs root, then finally chroot into it.
+```
+apt update
+apt install --yes debootstrap gdisk zfs-initramfs
+
+zpool create -o ashift=12 -O atime=off -O canmount=off -O compression=lz4 -O normalization=formD -O mountpoint=/ -R /mnt zp /dev/vda2
+zfs create -o canmount=off -o mountpoint=none zp/ROOT
+zfs create -o canmount=noauto -o mountpoint=/ zp/ROOT/ubuntu1804
+
+zfs mount zp/ROOT/ubuntu1804
+rsync -aHAXxvP / /mnt/
+rm -rf /mnt/boot/*
+
+mount --rbind /dev /mnt/dev
+mount --rbind /proc /mnt/proc
+mount --rbind /sys /mnt/sys
+mount --rbind /run /mnt/run
+chroot /mnt /bin/bash --login
+```
+Note: I've created a very simple dataset scheme here, but feel free to do something more advanced.
+
+Now that we're chrooted into our new zfs root, we'll create a mount point for the old ext4 partition, because we will be reusing its /boot directory.
+```
+mkdir /ext4root
+```
+Note: Though you may be tempted to try to get rid of the old ext4 root, I've found it's very important to keep it around, because:
+1. Booting a zfs root without an ext4-based /boot gets tricky on DigitalOcean (I haven't successfully done so).
+2. The DigitalOcean snapshot deployment process will error out if the ext4 partition doesn't exist. Meaning, without the ext4 in place, you will not be able to deploy a new droplet based on a DO snapshot that you create using this guide. This limitation is significant, since you'd have to go through this entire guide every time you want to spin up a new DO instance with a ZFS root.
+
+Edit the /etc/fstab file and revise it so that the old ext4 root is mounted to /ext4root and /boot is bind mounted to /ext4root/boot
+Your fstab should look something like:
+```
+LABEL=cloudimg-rootfs /ext4root ext4 defaults 0 0
+/ext4root/boot /boot none defaults,bind 0 0
+LABEL=UEFI /boot/efi vfat defaults 0 0
+```
+Note: Line ordering is important!
+
+Now run:
+```
+mkdir /ext4root
+mount -a
+```
+
+Run `mount` and confirm that the output is sane. `ls /boot` and confirm that the bind mount worked by ensuring the kernel and initramfs files are there.
+
+I suggest going into /etc/default/grub and setting GRUB\_HIDDEN\_TIMEOUT line to:
+```
+GRUB_HIDDEN_TIMEOUT=1.0
+```
+This gives you a chance to get into grub if you need to, but doesn't slow down the reboot process by much.
+
+Now run the various grub commands:
+```
+apt install --yes grub-pc # Some form of grub is already installed on the 1804 image that DO provides, so this is maybe not necessary? I didn't want to re-do this guide in order to find out, so feel free to find out for yourself and propose an edit to the guide based on that.
+grub-install /dev/vda2
+update-grub
+update-initramfs -u -k all # Also not sure if this is strictly necessary.
+```
+
+After this, you can confirm that your /boot/grub/grub.cfg lines reference the zfs root, for example I have many lines such as:
+```
+/boot/vmlinuz-4.15.0-20-generic root=ZFS=zp/ROOT/ubuntu1804 ro recovery nomodeset
+```
+
+Exit the chroot and make a snapshot if you wish:
+```
+zfs snapshot zp/ROOT/ubuntu1804@install
+```
+
+Unmount and export:
+```
+mount | grep -v zfs | tac | awk '/\/mnt/ {print $3}' | xargs -i{} umount -lf {}
+zpool export zp
+```
+
+Now reboot your droplet and you should be in your new zfs root!
+At this point you can (and I would recommend) powering down and creating a DigitalOcean snapshot from your droplet.
+This will allow you to easily deploy a zfs root DigitalOcean instance at any time instead of needing to redo this entire guide every time.
+
+## Expanding a pool after deploying to a larger droplet
+If you deploy your new zfsroot DO snapshot to a droplet that's larger than the one you used to create the original snapshot, you'll have to grow your pool.
+
+An example of what this might look like follows, where I expanded the pool to fill a 50GB disk:
+```
+$ parted /dev/vda
+(parted) resizepart
+Partition number? 2
+End? [21.5GB]? 53.7GB
+```
+
+Now enable autoexpand on the pool and re-online it to cause the expansion:
+```
+zpool set autoexpand=on zp
+zpool online -e zp /dev/vda2
+```
+
+That's it! Your pool should now be expanded:
+```
+# zpool list
+NAME SIZE ALLOC FREE EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
+zp 48.2G 648M 47.6G - 0% 1% 1.00x ONLINE -
+```
--
2.14.2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment