CentOS7 (1511) でbtrfsのスナップショットを定期的に保存するようにした。

前の記事で省いた、btrfsのスナップショットまわりについて。

btrfsのスナップショット便利だから、みんな使った方がいいよという話。

概要

前に記事に書いたように、システムのバックアップについては、別の外付けドライブを用意してある。このバックアップは、バックアップスクリプトの中で細工をして、grub設定ファイルやfstabなどは調整ずみであり、すぐに起動できるようになっている。

当然これは、起動ドライブが壊れるたらどうしよう、という意味でのバックアップにはなっているのだが、これとは別に、ファイルを誤って削除したらどうしよう、という意味でのバックアップも用意する必要がある。

幸い、btrfsにはスナップショット機能がついており、重複ファイル分の容量を気にせずスナップショットを作りまくれるので、今回はこれを利用することにした。

スナップショットの前に、サブボリュームの理解

snapshotの前に、snapshotをとる対象になる、subvolumeについておさらいしておく。

btrfsをただ作成した時には、サブボリュームがないただのファイルシステムのように見える。これを適当な場所にマウントし、マウントした場所にcdしてから下記コマンドでサブボリュームを作成できる。

btrfs subvolume create hogehoge 

これで、btrfsのトップレベルの下に、hogehogeサブボリュームができた。hogehogeの下に入ってもう一度スナップショットを作成すれば、ネストしたスナップショットの作成、というのも当然できる。また、ここで、マウントしていないとサブボリュームの追加ができない、という点に注意しておきたい(当然、削除や、スナップショットも)。

このhogehogeサブボリュームは、マウント時や、fstabにオプションを指定することによって、直接好きなディレクトリにマウントすることができる。デフォルトのマウントオプションでは、トップレベルがマウントされるようになっているため、最初に空のbtrfsをマウントした時に、トップレベルが見えていたというわけ(このデフォルトでマウントされるサブボリュームは、実はファイルシステムの設定で変更可能。でも、変更したらトップレベルをマウントするのが大変になるので、やらないほうがよさそう)。

なお、うちのCentOS7では、rootサブボリュームを / にマウントしている。スナップショットをとったり、復元したりする際の操作の煩雑さを軽減するためには、このように / のマウントポイントを独立したサブボリュームで持つのがベターと思う。

スナップショットを作る

サブボリュームができたので、次は、スナップショットを作成してみる。先ほどの、トップレベルディレクトリに戻って、次のコマンド。

btrfs subvolume snapshot hogehoge hugahuga

これでhogehogeのスナップショットhugahugaが作成され、同じディレクトリにhugahugaが見えていることがわかる。

サブボリュームの削除は、

btrfs subvolume delete hogehoge

サブボリュームの名称変更は、たとえば、トップレベルで

mv hugahuga higehige

するだけでできる。

参考URLから引用すると、

スナップショットは、サブボリュームの特殊な形です。サブボリュームのコピーですが、親や子となるサブボリュームを持ちません。スナップショットは、ファイルのコピーを作成せず、元のサブボリュームのデータやメタデータを共有します。そのため、領域の節約になり、作成速度も速くなります。元のサブボリュームとは独立しているため、スナップショットにファイルを追加しても、元のサブボリュームには追加されません。スナップショットのスナップショットも作成できますが、それぞれ、別々のものとして扱われます。

とのことなので、スナップショットがそれ自体サブボリュームなっており、そのまま簡単にマウントできるというカラクリになっている。スナップショットがマウントされたファイルシステムのようにそのまま見えることや、名称変更が簡単なことと合わせて、使いやすい機能になっている。

1日1回スナップショットを作成するスクリプト

/etc/cron.daily/make_snapshots に下記スクリプトを置くことで、1日1回スナップショットを作成している。

#!/bin/bash -e
DATE=$(date +"%Y%m%d")
DATED=$(date +"%d")
DATEMD=$(date +"%m%d")

for dir in home root; do
    if [ x${DATED} = x01 ]; then
        for sub in /root/snapshots/${dir}_*${DATEMD}; do
            if [ -d $sub ]; then btrfs subvolume delete $sub; fi
        done
    else
        for sub in /root/snapshots/${dir}_*${DATED}; do
            if [ -d $sub ]; then btrfs subvolume delete $sub; fi
        done
    fi
    if [ $dir = home ]; then
        src=/home
    else
        src=/
    fi
    last=/root/snapshots/${dir}_last
    if [ -d $last ]; then btrfs subvolume delete $last; fi
    btrfs subvolume snapshot $src $last
    btrfs subvolume snapshot $src /root/snapshots/${dir}_${DATE}
done

上のスクリプトで、 / には root サブボリュームを、/home には home サブボリュームを、 /root/snapshots には snapshots サブボリュームをマウントしてある。

毎月1日のスナップショットは1年分残し、その他の日付のスナップショットは、前回分を削除してから新しいものを作る、つまり、だいたい1か月分くらいを保存しておく、という作りになっている。また、 root_last や home_last という名前で、常に直近のスナップショットを残してある。

万が一、設定ファイルが壊れたり、home下の超重要なファイルを消してしまった場合には、適当な snapshot の中の同名ファイルを見つけて cp で普通に戻すか、大規模にやられてしまったなら、 root や home のサブボリューム自体を別名に変えてから、スナップショットを root や home そのものに変えてしまってもよい(btrfsのトップレベルを適当な場所にマウントして、その中で操作することにより、 / をマウントしたままで、 root のサブボリュームの名前を変更できます)。

(なお、前の記事で書いたバックアップの外付けドライブの方でも、バックアップ直後に下記スクリプトをどうさせることで、週1回スナップショットを作っている。)

感想とか

CentOS7を入れて当初からbtrfsを使ってはいたのだけれども、今までスナップショットでバックアップを取るということはしていなかった。

実際にやってみたら、コマンドが多くはないし、スナップショットやサブボリュームが普通のファイルシステムとしてマウントできて、ネストしたものが普通のディレクトリのようにみえるということで、使い勝手がよいもので、もっと早く試しておけばよかった。

そうはいっても、まだまだbtrfsは開発中ということで、300GBのデータが詰まったext4のデータドライブを、btrfsにconvertするということはちょっと不安なので、まだまだできない。今のデータドライブの容量がひっ迫して次のデータドライブが必要になった時には、btrfsにしてスナップショットの恩恵にあずかりたいと思う。

参考
man btrfs
参考URL
https://jp.linux.com/Linux%20Jp/tutorial/415460-tutorial20140407
https://docs.oracle.com/cd/E39368_01/b71105/ol_use_case3_btrfs.html

CentOS7 (1511) でbtrfsのスナップショットを定期的に保存するようにした。」への2件のフィードバック

コメントを残す