FreeBSD ZFS snapshots with zfstools

In my recent survey of ZFS snapshot automation tools, I short-listed zfstools and zfsnap. I’ll try both, but first we’ll cover FreeBSD ZFS snapshots with zfstools. Zfstools includes a script for creating snapshots, another for removing old snapshots, and one for snapshotting MySQL databases. The configuration uses only ZFS attributes and command line arguments via cron.

Start by deciding which ZFS filesystems you want to snapshot. The purpose of snapshotting is to let you get older versions of a filesystem, so you can either roll back the entire filesystem or grab an older version of a file. I’m a fan of partitioning, and typically use many partitions on a ZFS system. I use separate ZFS for everything from /usr/ports/packages to /var/empty.

So, which of these partitions won’t need snapshots? I don’t snapshot the following, either because I don’t care about older versions or because the contents are easily replicable. (I would snapshot some of these on, say, my package-building machine.)

/tmp
/usr/obj
/usr/src
/usr/ports
/usr/ports/distfiles
/usr/ports/packages
/var/crash
/var/empty
/var/run
/var/tmp

Zfstools uses the ZFS property com.sun:auto-snapshot to determine if it should snapshot a filesystem. On a new system, this property should be totally unset, like so:


# zfs get com.sun:auto-snapshot
...
zroot/var/tmp com.sun:auto-snapshot - -
...

Set this property to false for datasets you want zfstools to never snapshot.

# zfs set com.sun:auto-snapshot=false zroot/var/empty

You should now see the attribute set:


# zfs get com.sun:auto-snapshot zroot/var/empty
NAME PROPERTY VALUE SOURCE
zroot/var/empty com.sun:auto-snapshot false local

Set this attribute for every filesystem you don’t want to snapshot, then activate snapshotting on the entire zpool.

# zfs set com.sun:auto-snapshot=true zroot

The other filesystems will inherit this property from their parent zpool.

Now to activate snapshots. Zfstool’s zfs-auto-snapshot tool expects to run out of cron. It requires two arguments: the name of the snapshot, and how many of that snapshot to keep. So, to create a snapshot named “15min” and retain 4 of them, you would run

# zfs-auto-snapshot 15min 4

Zfstools lets you name your snapshot anything you want. You can call your hourly snapshots LucasIsADweeb if you like. Other snapshot tools are not so flexible.

The sample cron file included suggests retaining 4 15 minute snapshots, 24 hourly snapshots, 7 daily snapshots, 4 weekly snapshots, and 12 monthly snapshots. That’s a decent place to start, so give root the following cron entries:

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin
15,30,45 * * * * /usr/local/sbin/zfs-auto-snapshot 15min     4
0        * * * * /usr/local/sbin/zfs-auto-snapshot hourly   24
7        0 * * * /usr/local/sbin/zfs-auto-snapshot daily     7
14       0 * * 7 /usr/local/sbin/zfs-auto-snapshot weekly    4
28       0 1 * * /usr/local/sbin/zfs-auto-snapshot monthly  12

(The zfstools instructions call the 15-minute snapshots “frequent.” I’m choosing to use a less ambiguous name.)

One important thing to note is that zfstools is written in Ruby, and each script starts with an environment call to find the ruby interpreter. You must set $PATH in your crontab.

Now watch /var/log/cron for error messages. If zfs-auto-snapshot runs correctly, you’ll start to see snapshots like these:

# zfs list -t snapshot

NAME                                                         USED  AVAIL  REFER  MOUNTPOINT
zroot/ROOT/default@zfs-auto-snap_monthly-2014-08-01-00h28       0      -   450M  -
zroot/ROOT/default@zfs-auto-snap_weekly-2014-08-03-00h14        0      -   450M  -
zroot/ROOT/default@zfs-auto-snap_daily-2014-08-06-00h07         0      -   450M  -
zroot/ROOT/default@zfs-auto-snap_hourly-2014-08-06-11h00        0      -   450M  -
zroot/ROOT/default@zfs-auto-snap_15min-2014-08-06-11h30         0      -   450M  -
zroot/home@zfs-auto-snap_hourly-2014-07-31-16h00              84K      -   460K  -
...

Each snapshot is unambiguously named after the snapshot tool, the snapshot name, and the time the snapshot was made.

Snapshots consume an amount of disk space related to the amount of churn on the filesystem. The root filesystem on this machine doesn’t change, so the snapshots are tiny. Filesystems with a lot of churn will generate much larger snapshots. I would normally recommend not snapshotting these filesystems, but you can at least exclude the 15-minute snapshots by setting a property.

# zfs set com.sun:auto-snapshot:15min=false zroot/var/churn

Note that this won’t show up when you do a zfs get com.sun:auto-snapshot. You must specifically check for this exact property. To see all snapshot settings, I would up using zfs get all and grep(1).

# zfs get -t filesystem all | grep auto-snapshot

zroot/ROOT/default  com.sun:auto-snapshot:frequent  false    local
zroot/ROOT/default  com.sun:auto-snapshot           true     inherited from zroot
zroot/ROOT/default  sun.com:auto-snapshot           true     inherited from zroot

If you disable a particular interval’s snapshots on a filesystem with existing snapshots, the older snapshots will gradually rotate away. That is, if you kept 4 15-minute snapshots, when you disable those 15-minute snapshots the old snapshots will disappear over the next hour.

Overall, zfstools works exactly as advertised. It creates new snapshots as scheduled, destroys old snapshots, and has very fine-grained control over what you’ll snapshot and when. The use of ZFS attributes to control which filesystems get snapshotted under which conditions doesn’t thrill me, but I’m biased towards configuration files and reading this configuration is really no worse than a config file.

I’ll try zfsnap next.

2 comments to FreeBSD ZFS snapshots with zfstools