zfsnap2(面倒くさいので以降zfsnap)のおかげで気軽にzfs snapshotできるようになった。
あとはこれをcronに仕込んで日々、snapshotを取得、削除するだけである。

zfsnapをpkg、あるいはportsからインストールすると、cron用のシェルスクリプトも付いてくる。
これを加工してperiodic用のディレクトリに放り込めば、あとは全部、zfsnapがやってくれる。

基本はここを見ながら。
https://github.com/zfsnap/zfsnap/wiki/zfSnap-periodic.conf

なお、本稿で扱う周期、契機は日週月次に限る。

全体の流れ

  1. スナップショットの方針を決める
  2. cron用シェルスクリプトを日・週・月ごとのperiodicディレクトリにコピーし、ファイル名を変更する
  3. スクリプトの内容を修正する
  4. /etc/periodic.confにバックアップ方針に沿った設定を書き加える

では早速。

スナップショット方針を決める

ここでは簡単に、あるzpool丸ごとに対して;

  • 毎日のスナップショットは1週間と1日、保存する
  • 毎週のスナップショットは1か月と1日、保存する
  • 毎月のスナップショットは1年と1週間、保存する

とする

[補足]periodicから実行されるときのsnapname

zfsnap付属のスクリプトを使うと、snapnameの頭にdaily, weekly, monthlyと付く。
もちろん変更可能だが、本稿ではそのまま使う。

zfsnapのcron用スクリプトはどこにある

cron用スクリプトは、zfsnapインストール時にshareにコピーされる。
例えば以下のようにして探す

  
$ pkg list|grep zfsnap  
/usr/local/etc/bash_completion.d/zfsnap.sh  
/usr/local/man/man8/zfsnap.8.gz  
/usr/local/sbin/zfsnap  
/usr/local/share/doc/zfsnap/AUTHORS  
/usr/local/share/doc/zfsnap/NEWS  
/usr/local/share/doc/zfsnap/PORTABILITY  
/usr/local/share/doc/zfsnap/README.md  
/usr/local/share/examples/zfsnap/completion/zfsnap-completion.bash  
/usr/local/share/examples/zfsnap/completion/zfsnap-completion.tcsh  
/usr/local/share/examples/zfsnap/completion/zfsnap-completion.zsh  
/usr/local/share/examples/zfsnap/periodic/xPERIODICx_zfsnap.sh  
/usr/local/share/examples/zfsnap/periodic/xPERIODICx\_zfsnap\_delete.sh  
/usr/local/share/licenses/zfsnap2-2.0.0.b3/BSD3CLAUSE  
/usr/local/share/licenses/zfsnap2-2.0.0.b3/LICENSE  
/usr/local/share/licenses/zfsnap2-2.0.0.b3/catalog.mk  
/usr/local/share/zfsnap/commands/destroy.sh  
/usr/local/share/zfsnap/commands/recurseback.sh  
/usr/local/share/zfsnap/commands/snapshot.sh  
/usr/local/share/zfsnap/core.sh  
/usr/local/share/zsh/site-functions/_zfsnap

上記のうち以下が狙いのスクリプトである。
スナップショット取得用、削除用の2種類。
なお削除用はそのままでは期待する動作にならないので別記事で扱う。
/usr/local/share/examples/zfsnap/periodic/xPERIODICx_zfsnap.sh /usr/local/share/examples/zfsnap/periodic/xPERIODICx_zfsnap_delete.sh

スクリプトのコピーとファイル名の変更

さてこれを、日・週・月のperiodicディレクトリにコピーし設定していくが、まずは日次で試す。
日ごとのperiodicディレクトリは/usr/local/etc/periodic/dailyである。
ここにコピーし、ファイル名を変える。
ファイル名のxPERIODICxを、日次・週次・月次、どの周期用かに合わせて変える。
具体的にはそれぞれdaily, weekly, monthlyに。
以下の例では日次のスクリプトなので、dailyに変えている。
prefixの番号は好きなようにしたまえ。

$ cd /usr/local/etc/periodic/daily  
$ sudo cp /usr/local/share/examples/zfsnap/periodic/* .  
$ sudo mv ./xPERIODICx_zfsnap.sh ./500.daily_zfsnap.sh  
$ sudo mv ./xPERIODICx_zfsnap_delete.sh ./500.daily_zfsnap_delete.sh  
$ ls  
411.pkg-backup 500.daily_zfsnap_delete.sh 998.ntpdate  
490.status-pkg-changes 500.daily_zfsnap.sh smart

スクリプトの修正

スクリプト(取得用)の内容は以下の通りである。
変える場所はxPERIODICxとxPREFIXxである。
xPERIODICxは周期に合わせて、xPREFIXxはzfsnapの置いてあるパス、つまり/usr/local/sbin/zfsnapに。

#!/bin/sh

# This file is licensed under the BSD-3-Clause license.
# See the AUTHORS and LICENSE files for more information.

# If there is a global system configuration file, suck it in.
if [ -r /etc/defaults/periodic.conf ]; then
    . /etc/defaults/periodic.conf
    source_periodic_confs
fi

# xPERIODICx_zfsnap_enable          - Enable xPERIODICx snapshots (values: YES | NO)
# xPERIODICx_zfsnap_flags           - `zfsnap snapshot` flags
# xPERIODICx_zfsnap_fs              - Space-separated ZFS filesystems to create non-recursive snapshots
# xPERIODICx_zfsnap_recursive_fs    - Space-separated ZFS filesystems to create recursive snapshots
# xPERIODICx_zfsnap_ttl             - Explicit TTL value
# xPERIODICx_zfsnap_verbose         - Verbose output (values: YES | NO)
# xPERIODICx_zfsnap_enable_prefix   - Create snapshots with prefix (values: YES | NO) (Default = YES)
# xPERIODICx_zfsnap_prefix          - set prefix for snapshots (Default = xPERIODICx)

case "${xPERIODICx_zfsnap_enable-"NO"}" in
    [Yy][Ee][Ss])
        OPTIONS="$xPERIODICx_zfsnap_flags"

        case "${xPERIODICx_zfsnap_verbose-"NO"}" in
            [Yy][Ee][Ss]) OPTIONS="$OPTIONS -v" ;;
        esac

        case "${xPERIODICx_zfsnap_enable_prefix-"YES"}" in
            [Yy][Ee][Ss]) OPTIONS="$OPTIONS -p ${xPERIODICx_zfsnap_prefix:-"xPERIODICx-"}" ;;
        esac

        case 'xPERIODICx' in
            'hourly')
                default_ttl='3d'
                ;;
            'daily'|'reboot')
                default_ttl='1w'
                ;;
            'weekly')
                default_ttl='1m'
                ;;
            'monthly')
                default_ttl='6m'
                ;;
            *)
                printf '%s\n' "ERR: Unexpected error" >&2
                exit 1
                ;;
        esac

        xPREFIXx/zfsnap snapshot $OPTIONS -a ${xPERIODICx_zfsnap_ttl:-"$default_ttl"} $xPERIODICx_zfsnap_fs -r $xPERIODICx_zfsnap_recursive_fs
        exit $?
        ;;

    *)
        exit 0
        ;;
esac

# vim: set ts=4 sw=4:

vimなら:%s/xPERIODICx/daily/g などとコマンド叩いて一括置換する。
以下が修正後。

#!/bin/sh

# This file is licensed under the BSD-3-Clause license.
# See the AUTHORS and LICENSE files for more information.

# If there is a global system configuration file, suck it in.
if [ -r /etc/defaults/periodic.conf ]; then
    . /etc/defaults/periodic.conf
    source_periodic_confs
fi

# daily_zfsnap_enable          - Enable daily snapshots (values: YES | NO)
# daily_zfsnap_flags           - `zfsnap snapshot` flags
# daily_zfsnap_fs              - Space-separated ZFS filesystems to create non-recursive snapshots
# daily_zfsnap_recursive_fs    - Space-separated ZFS filesystems to create recursive snapshots
# daily_zfsnap_ttl             - Explicit TTL value
# daily_zfsnap_verbose         - Verbose output (values: YES | NO)
# daily_zfsnap_enable_prefix   - Create snapshots with prefix (values: YES | NO) (Default = YES)
# daily_zfsnap_prefix          - set prefix for snapshots (Default = daily)

case "${daily_zfsnap_enable-"NO"}" in
    [Yy][Ee][Ss])
        OPTIONS="$daily_zfsnap_flags"

        case "${daily_zfsnap_verbose-"NO"}" in
            [Yy][Ee][Ss]) OPTIONS="$OPTIONS -v" ;;
        esac

        case "${daily_zfsnap_enable_prefix-"YES"}" in
            [Yy][Ee][Ss]) OPTIONS="$OPTIONS -p ${daily_zfsnap_prefix:-"daily-"}" ;;
        esac

        case 'daily' in
            'hourly')
                default_ttl='3d'
                ;;
            'daily'|'reboot')
                default_ttl='1w'
                ;;
            'weekly')
                default_ttl='1m'
                ;;
            'monthly')
                default_ttl='6m'
                ;;
            *)
                printf '%s\n' "ERR: Unexpected error" >&2
                exit 1
                ;;
        esac

        /usr/local/sbin/zfsnap snapshot $OPTIONS -a ${daily_zfsnap_ttl:-"$default_ttl"} $daily_zfsnap_fs -r $daily_zfsnap_recursive_fs
        exit $?
        ;;

    *)
        exit 0
        ;;
esac

# vim: set ts=4 sw=4:

削除用も同じようにしたら、periodic.confに指示を書き入れる。

/etc/periodic.confにおけるzfsnap設定の書式

/etc/periodic.confは無ければ作る。
zfsnapのperiodic向け書式は以下の通り。
https://github.com/zfsnap/zfsnap/wiki/zfSnap-periodic.conf

以下、日次のものとして記す。
週、月次の場合はdailyをそれぞれweekly, monthlyに変えればよい。

snapshot取得の有効化

daily_zfsnap_enable
YES/NOで指定

共通オプション(generic option)

daily_zfsnap_flags
例えばscrub, resilver中は避け、日付シリアルの秒を切り捨て、というような設定をここで行う。
-v, -dを指定しないこと。
初めて作るときにはテスト実行オプションを付けて試験する。

zfs, zpoolの指定

daily_zfsnap_fs
daily_zfsnap_recursive_fs
recursiveとなっているのは、当然ながら子孫も含めて再帰的に取得される
複数あるなら、スペースを空けて列挙

冗長アウトプット指定

daily_zfsnap_verbose
YES/NOで指定

保存期間指定

daily_zfsnap_ttl
指定がなければ日次は1週間、週次は1か月、月次は6か月になる。

スナップショット削除有効化

daily_zfsnap_delete_enable
YES/NOで指定

periodic.conf例

ということで、periodic.confに追加したのは以下の通り。

# zfsnap_daily  
daily_zfsnap_enable="YES"  
daily_zfsnap_recursive_fs="vault"  
daily_zfsnap_verbose="YES"  
daily_zfsnap_delete_enable="YES"  
daily_zfsnap_flags="-n -s -S -z"  
daily_zfsnap_ttl="1w1d"

試験

zfsnap_flagsに-nを付けた状態で試験。

$ sudo /usr/local/etc/periodic/daily/500.daily_zfsnap.sh  
/sbin/zfs snapshot vault/chamber@daily-2018-12-03_02.14.00-1w1d  
/sbin/zfs snapshot vault/itunes@daily-2018-12-03_02.14.00-1w1d

大丈夫そうなので-nを外す。

最終的なperiodic.confの結果

週次、月次で同じようにperiodic用のスクリプトを作成する。

$ pwd
/usr/local/etc/periodic
$ find ./ -name '*zfsnap*'
./weekly/999.weekly_zfsnap.sh
./weekly/999.weekly_zfsnap_delete.sh
./daily/500.daily_zfsnap.sh
./daily/500.daily_zfsnap_delete.sh
./monthly/910.monthly_zfsnap.sh
./monthly/910.monthly_zfsnap_delete.sh

最終的なperiodic.confの結果は以下の通り。

# zfsnap_weekly
weekly_zfsnap_enable="YES"
weekly_zfsnap_recursive_fs="vault"
weekly_zfsnap_verbose="YES"
weekly_zfsnap_delete_enable="YES"
weekly_zfsnap_flags="-s -S -z"
weekly_zfsnap_ttl="1m1d"
# zfsnap_daily
daily_zfsnap_enable="YES"
daily_zfsnap_recursive_fs="vault"
daily_zfsnap_verbose="YES"
daily_zfsnap_delete_enable="YES"
daily_zfsnap_flags="-s -S -z"
daily_zfsnap_ttl="1w1d"
# zfsnap_monthly
monthly_zfsnap_enable="YES"
monthly_zfsnap_recursive_fs="vault"
monthly_zfsnap_verbose="YES"
monthly_zfsnap_delete_enable="YES"
monthly_zfsnap_flags="-s -S -z"
monthly_zfsnap_ttl="1y1d"

翌日以降、root宛には以下のようなメールが届くので、結果はここで確認する。

/sbin/zfs snapshot -r vault@daily-2018-12-02_04.47.00-1w1d ... DONE