Skip to content

Instantly share code, notes, and snippets.

@dasjoe
Last active April 24, 2016 16:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dasjoe/d12a8061bee56a966359d046a61161c6 to your computer and use it in GitHub Desktop.
Save dasjoe/d12a8061bee56a966359d046a61161c6 to your computer and use it in GitHub Desktop.
A small HOWTO about installing Ubuntu 16.04 LTS on ZFS
# Boot Ubuntu 16.04 LTS from a ZFS rpool
#
#
# We boot the remote server to its (Debian or Ubuntu based) rescue mode
# then ssh into it with forwarded ports for the VM's SSH and VNC servers
#
# Shell here documents that are not passed to a command are used for
# documentation and copy and paste sources.
# "<<'LOCAL'" denotes commands to be run on the local machine, 'RESCUE'
# and 'VM' should be run in the rescue system or the VM, respectively.
#
# This is for a single-disk pool on /dev/sda, rpools on raidz{1,2,3} or
# mirror vdevs are known to work, too. Just pass through the additional
# disks to the VM and
<<'LOCAL'
ssh \
-L 5900:localhost:5900 \
-L 5901:localhost:5901 \
-o "UserKnownHostsFile /dev/null" \
-o "StrictHostKeyChecking no" \
root@91.121.135.62
LOCAL
<<'RESCUE'
# Get Xubuntu iso
wget http://cdimage.ubuntu.com/xubuntu/releases/16.04/release/xubuntu-16.04-desktop-amd64.iso
# Start a VM, boot the Xubuntu iso and pass through our local disks
# TODO: Redirect the disks you want to use, here: /dev/sda
qemu-system-x86_64 \
-cdrom xubuntu-16.04-desktop-amd64.iso \
-boot d \
-drive file=/dev/sda,media=disk \
-nographic \
-vnc 127.0.0.1:0 \
-m 12G \
-cpu host \
-smp 4 \
-enable-kvm \
-redir tcp:5901::22
# For testing the installation it's possible to run qemu without the iso
# attached, to start the VM from qemu's console: Ctrl+a c, "cont"
# TODO: same as above, you may want to add more disks
qemu-system-x86_64 \
-drive file=/dev/sda,media=disk \
-nographic \
-vnc 127.0.0.1:0 \
-m 12G \
-cpu host \
-smp 4 \
-enable-kvm \
-redir tcp:5901::22 \
-S
RESCUE
<<'VM'
# Add password to 'xubuntu' user
echo "xubuntu:xubuntu" | chpasswd
# Install openssh-server
apt-get --quiet update
apt-get --yes --quiet install openssh-server
VM
<<'LOCAL'
# copy file over
scp \
-P 5901 \
-o "UserKnownHostsFile /dev/null" \
-o "StrictHostKeyChecking no" \
xenial-on-zfs.sh \
xubuntu@localhost:
LOCAL
<<'VM'
# now run this script on the virtual machine
sudo bash -x /home/xubuntu/xenial-on-zfs.sh
VM
# Disable automatic installation of recommended or suggested packages
cat > /etc/apt/apt.conf.d/01norecommend <<EOF
APT::Install-Recommends "0";
APT::Install-Suggests "0";
EOF
# Zap our disks' GPT and MBR structures so we don't accidentally
# import an outdated pool during installation of zfsutils-linux
# TODO:
for disk in /dev/sda
do
sgdisk -Z "$disk"
done
# Get required tools, i.e. debootstrap and ZFS userspace tools
apt-get --quiet update
apt-get --yes --quiet install debootstrap zfsutils-linux
# We follow partman-auto's partition size for ESP:
# https://bugs.launchpad.net/curtin/+bug/1306164
#
# Our disks will get partitioned in this way:
# (note the out-of-order partition numbering)
#
# Protective MBR
# LBA 0
# Primary GPT
# LBA 1 → 33
# Partition 2
# LBA 34 → 2047
# BIOS boot partition, used for grub
# Partition 3
# 1 MiB → 539 MiB
# EFI system partition, unused as of now
# Partition 1
# 539 MiB → -9 MiB
# ZFS pool
# Partition 9
# -9 MiB → -1 MiB (= LBA -34)
# Reserved partition, here used for ZFS label padding
# Secondary GPT
# LBA -33 → -1
#
# We wipe stale, overlapping ZFS labels from partition 1 if they exist
for disk in /dev/sda
do
sgdisk -a1 -n2:34:2047 -t2:EF02 -c2:grub \
"$disk"
sgdisk -n3:1M:+538M -t3:EF00 -c3:EFI \
-n9:-8M:0 -t9:BF07 -c9:reserved \
-n1:0:0 -t1:BF01 -c1:zfs \
"$disk"
zpool labelclear -f "$disk"1
done
# I am using ashift=9 as my sample server uses an HUS724020ALA640:
# HUS724020ALE640 = 2TB, SATA 6Gb/s, 512n, 64MB buffer
# H = HGST
# U = Ultrastar
# S = Standard
# 72 = 7200 RPM
# 40 = Full capacity, 4TB
# 20 = This model's Capacity, 40 = 4TB, 30 = 3TB, 20 = 2TB
# A = Generation code
# L = 26.1mm z-height
# A6 = Interface, SATA 6Gb/s, 512n (E6 = SATA 512e, S6 = SAS 512n)
# 4 = 64MB buffer
# 0 = No encryption (1 = encryption)
#
# TODO: If using more than one disk, replace "/dev/sda1" with your own
# pool layout, e.g. "mirror /dev/sda1 /dev/sdb1"
zpool create \
-o ashift=9 \
-O normalization=formD \
-O atime=off \
-O canmount=off \
-O compression=lz4 \
-O mountpoint=/ \
-O recordsize=1M \
-R /mnt \
rpool \
/dev/sda1
zfs create -o canmount=off -o mountpoint=none rpool/ROOT
zfs create -o canmount=noauto -o mountpoint=/ rpool/ROOT/xenial
# Turn synchronous requests into async ones for faster installation
zfs set sync=disabled rpool
zfs mount rpool/ROOT/xenial
# TODO: Replace with your closest mirror
debootstrap xenial /mnt http://de.archive.ubuntu.com/ubuntu
zfs snap rpool/ROOT/xenial@inst-debootstrap
# TODO: Replace with real host name
echo 'xenial' > /mnt/etc/hostname
sed -i '1 a 127.0.1.1 xenial' /mnt/etc/hosts
# fix "predictable" device naming, see
# https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/
ln -s /dev/null /mnt/etc/udev/rules.d/80-net-setup-link.rules
# TODO: This is my network configuration, use your own!
cat > /mnt/etc/network/interfaces.d/eth0 <<'EOF'
auto eth0
iface eth0 inet static
address 91.121.135.62
netmask 255.255.255.0
gateway 91.121.135.254
dns-nameservers 8.8.8.8 8.8.4.4
iface eth0 inet6 static
address 2001:41d0:1:b63e::1
netmask 64
gateway 2001:41d0:1:b6ff:ff:ff:ff:ff
dns-nameservers 2001:4860:4860::8888 2001:4860:4860::8844
EOF
# Install a sane sources.list
cat > /mnt/etc/apt/sources.list <<'EOF'
deb http://de.archive.ubuntu.com/ubuntu xenial main restricted universe multiverse
deb http://de.archive.ubuntu.com/ubuntu xenial-backports main restricted universe multiverse
deb http://de.archive.ubuntu.com/ubuntu xenial-updates main restricted universe multiverse
deb http://de.archive.ubuntu.com/ubuntu xenial-security main restricted universe multiverse
EOF
# Disable automatic installation of recommended or suggested packages
cat > /mnt/etc/apt/apt.conf.d/01norecommend <<'EOF'
APT::Install-Recommends "0";
APT::Install-Suggests "0";
EOF
# This is a remote system, so we disable plymouth, enable quiet boot
# and do not wait for user input
cat > /mnt/etc/default/grub <<'EOF'
# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
# info -f grub -n 'Simple configuration'
GRUB_DEFAULT=0
#GRUB_HIDDEN_TIMEOUT=0
GRUB_HIDDEN_TIMEOUT_QUIET=true
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="noplymouth quiet"
GRUB_CMDLINE_LINUX=""
# Uncomment to enable BadRAM filtering, modify to suit your needs
# This works with Linux (no patch required) and with any kernel that obtains
# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef"
# Uncomment to disable graphical terminal (grub-pc only)
GRUB_TERMINAL=console
# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
#GRUB_GFXMODE=640x480
# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true
# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_RECOVERY="true"
# Uncomment to get a beep at grub start
#GRUB_INIT_TUNE="480 440 1"
EOF
echo 'LANG="en_US.UTF-8"' > /mnt/etc/default/locale
# Fix the chroot's mtab
ln -s /proc/mounts /mnt/etc/mtab
mount -t devtmpfs /dev /mnt/dev
mount -t devpts /dev/pts /mnt/dev/pts
mount -t sysfs /sys /mnt/sys
mount -t proc /proc /mnt/proc
mount -t tmpfs /run /mnt/run
# Create temporary resolv.conf by manually setting it up
# TODO: feel free to use a different name server, this is Google's
mkdir /mnt/run/resolvconf/
echo "nameserver 8.8.8.8" > /mnt/run/resolvconf/resolv.conf
# Finish installation in a chroot
chroot /mnt /bin/bash -l -- <<'EOF'
# Enable bash's debug mode, to show executed commands
set -x
# TODO: replace with your locale needs
for locale in en_US.UTF-8 de_DE.UTF-8; do locale-gen "$locale"; done
# TODO: edit timezone
# This is a workaround for https://bugs.launchpad.net/ubuntu/+source/tzdata/+bug/1554806
ln -fs /usr/share/zoneinfo/Europe/Berlin /etc/localtime
dpkg-reconfigure -f noninteractive tzdata
# Update package cache and upgrade everything
apt-get --quiet update
apt-get --yes --quiet dist-upgrade
# Install a minimal but sane set of packages
# TODO: edit according your needs
apt-get --yes --quiet install \
linux-image-generic \
zfsutils-linux \
zfs-initramfs \
openssh-server \
ssh-import-id \
tmux \
aptitude \
vim
# Install grub, force usage of our custom /etc/default/grub
DEBIAN_FRONTEND=noninteractive apt-get --yes --quiet \
-o Dpkg::Options::="--force-confdef" \
-o Dpkg::Options::="--force-confold" \
install grub-pc
# Actually install grub to disk
# TODO:
for disk in /dev/sda
do grub-install "$disk"
done
update-grub
# Add local user with appropriate groups, import SSH key from Launchpad
# TODO: Edit username and password to your own
adduser --disabled-password --gecos "Hajo Moeller,,," dasjoe
usermod -a -G adm,sudo dasjoe
echo "dasjoe:dasjoe" | chpasswd
sudo -Hu dasjoe ssh-import-id dasjoe
# Disable password login via SSH
sed -i 's/^#\{0,1\}\(PasswordAuthentication\) .*/\1 no/g' /etc/ssh/sshd_config
exit
EOF
# Prepare zpool for export, unmount /run, /proc, /sys, /dev/pts and /dev
umount /mnt/run
umount /mnt/proc
umount /mnt/sys
umount /mnt/dev/pts
umount /mnt/dev
umount /mnt
# Reset synchronous behaviour to ZFS defaults
zfs inherit sync rpool
zfs snap rpool/ROOT/xenial@inst-done
zpool export rpool
<<'FIXME'
Stuff left TODO:
- encryption (+ dropbear?)
- cpu ondemand
- EFI
- grub-mkpasswd-pbkdf2
FIXME
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment