hokuishi.be

Btrfs のスナップショットと tar でのバックアップ

2023/05/23

目次

はじめに

普段使いのラップトップは Arch Linux で動いていて、主にプログラミングや学校の課題などに使っています。 というかデスクトップ PC を持っていないので、 PC 上で行う作業は全てこのラップトップでやっています。 一年程前までは Timeshift で定期的にシステムバックアップを取っていたのですが、最近は面倒になってずっとバックアップを取っておらず、 OS や PC が壊れて書きかけの課題が消し飛んだり、普段の生活ができなったりする不安がありました。 そこで今一度バックアップの必要性やどのように行うべきかを考え、「Btrfs のスナップショット取得と tar でのバックアップ」をするという結論になったため、その時の思考とやったことのログを残すために書きます。

この時の記録は Scrapbox にもあります。

懸念事項

バックアップを取っていない場合の心配事として主に以下の二つがありました。

  • システムやカーネルのアップデートに万が一不具合があって壊れる (または rm -rf /* による事故)
  • 間違えて rm コマンドなどでファイルを削除してしまう

前者はシステムバックアップ、後者はデータバックアップを行うことで対処できます。 システムが壊れるタイミングはパッケージマネージャのアップデート (paru -Syu) 後で、PC が長い間使えないのは困るのでトラブル時は早急に復活させたいと思いました。 そのため、フルバックアップを毎回行い、バックアップのタイミングは週 1 回程度の paru -Syu 直前かつ、保管場所は同じ PC のストレージ以外が良いです。 またデータは刻々と移り変わっていくため、できれば毎日データバックアップがあると安心です。

Ext4 から Btrfs への移行

バックアップをするために、その前にスナップショットを取りたいと思いましたが、その方法は主に二つありました。

  • LVM で論理ボリュームを確保してそこにスナップショットを格納する
  • Btrfs の機能でスナップショットを取る

この時のファイルシステムは Ext4 でしたが、 Btrfs のスナップショットは CoW を用いた機能のため高速かつ効率的だと思い、 Ext4 から Btrfs に移行することにしました。

その時の手順は Scrapbox に書いてあります。

  1. 予め dd コマンドなどでバックアップを取っておく
  2. Live USB から Linux を起動
  3. # cryptsetup open --type luks /dev/nvme0n1p2 vg0 でパスワードを入力し、暗号化されている移行元のパーティションをマウントできるようにする
  4. # btrfs-convert /dev/mapper/vg0-root でファイルシステムを変換
  5. /etc/fstab を編集 (UUID の変更、ファイルシステム名を btrfs に変更、最後のフィールドを 0 に変更)
# <file system> <dir> <type> <options> <dump> <pass>
# /dev/mapper/vg0-root
UUID=a0bb3c42-0485-4367-90dd-5be4956344d3	/         	btrfs      	rw,relatime	0 0
  1. # arch-chroot /dev/mapper/vg0-root
  2. # mkinitcpio -p linux
  3. # btrfs subvolume delete /ext2_saved
  4. # btrfs balance start / (これがなぜかエラーで失敗する)
  5. # btrfs filesystem defragment -r -v -czstd / で透過的自動圧縮を適用 (zstd にした)

Btrfs でのサブボリューム設計

(追記:2023/05/21) Btrfs でのサブボリューム設計を見直して //home を分けてスナップショットが取られるようになりました。 詳しいことは Scrapbox に書きました。

サブボリューム マウントポイント
/ (id=5) /
@home /home
@snapshots /snapshots

この設計に則ってサブボリュームを生成する手順は以下です。

  1. # btrfs subvolume create /@home
  2. # rsync -av --links /home /@home
  3. # mount /dev/mapper/vg0-root -o subvol=/@home /home
  4. /etc/fstabUUID=6e62ce5d-407e-4265-abba-c4bf30ee8d06 /home btrfs rw,relatime,ssd,space_cache,subvolid=380,subvol=/@home,compress=zstd 0 0 を追加、 UUID=/dev/mapper/vg0-root のものにして subvolid= は適切なものにする
  5. # mount -a や再起動で fstab の変更を適用する
  6. @snapshots も同様に生成してからマウントする

バックアップの方針

バックアップの方針を以下のようにしました。

  • システムバックアップは週 1 回程度で paru -Syu の前に行う
  • / のバックアップを tar で取りクラウドに保管する
  • /home のバックアップは tar で取らず、数時間毎に Btrfs でのスナップショットを取るのみ

スナップショットを取る

以下のようなスクリプトを作成し、 fcron のジョブで 2 時間毎にスナップショットを取るようにしました。 とりあえずは過去 5 個分のスナップショットをローカルに持っておくようにしました。

#!/bin/bash
# take a snapshot

date=$(date "+%F_%H-%M-%S")

if [ $1 = '/' ]; then
	snapshot_dir="/snapshots/root"
elif [ $1 = '/home' ]; then
	snapshot_dir="/snapshots/home"
else
	echo "invalid argument: first argument must be / or /home"
	exit 1
fi

if [ 5 -le $(ls -1U ${snapshot_dir} | wc -l) ]; then
	oldest_snapshot="$(ls -rt ${snapshot_dir} | tail -n1)"
	btrfs subvolume delete ${snapshot_dir}/${oldest_snapshot}
fi

if [ -e ${snapshot_dir}/${date} ]; then
	echo "snapshot is already exist"
	exit 1
else
	btrfs subvolume snapshot -r $1 ${snapshot_dir}/${date}
fi

tar でのバックアップ

以下のスクリプトを手動で実行して、アーカイブファイルを手動でクラウドに保存します。 本当は Dropbox などでローカルにあるファイルと同期させる方がスマートで良かったのですが、複数回分のバックアップをローカルに置いておくとディスクの容量を圧迫して嫌なのでクラウドのみに保存するようにしました。

#!/bin/bash
# system backup

echo "taking a snapshot"

snapshot $1

echo "creating a tar archive file"

if [ $1 = '/' ]; then
	dir_name="root"
elif [ $1 = '/home' ]; then
	dir_name="home"
else
	echo "invalid argument: first argument must be / or /home"
	exit 1
fi

backup_dir="/backup"
snapshot_dir="/snapshots/${dir_name}"
exclude_file="/backup/exclude.txt"

latest_snapshot="$(ls -rt ${snapshot_dir} | head -n1)"

nice tar cvpf ${backup_dir}/${dir_name}_${latest_snapshot}.tar.xz \
	--sparse \
	--use-compress-prog=pixz \
	--xattrs \
	--exclude-from=${exclude_file} \
	-C ${snapshot_dir}/${latest_snapshot} \
	. \
	> ${backup_dir}/${dir_name}_${latest_snapshot}.log

まとめ

Btrfs のスナップショットを fcron で数時間毎に取り、パッケージアップデートの前に tar でフルシステムバックアップを取ることで、システムの破損とユーザデータの誤消去に対処できるようになったと思います。 dotfiles に加えて、これらのバックアップを取ることで安心して PC を使えるようになりました。

参考