Switching a remote server from Linux to FreeBSD
How to switch a remote server from Linux to FreeBSD through ssh in a few easy steps. In this particular case, we want to retain the data, stored on ZFS in a two-way mirror pool zdata. The pool's providers are LUKS encrypted partitions, sda3 and sdb3 respectively, so our current set up is like this:
- sda1 - the bios boot partition, 1M
- sda2 - system root, mdadm md0 device
- sda3 - LUKS provider for the zdata pool
sdb mirrors sda. This process assumes that a single disc can hold our zdata data twice and still have room for zroot and the bootloader partition. So for example, this was done with 2x3TB HDDs and zdata pool holding some 400GB so there was plenty of room for transfer.
1. Disable any usage of the '''sdb''' disk
First let's drop sdb from the zdata pool and from md0 device, because we need to completely rework the sdb disk.
# zpool offline zdata /dev/mapper/sdb3_crypto # zpool detach zdata /dev/mapper/sdb3_crypto # zpool labelclear /dev/mapper/sdb3_crypto # mdadm /dev/md0 --fail /dev/sdb2 --remove /dev/sdb2
2. Repartition '''sdb''' for the new, temporary layout
With sdb unused now, we repartition it for the new, temporary, layout using parted, or any of the partitioning tools of linux. With parted:
parted -s /dev/sdb mklabel gpt parted -s /dev/sdb mkpart primary 40 512k parted -s /dev/sdb mkpart primary 1Mib 10GiB parted -s /dev/sdb mkpart primary 10GiB 1010GiB parted -s /dev/sdb mkpart primary 1010GiB 100%
So we created the bootloader partition, sdb1 (future ada1p1); the zroot partition sdb2 (future ada1p2); the zdata partition sdb3 (future ada1p3) and the ztransfer partition sdb4. The idea is to move data from current zdata pool into ztransfer on sdb (ada1). Reboot and reinstall FreeBSD using ada0p2 + ada1p2 as providers for zroot, ada0p3 and ada1p3 as providers for GELI for zdata, move the data from ztransfer to new zdata, kill ztransfer, expand ada0p3 and ada1p3, expand the GELI providers, expand the zdata pool.
So far the server has been online and zdata serving without interruption even in degraded state. Before we continue with FreeBSD installation, we need to actually save the data from the old zdata mirrored pool into temporary ztransfer. Doing this after we've removed sdb from the pool allows disk-to-disk transfer which is fastest, otherwise ZFS would load balance sda and sdb at reading from it, while writing to ztransfer on sdb basically halving the available bandwidth, as sdb will be both read from and written to.
zfs snapshot -r zdata@transfer zfs send -Rv zdata@transfer | zfs receive ztransfer
After this is done, the data has been copied over to the temporary ztransfer pool and we can proceed with reinstalling FreeBSD which will result in removal our existing root and zdata.
3. Reboot and install FreeBSD
Reboot into FreeBSD installation / rescue environment and perform a regular install through ssh with bsdinstall, or by unpacking the tarballs. We partition the ex sda, now ada0:
gpart destroy -F ada0 gpart create -s gpt ada0 gpart add -t freebsd-boot -s 512k -b 40 ada0 gpart add -t freebsd-zfs -s 10G -a 1M ada0 gpart add -t freebsd-zfs -s 1000G ada0
Note that we only create three partitions on ada0. p1 will be for the gpt bootloader, p2 will hold our zroot pool and p3 will hold our zdata pool. We currently create it to match the size of sdb3, which is temporarily 1T, but that is not strictly required as ZFS allows providers of different sizes in the mirror vdev, so technically ada0p3 can be full remaining disk size.
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada0 zpool create zroot mirror ada0p2 ada1p2 geli init -l 256 -s 4096 ada0p3 geli init -l 256 -s 4096 ada1p3 geli attach ada0p3 geli attach ada1p3 zpool create zdata mirror ada0p3.eli ada1p3.eli
So now we have the new zdata pool, already in a mirror vdev that can receive data back from the temporary ztransfer. At this point we need to run bsdinstall or use whatever method to install FreeBSD onto the prepared zroot and zdata.
Note: With FreeBSD 11 it is possible to boot from encrypted zroot, so having two pools may not be needed.
4. Reboot into installed FreeBSD and continue operations
After installing FreeBSD we can reboot into it and configure the server for its purpose. At this point the zdata pool only needs to receive data back from the temporary ztransfer pool, so let's get it back:
zfs send -Rv ztransfer@transfer | zfs receive zdata
When that is complete the server can resume operation. All that remains to be done is remove the temporary ztransfer pool and expand zdata to use full remaining disk space:
Total server downtime is time required to copy zdata over to ztransfer and back, plus time needed to partition and install FreeBSD and configure it for the wanted operation. One day, when ZFS allows creating degraded mirror pools, this operation can be reduced down to time required to reboot and reinstall FreeBSD, since in that case sdb can be partitioned and prepared with new (degraded) zdata, data copied over while the server is operational, without the requirement to use temporary ztransfer pool.