世代管理用のファイルシステムBRTFS
BTRFSはB-tree file systemの略で、このファイルシステムはドキュメントやコード等の世代管理やバックアップに最適な機能が備えられています。
今回はDebian13を使って、このBTRFSを使って、世代管理とリモートへバックアップをしたいと思います。
ディスクの増設
ここでは既にDebianOSは動いていると仮定して、最初に物理ディスクを増設します。
なるべく物理ディスクを分けた方がいいですが、無理ならパーテーションを区切ってスペースを設けます。
OSを含んだ全体をBTRFSにするのは得策ではないようです。
また、バックアップ用のディスクなので、SSDよりHDDにしておいた方がいいと思います。
取り付けたら、OSを起動させlsblkで認識しているかを確認します。
# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8:0 0 465.8G 0 disk |-sda1 8:1 0 976M 0 part /boot/efi |-sda2 8:2 0 460.8G 0 part / `-sda3 8:3 0 4G 0 part [SWAP] sdb 8:16 0 931.5G 0 disk sr0 11:0 1 1024M 0 rom
パーテーションの作成
fdiskでパーテーションを作ります。
GPTで作成する場合は、gコマンドを入力します。
# fdisk /dev/sdb g Created a new GPT disklabel (GUID:....) n ... w ...
パーテーションタイプはデフォルトのLinux filesystemにしておきます。
btrfs領域のイニシャル
btrfs-progsをインストールし、フォーマットをします。
# apt install btrfs-progs # mkfs.btrfs /dev/sdb1 /dev/sdb1 appears to contain an existing filesystem (vfat) ERROR: use the -f option to force overwrite of /dev/sdb1 # mkfs.btrfs -f /dev/sdb1 ... # btrfs filesystem label /dev/sdb1 backupdisk
ディスクを再利用していたりすると、既にファイルシステムが存在すると警告を出します。そのままだとフォーマットが進まないので、問題なければ-fオプションをつけて実行します。
また管理時に分かりやすくするために、ディスクにラベルを付けています。すでにマウントしている場合はマウントポイントを指定します。
fstabを編集して常時マウントさせるようにします。
/etc/fstab
LABEL=backupdisk /mnt/bkupdisk btrfs defaults,compress=zstd,noatime,space_cache=v2 0 0fstabのオプションを説明しておきます。
- defaults
rw(読み書き),suid(SUID:/SGID:ビット有効),dev(デバイスファイル有効),exec(ファイル実行可能),auto(自動マウント),nouser(ユーザーマウント不可),async(非同期IO)
- compress=zstd
zstdで圧縮します
- noatime
ファイルアクセス毎のタイムスタンプの書き込みを抑制し、IOを減らします。
- space_cache=v2
空き領域をキャッシュしておく設定です。v1とv2があり、v2としておきます。
- autodefrag
オートデフラグ、細かなファイルの更新が多いなら設定します。Linuxのカーネルバージョン5.16.5未満の5.16.xの場合はデフラグの無限ループの不具合があるそうなので、このオプションを付けない方がいいです。
- nofail
状況により、今回はバックアップサーバーで必須ディスクなので、このオプションはつけません
サブボリューム
ファイルシステムをBTRFSにしたのは、スナップショットをディスク効率的に使って高速でとる為です。
スナップショットは、以降で設定する「サブボリューム」単位で管理することになります。
またzstdによる圧縮もメリットのひとつになります。
サブボリュームを作成するには btrfs subvolume create コマンドを使います。コマンドに続いてサブボリュームとするディレクトリを指定します。
サブボリューム作成時は既存のディレクトリは指定できません(既存ディレクトリを対象にしたい場合は退避して中身の移動をします)。また、BTRFS外の場所には作成できません。
コマンドを実行するとそこにディレクトリが生成され、サブボリュームとして管理されます。
サブボリュームとして作成したディレクトリを削除したい場合は、btrfs subvolume delete コマンドで削除します。
btrfs subvolume create /mnt/bkupdisk/test1 ... btrfs subvolume create /mnt/bkupdisk/test2 ... btrfs subvolume create /mnt/bkupdisk/test3 ... btrfs subvolume delete /mnt/bkupdisk/test2
作成したサブボリュームの確認をしたい場合は btrfs subvolume list を使います。
# btrfs subvolume list /mnt/bkupdisk ID 256 gen 18 top level 5 path test1 ID 260 gen 20 top level 5 path test2 ID 261 gen 20 top level 5 path test3
サブボリュームはネストして持てます。たとえばtest1の下にtest15というサブボリュームを作れます。
ただし、test1のスナップショットを取った時に、test15はそこには含まれないので注意が必要です。スナップショットは完全にサブボリューム単位で管理されます。
スナップショットの作成と運用
基本的なスナップショットの取り方は次のようになっています。
ここでも保存先は未存在のパスを指定する必要があります。保存先にはコマンド実行時のサブボリュームの中身が入ります。
-rオプションはリードオンリーオプションです。バックアップ目的の場合は一般的にオプションを付けるのが普通です。
ここで作成したスナップショットは、先ほど実行したサブボリュームのリストに加わります。
削除はサブボリュームと同様に行えます。
また、btrfs subvolume list -s と -sオプションをつけるとスナップショットだけの一覧となります。
# btrfs subvolume snapshot -r /mnt/bkupdisk/test2 /mnt/bkupdisk/snapshot ... # btrfs subvolume list ID 256 gen 18 top level 5 path test1 ID 260 gen 21 top level 5 path test2 ID 261 gen 20 top level 5 path test3 ID 267 gen 21 top level 5 path snapshot
復元時は、-rオプションを付けない snapshotを使い保存先とサブボリュームへのパスを逆にします。
先ほど実行したsnapshotをとるコマンドそのものですので、存在しないディレクトリを指定して新たにスナップショットを作ることもできます。
ファイル単位で復元したい場合は、スナップショットにはファイル構造がそのまま存在しますので、通常のcpコマンドを使います。
世代管理
スナップショットの取り方と復元を覚えたら、あとは何日残すか等の世代管理を設定し、cronで自動化します。
たとえば7日毎に削除するスクリプトは次のような感じに書くことができ、このスクリプトをcronに登録します。
daily-snap.sh
#!/bin/bash set -e SRC=/mnt/bkupdisk/data DST=/mnt/bkupdisk/.snapshot/ TODAY=$(date +%F) btrfs subvolume snapshot -r "$SRC" "$DST/data_$TODAY" cd "$DST" ls -1 data_* | sort | head -n -7 | xargs -r btrfs subvolume delete
btrfs subvolume list 中の gen
btrfs subvolume list 中に出てくる genは世代を意味するものですが、このgenはファイルシステム全体共通のカウンタ値で、スナップショットの作成などの操作によってインクリメントされます。
たとえば、test2のスナップショットを作った時のgenが(作る時に1加算されれ)30だととすると、スナップショットにも30というgenが付きます。そのあとに、test1のスナップショットをつくると、test1のgenは31となり、そのスナップショットのgenも31となります。
サブボリュームの中にファイルを追加したりするとgenの値はその時点のものとなります。リードオンリーにしたスナップショットは当時のgenから変更されることはありません。
サブボリュームのマウント
サブボリュームを指定してのマウントが可能です。イメージとしては mountの --bind オプションでディレクトリを別の場所へマウントする時と同じです。元の場所とマウンティングポイントのどちらを経由しても同じ実体を編集することができます。
マウントの方法は、さきほどの list で出力される名前でする方法と、IDで指定する方法があります。
mount -o subvol=test1 /dev/sdb1 /mnt/submount mount -o subvolid=256 /dev/sdb1 /mnt/submount
サブボリュームのquota
BTRFSでは、サブボリューム毎に容量の制限(quota)ができます。そのためにはまず設定を有効にさせなければいけません。
過去に不安定だった経緯もあり、quotaを利用しないなら無効にしておいた方がよいとの説明があります。
有効にするはマウントポイントを指定して、次のコマンドを実行します。
#btrfs quota enable /mnt/bkupdisk
制限を指定するには、btrfs qgroup limit を使います。limitのあとサイズを指定します。取り消す場合は noneを指定します。
現在の状況を確認するにはbtrfs qgroup showを使います。
Rferencedで共通利用量、Exclusiveで排他的使用量を表します。
# btrfs qgroup show /mnt/bkupdisk Qgroupid Referenced Exclusive Path -------- ---------- --------- ---- 0/5 16.00KiB 16.00KiB <toplevel> 0/256 16.00KiB 16.00KiB test1
send と receive
BorgBackupを使うので今回は使いませんが、別のマシンと同期するためのコマンドもあります。
btrfs sendコマンドでサブボリュームを作成するためのストリームが作成されます。
ストリームを後で説明するbtrfs receiveコマンドで処理する事でふたつのマシン間でサブボリュームを受け渡しできます。
この時に指定するサブボリュームはリードオンリーである必要があります。
-pオプションを付与すると、ふたつのサブボリュームの差分を抽出することができます。
-fオプションを付与すると、ストリームのかわりにファイルを作成します。この時のファイルは別のファイルシステムへ出力する事ができます。
btrfs receiveコマンドは先の、btrfs send コマンドで出力したストリームを受け取るコマンドです。-fをつけることにより、同様に-fオプションで出力したファイルを受信することができます。
引き数に渡すのは、btrfsのマウントポイントとなるディレクトリとなります。
sendの-pオプションで差分を送信する時は、receive側も元の環境と同じ親ディレクトリがある前提となっています。
sendからパイプするreceive側のコマンドをsshコマンドに置き換えリモート側でシェルを許可すれば、一文でリモートへのバックアップも実現できます。
初回は-pオプションを抜いた全件を送り、以降は差分を送り続けることでふたつのマシンの間で同期をとることができます。
