zfsは本当に本当に便利で助かるのだが、それでも面倒なことはある。
私にとって面倒なのは、スナップショット作成とスナップショットの差分転送である。

スナップショットの簡素化について。
スナップショットを作成する際には、ファイルシステムやボリュームに続けてスナップショットの名前、スナップネームを指定する必要がある。
スナップネームはスナップショットを特定するために必要なものなので文句を言う筋合いはないのだが、いちいち名前を付けるのが面倒なんである。日付でもなんでも自動的に付けてほしい。

なんとか改善したくていろいろ調べてみた。

スナップショット取得補助ツール

スナップショット関連ではzfstools, zfsnap2, zapの三つを調べた。
結論から言うと、zfsnap2を選択した。

zfstools

https://github.com/bdrewery/zfstools
https://www.freshports.org/sysutils/zfstools/
よさそうだけどruby依存なのでその一点で対象外に。
このツールのためだけにrubyを入れますか、という話で。
なるべく依存の少ないツールがよい。

zap

https://www.freshports.org/sysutils/zap
https://github.com/Jehops/zap
よさそうだけど、zfsに独自のプロパティ(zap:)を設定する必要があるっぽい。
独自プロパティの設定が、zfsとして許容されている作法であっても、対象のファイルシステムに何らかの手を加えるのは躊躇する

zfsnap2

https://www.freshports.org/sysutils/zfsnap2
https://github.com/zfsnap/zfsnap
単純なシェルスクリプト。
よさそう。

zfsnap2 お手軽snapshot

まず、zfsnap2は、取得すると日付シリアルをsnapnameに付けてくれる。
例えば。

vault/chamber@2018-11-11_09.48.00-1y

ご覧の通り2018/11/11 09:48:00と日付をsnapnameに付ける
なお、末尾に1yと書いてあるがこれは1年という意味である。
これは何かというと(次項につづく)

zfsnap2 snapshot削除の仕組みとTTL

snapshotは取得するだけでなく、消す方の面倒を見ることも重要。
zfsnap2は、取得したタイムスタンプとTTL(Time To Live)をsnapnameに含めておくのがアイデア(他みも同じようなツールあるかもしれないけど)。
先ほどの例でいえば、末尾の1yがそれ。1yだから1 year、1年ですな。

vault/chamber@2018-11-11_09.48.00-1y

上記の通り、取得日付、保存期間をsnapname自体に持たせるので、ツール側では状態を記憶しておく必要がない。
削除を指示されたら、zfsnap2はその都度、snapnameだけを見て判断・処理をするということ。
何より人間もsnapnameから保存期限を判断できる。これはよい。

とりあえず使う

管理者権限でzfsnap snapshotに続けてzfs/zpoolを指定するだけ。
日付も付けてくれる。

  
# zfsnap snapshot zroot/var/tmp  
$ zfs list -t snapshot|grep 'zroot/var/tmp';  
zroot/var/tmp@20181120 56K - 88K -  
zroot/var/tmp@2018-12-01_22.19.13-1m 0 - 88K -

zfsnap書式概要

詳細はman等するとして、概要を示す。
書式は以下の通り。

zfsnap コマンド <共通オプション> <個別オプション> zpool/zfs

zfsnapのコマンド

コマンドにはsnapshot, destroy, recursebackの三つがある。
それらに続けてzpool, zfsを指定する。こちらの指定は複数でもよい。
共通オプション(generic option)は、その名の通り、共通的なオプション。
個別オプションはzpool, zfsごとのオプションである。

コマンドのsnapshot, destroyは当然ながらそれぞれsnapshot作成、削除。
recursebackは、zfs rollbackの拡張で、rollbackの際、指定のdataset配下すべてをrollbackするもの。
本稿では扱わない。

共通オプション(generic option)

主なものだけ示す

  • -s  : resilver中は作業しない
  • -S : scrub中は作業しない
  • -z : 日付シリアルの秒切り捨て(18:06:15を18:06:00にする)
  • -n : dry run。テスト実行。ファイルシステムに変更を加えない。
  • -v : 冗長output

-s, -Sは常時付けておいたほうがいいかな。

個別オプション

個別オプションなので、これに続けて指定されたzpool/zfsにのみ効果がある。
主なものだけ示す

  • -a : TTL。指定がなければ1m = 1か月
  • -r : 再帰オプション。再帰的にsnapshotを取得
  • -R : 非再帰オプション。再帰的なsnapshotを取得「しない」

TTLオプション

以下のうち、必要なものだけをズラズラ書けばよい

  • y : 年(365日)
  • m : 月(30日)
  • w : 週(7日)
  • d : 日
  • h : 時
  • M : 分
  • s : 秒

1週間と1日なら-a 1w1d。
2か月なら-a 2m。

実行例

以上を踏まえて;
resilver, scrub中は実行せず、日付シリアルの秒切り捨て、冗長アウトプットでsnapshotをテスト実行。
対象zfsその1はzroot/usrで、再帰的に取得し、TTLは1週間と1日。その2はzroot/ROOTで、再帰的に取得「せず」、TTLは1分。
という実行例。

# zfsnap snapshot -sSvzn -a1w1d -r zroot/usr -R -a1M zroot/ROOT  
/sbin/zfs snapshot -r zroot/usr@2018-12-01_22.33.00-1w1d  
/sbin/zfs snapshot zroot/ROOT@2018-12-01_22.33.00-1M

よさそうなのでテスト実行オプションを省いて本番実行すると;

# zfsnap snapshot -sSvz -a1w1d -r zroot/usr -R -a1M zroot/ROOT  
/sbin/zfs snapshot -r zroot/usr@2018-12-01_22.34.00-1w1d ... DONE  
/sbin/zfs snapshot zroot/ROOT@2018-12-01_22.34.00-1M ... DONE

zfs listで結果を確認。zroot/usrにのみ配下にもスナップショットが出来ている。

$ zfs list -t snapshot | grep '2018-12-01';  
zroot/ROOT@2018-12-01_22.34.00-1M 0 - 88K -  
zroot/usr@2018-12-01_22.34.00-1w1d 0 - 88K -  
zroot/usr/home@2018-12-01_22.34.00-1w1d 0 - 5.97M -  
zroot/usr/ports@2018-12-01_22.34.00-1w1d 0 - 88K -  
zroot/usr/src@2018-12-01_22.34.00-1w1d 0 - 88K -

では削除のほうも。
zroot/ROOT、zroot/usr配下のTTL切れsnapshotを削除
ただしzroot/ROOTは非再帰的、zroot/usrは再帰的に。
テスト実行。

# zfsnap destroy -sSvn -R zroot/ROOT -r zroot/usr  
/sbin/zfs destroy zroot/ROOT@2018-12-01_22.34.00-1M

期限切れはzroot/ROOT@2018-12-01_22.34.00-1Mのみ。
じゃ、それで本番実行

# zfsnap destroy -sSv -R zroot/ROOT -r zroot/usr  
/sbin/zfs destroy zroot/ROOT@2018-12-01_22.34.00-1M ... DONE

以上。