サーバのファイルシステムをZFSにしたので、だんだんスナップショットが溜まってきました。そうなると、やっぱり古いのを自動で消したくなります。

普通だとcronで1日1回スナップショットを取って、n日より前のスナップショットは消して、みたいな運用が多いと思います。まあ常時通電してる場合はそれがいちばん単純で分かりやすい。

ですが、ウチの個人用サーバみたいに、使うときだけ電源入れるやつだと(そんなのサーバじゃないよ、という議論は置いといて)、スナップショットを取るのも不定期になります。基本は寝る前に電源を落とすので、シェルスクリプトでシャットダウンの直前にスナップショットを取ってるんですが、たまに今週は一度も電源入れなかったなー、なんてこともあるので、単純に「5日より前のスナップショットは消す」などのルールにすると、履歴が1コも無くなっちゃったりします。

となると、ファイルシステムごとにスナップショットの保持数を決めておいて、それを超えたら古いやつから消して行くのがよさげ。シェルスクリプトにするとこんな感じでしょうか。

#!/bin/sh
cleanup () {
    for s in $(zfs list -H -o name -S creation -t snapshot | grep ^$1@ | sed 1,$2d); do
      zfs destroy $s
    done
}

cleanup tank/foo 100
cleanup tank/foo/bar 10
cleanup tank/baz 1

cleanup関数の第1引数は対象のファイルシステム、第2引数はスナップショットの保持数です。

zfs listコマンドのオプションの意味は次のとおり。

  • -H …ヘッダ抑止
  • -o name …データセット名のみ出力
  • -S creation …作成日の降順にソート
  • -t snapshot …スナップショットの一覧を表示

このzfs listの結果から、第1引数で指定されたファイルシステムだけgrepして、sedで1行目から保持数行目までを飛ばして、それ以降のものをひとつずつzfs destroyして行きます。

今日のスナップショットを取ったあと、かつシャットダウンの前にこれを実行するようにしたので、もう古いスナップショットは気にしなくて済みそうです。

※バージョンメモ

  • FreeBSD 9.1-RELEASE-p0 amd64