The universal way to move the node is described in the documentation (it involves multiple rsync passes: one or more passes to transfer the bulk of the data first without shutting down the node, and then another pass to catch up to the current state with the node off). This is an inherently long, IO heavy process, however, if the target and a destinations are hosted on a ZFS filesystem, (including on different machines), the process can be significantly sped up by avoiding rsync and using ZFS send/receive and snapshots instead.
This is a short walkthrough, for reference for the future users.
Assumptions:
- storagenode node data is located on
pool1/storagenode-old
dataset, and databases are on the child datasetpool1/storagenode-old/databases
- OS is FreeBSD and node runs in a jail, named
storagenode-jail
- We are moving the node to a new dataset on another pool on the same machine, named
pool2/storagenode-new
. If the target pool is on another machine — zfs send/receive should be piped over ssh, and the jail should be exported and imported on the target machine.
The process:
- Without stopping the node, create a recursive snapshot of the source node dataset. This happens instantly:
zfs snapshot -r pool1/storagenode-old@snap1
- Send over the snapshot to the target filesystem. This takes huge amount of time (days), but node keeps running, so no hurry here:
Herezfs send -Rv pool1/storagenode-old@snap1 | zfs receive pool2/storagenode-new
R
stands for Recursive, andv
verbose, to see progress. If you are running this remotely, it’s a good idea to usetmux
, to disconnect remote session without interrupting the transfer. The target dataset should not exist prior to running the command; it will be created.
Now enjoy life until the process is done. - While this has been running, node was adding and removing more data. So, let’s catch up with that too:
Here we create another snapshot, and then send the differential (zfs snapshot -r pool1/storagenode-old@snap2 zfs send -Rvi pool1/storagenode-old@snap1 pool1/storagenode-old@snap2 | zfs receive pool2/storagenode-new
i
) update to the target filesystem. It can take few minutes to an hour – depending on how much data changed since last snapshot. - Now we can finally stop the node and transfer small amount of changes accumulated since the snapshot in the previous step, to fully catch up:
This shall take very little time, under a minute, since not much changes could have happened during previous short transfer.iocage stop storajenode-jail zfs snapshot -r pool1/storagenode-old@snap3 zfs send -Rvi pool1/storagenode-old@snap2 pool1/storagenode-old@snap3 | zfs receive pool2/storagenode-new
- Now we have a coherent copy of the node data on the new dataset, but the jail mounts still point to the old one. Modify them:
This will open the editor with the fstab config. Edit the mounts to point to the new datasets at the target pool, save, and exit the editor.iocage fstab -e storagenode-jail
- Now start the node:
At this point the node continues running from the state it was last stopped at, from the new dataset. Total downtime was under a minute spent in step 4 and a few seconds in step 5.iocage start storagenode-jail
- Confirm node is up, and destroy the old dataset; it’s obsolete, out of date, and useless now:
zfs destroy -rv -n pool1/storagenode-old
r
stands for “recursive”,v
– verbose, andn
– dry run. Review the output, and once you are content with what’s about to happen – re-run the command without the-n
That’s it.