増分オフサイトバックアップ用にBtrfsの送信と受信を設定する方法

エヴァ・ウォンテクニカルライター であり ZimaSpaceの常駐ティンカーでもあります。 生涯のオタクであり、 ホームラボとオープンソースソフトウェアに情熱を持っています。彼女は複雑な技術的概念をわかりやすく、 実践的なガイドに翻訳することを専門としています。エヴァはセルフホスティングは楽しくあるべきで、怖がるものではないと信じています。彼女のチュートリアルを通じて、コミュニティが ハードウェアのセットアップを解明する手助けをしています。初めてのNAS構築からDockerコンテナの習得まで。

Btrfsのsendとreceiveを使うと、読み取り専用サブボリュームスナップショットを効率的なオフサイト複製チェーンにできます。最初の転送では、完全なスナップショットを送信します。以降の転送では、以前に複製したスナップショットを親として使用するため、新しいスナップショットを再構築するために必要な変更だけがネットワーク経由で送信されます。

ZimaOSでは、まずソースとオフサイトの宛先が実際にBtrfsファイルシステムであること、そしてSSHアクセスが利用できることを確認してください。ZimaSpaceの最新のディスク形式ガイドにはBTRFSの読み書きサポートが記載されています。また、ZimaOSのSSHガイドでは、開発者モードからターミナルアクセスを有効にする方法が説明されています。

バックアップチェーンを開始前に理解する

Btrfsのsend/receiveはサブボリュームの複製であり、汎用的なディレクトリコピーコマンドではありません。ソースはBtrfsサブボリュームでなければならず、使用するすべてのスナップショットは btrfs send 読み取り専用でなければなりません。読み取り専用マウントは、読み取り専用サブボリュームスナップショットの代わりにはなりません。

公式のbtrfs sendドキュメントでは、2つのモードが説明されています。完全送信にはスナップショット全体が含まれます。増分送信では、送信側と受信側の両方で同じ状態で利用できるスナップショットとともに、-pまたは-cを使用します。

単純なオフサイトチェーンでは、明示的な親を1つ指定して -p:

snapshot-A  --full send-->  オフサイトのsnapshot-A
snapshot-B  --send -p A-->  オフサイトのsnapshot-B
snapshot-C  --send -p B-->  オフサイトのsnapshot-C

次の増分転送が完了して検証されるまで、現在の親を削除したり変更したりしないでください。

ソースがBtrfsサブボリュームであることを確認する

例のパスを、システム上の実際のマウントポイントに置き換えてください。バックアップスナップショットが保護対象のデータ内に入れ子にならないよう、スナップショットディレクトリは稼働中のソースサブボリュームの外側に配置してください。

findmnt -no FSTYPE --target /mnt/pool/data
sudo btrfs subvolume show /mnt/pool/data
sudo btrfs version

1つ目のコマンドでは、次のように表示されるはずです btrfs。2つ目は正常に識別できる必要があります /mnt/pool/data サブボリュームとして扱います。通常のディレクトリにすぎない場合は、ここで中止してください。 btrfs send 任意のディレクトリを送信することはできません。

オフサイトシステムの受信先でも、同じファイルシステムチェックを実行します。 btrfs receive Btrfsファイルシステム上に、その複製サブボリュームを作成する必要があります。

バックアップデータをストリーミングする前にSSHを準備する

オフサイト送信ストリームはバイナリのファイルシステムデータです。SSHは、転送中の認証と暗号化を提供する実用的なトランスポートです。いずれかのエンドポイントでZimaOSを使用している場合は、まずSSHを有効にし、Btrfsストリームを試す前に通常のログインをテストしてください。

ssh backup@backup.example.net

自動実行ジョブでは、鍵ベースのSSH認証を使用します。リモートアカウントは、次も実行できる必要があります。 btrfs receive 非対話的に実行してください。リモートの sudo Btrfsストリームを運ぶ同じ標準入力からパスワードプロンプトが読み取られます。必要な受信操作に限定した権限ルールは、広範なパスワードなしのrootアクセスより安全です。

対話的な管理セッション中に宛先ディレクトリを作成します。

ssh -t backup@backup.example.net \
  'sudo mkdir -p /mnt/backup/btrfs-recv'

最初の読み取り専用スナップショットを作成する

稼働中のソースサブボリュームの固定された読み取り専用スナップショットを作成します。 -r このフラグが重要なのは、Btrfsの増分送信が、送信処理中に変更されないスナップショットに依存するためです。

sudo mkdir -p /mnt/pool/.snapshots

sudo btrfs subvolume snapshot -r \
  /mnt/pool/data \
  /mnt/pool/.snapshots/data-20260831-1000

送信前にプロパティを確認します。

sudo btrfs property get \
  /mnt/pool/.snapshots/data-20260831-1000 ro

期待される結果は次のとおりです。 ro=true.

初回のフルスナップショットをオフサイトに送信する

最初の転送には親がないため、フル送信になります。Bash互換シェルでは、次を有効にします。 pipefail を指定すると、パイプラインのどちら側で発生した失敗も呼び出し元のシェルに通知されます。

set -o pipefail

sudo btrfs send \
  /mnt/pool/.snapshots/data-20260831-1000 \
  | ssh backup@backup.example.net \
  'sudo -n btrfs receive /mnt/backup/btrfs-recv'

もし sudo -n リモートホストで失敗する場合は、再試行する前にリモートの権限設定を修正してください。ストリーミングパイプライン内でパスワードプロンプトに置き換えないでください。

公式のbtrfs receiveドキュメントには、正常に受信されたサブボリュームは読み取り専用になると記載されています。また、ストリームの適用中は受信パスを変更しないよう警告しています。

親として使用する前に受信スナップショットを確認する

SSHセッションが終了したからといって、バックアップチェーンが正常だと判断しないでください。両方のスナップショットを調べます。

sudo btrfs subvolume show \
  /mnt/pool/.snapshots/data-20260831-1000

ssh backup@backup.example.net \
  'sudo -n btrfs subvolume show \
  /mnt/backup/btrfs-recv/data-20260831-1000'

送信側で、スナップショットを確認します。 UUID受信側では、複製されたサブボリュームに、そのソース識別子がUUIDとして表示されるはずです。 受信済みUUID受信したサブボリュームが読み取り専用であることも確認します。

この確認を行ってから、 data-20260831-1000 次の増分バックアップの親にします。

次の増分スナップショットを作成して送信する

稼働中のデータが変更されたら、新しい読み取り専用スナップショットを作成します。

sudo btrfs subvolume snapshot -r \
  /mnt/pool/data \
  /mnt/pool/.snapshots/data-20260901-0200

続いて、前回のスナップショットとの差分のみを送信します。

set -o pipefail

sudo btrfs send \
  -p /mnt/pool/.snapshots/data-20260831-1000 \
  /mnt/pool/.snapshots/data-20260901-0200 \
  | ssh backup@backup.example.net \
  'sudo -n btrfs receive /mnt/backup/btrfs-recv'

最初の送信元の親スナップショットが、両方のシステムに一致する形で残っているため、これが機能します。新しいスナップショットが正常に受信され、検証されたら、 data-20260901-0200 次回の実行の親として使用できるようになります。

親スナップショットを同一に保つ

増分チェーンを壊す最も一般的な方法は、親として使用されているスナップショットの読み取り専用状態または内容を変更することです。Btrfsは、送信側と受信側が対応する履歴を識別できるよう、受信したスナップショットを受信UUIDで追跡します。

サブボリュームフラグと受信UUIDに関する公式のBtrfsガイダンスでは、受信したスナップショットを読み取り専用から読み書き可能に変更すると、増分送信で使用される前提が崩れると警告しています。

そのため、閲覧、復元、またはファイルの編集だけを目的に、オフサイトの受信スナップショットを書き込み可能に変更しないでください。書き込み可能な復元コピーが必要な場合は、保護された受信スナップショットから別のスナップショットを作成してください。

sudo btrfs subvolume snapshot \
  /mnt/backup/btrfs-recv/data-20260901-0200 \
  /mnt/restore/data-20260901-0200

新しい復元スナップショットはデフォルトで書き込み可能ですが、元の受信スナップショットは今後の増分送信に備えてそのまま維持されます。

安全なスナップショット保持ルールを使用する

古いスナップショットをすべて永遠に保持する必要はありませんが、次回の送信に必要な親を両方のシステムで保持する必要があります。簡単なローテーションルールは次のとおりです。

  1. 新しい読み取り専用のソーススナップショットを作成します。
  2. 前回成功したスナップショットを使用して送信します。 -p.
  3. 新しいオフサイト受信スナップショットを検証します。
  4. 新しいスナップショットを次の親に設定します。
  5. その後で、保持ポリシーに従って古い復元ポイントを削除します。

複数の過去のスナップショットを保持すると、ロールバックに役立つ復元ポイントを確保できます。ただし、同じファイルシステム上のスナップショットは独立したバックアップではないことに注意してください。オフサイトレプリカに価値があるのは、別のシステムと場所にもう1つのコピーを置けるためです。ZimaSpaceの3-2-1バックアップガイドでは、ローカル冗長化では対処できない障害からオフサイトコピーがどのように保護するかを説明しています。

入れ子のBtrfsサブボリュームを個別に扱う

Btrfsのスナップショットは、入れ子のサブボリュームを再帰的には含みません。 /mnt/pool/data 別のサブボリュームが含まれている場合、親スナップショットには入れ子データの完全なスナップショットではなく、サブボリュームのスタブが含まれます。

バックアップ計画を確定する前にサブボリュームを一覧表示します:

sudo btrfs subvolume list /mnt/pool

重要なアプリケーションデータが入れ子のサブボリュームに存在する場合は、それぞれについて別個の読み取り専用スナップショットチェーンを作成して複製します。

-pを使う場合と-cを使う場合を判断する

直線的なバックアップ履歴では、 -p 最も単純で監査しやすいオプションです。 -c オプションを使用すると、Btrfsが追加のスナップショットから一致するエクステントを再利用できるクローン元を1つ以上指定できますが、それらのクローン元も両端でまったく同じ状態で存在している必要があります。

クローン元が変更されておらず、両方のシステムに存在することを証明できない場合は、使用しないでください。オフサイトバックアップジョブでは、単純な1つの親によるチェーンのほうが通常は安全です。

任意: 圧縮エクステントにプロトコル2を使用する

十分に新しいバージョンの Linux と btrfs-progs では、Btrfs送信プロトコル2により、圧縮エクステントをより効率的に次のオプションで送信できます --compressed-data公式の送信ドキュメントでは、プロトコル2には送信側と受信側の両方で btrfs-progs 6.0以降、送信側で Linux 6.0以降が必要とされています。

sudo btrfs send \
  --proto 2 \
  --compressed-data \
  -p /mnt/pool/.snapshots/data-20260831-1000 \
  /mnt/pool/.snapshots/data-20260901-0200 \
  | ssh backup@backup.example.net \
  'sudo -n btrfs receive /mnt/backup/btrfs-recv'

オプションが存在するからという理由だけで有効にしないでください。まず両方のエンドポイントでバージョンを確認し、最適化より互換性が重要な場合はデフォルトのプロトコルを使用します。

増分送信と受信でよくある失敗のトラブルシューティング

送信コマンドでスナップショットが読み取り専用ではないと表示される

次のコマンドでスナップショットを再作成します btrfs subvolume snapshot -r読み取り専用マウントを通じて書き込み可能なスナップショットをマウントするだけでは、送信要件を満たしません。

増分送信で親を見つけられない、または使用できない

送信側に正確な親スナップショットがまだ存在し、受信側にも対応する受信済みスナップショットがまだ存在することを確認します。どちらかの親が削除、変更、または書き込み可能にされた場合は、利用できる一致する親があればそれを復元します。なければ、新しい読み取り専用スナップショットを作成し、フルシードを新たに開始します。

宛先のサブボリュームはすでに存在すると btrfs receive が表示する

btrfs receive 同じ受信名を持つ既存のサブボリュームを上書きしません。まず既存のサブボリュームを調査します。受信に失敗した、または不完全な受信であり、安全に削除できることを確認した場合は、同じ転送を再試行する前に、その不完全なサブボリュームを削除します。

受信側の親が到着後に変更された

変更されたそのスナップショットを新しい増分ストリームの基礎として使用しないでください。変更されていない一致する受信側の親がない場合は、新しいフルバックアップチェーンを開始します。

ネストされたディレクトリ内のファイルがスナップショットに含まれていない

そのディレクトリ自体がBtrfsサブボリュームかどうかを確認します。ネストされたサブボリュームは親スナップショットに再帰的には含まれないため、独自のsend/receiveチェーンが必要です。

転送中にWANまたはSSH接続が切断される

正常に完了し、生成されたサブボリュームが正しく検証された場合にのみ、受信は成功したものとして扱います。文書化されているBtrfsのsend/receiveコマンドインターフェースには、ストリームを再開するオプションがありません。信頼性の低い長距離リンクでは、sendストリームをステージングファイルに書き込み、そのファイルを再開可能な転送方式で転送してから、完成した信頼済みファイルを次のコマンドに入力する方法を検討してください btrfs receive.

信頼できないストリームから受信側を保護する

Btrfs receiveは、受信ストリームに含まれるファイルシステム操作を適用します。公式のreceiveドキュメントでは、信頼できないソースからsendストリームを受け入れないよう勧告しており、ストリームの適用中は受信パスを同時書き込みから保護することを推奨しています。

SSHホスト検証、鍵ベース認証、専用のバックアップアカウント、および実用上可能な限り限定的な権限を使用します。バックアップ実行中は、通常のユーザーが書き込むパスから受信ディレクトリを分離します。

各増分実行でこのチェックリストを使用する

  • 両方のエンドポイントがBtrfsであることを確認します。
  • 次のコマンドで新しいソーススナップショットを作成します -r.
  • 前回成功した親を、両方のシステムで変更せずに保持します。
  • 次のコマンドで送信します btrfs send -p OLD NEW.
  • 認証および暗号化されたSSH接続経由で受信します。
  • 成功を検証し、ソースUUIDと受信側のReceived UUIDを比較します。
  • 受信したバックアップスナップショットは読み取り専用のままにします。
  • データを復元またはテストする必要がある場合は、書き込み可能な別のスナップショットを作成します。
  • 新しい親が検証された後にのみ、古いスナップショットをローテーションします。
  • ネストされたサブボリュームは、個別のチェーンでバックアップします。

1つのフルシードと1つの増分実行が手動でともに成功したら、ログ記録と明示的な終了ステータス確認を含めて、同じ手順を自動化します。重要なのはスケジューラーではなく、すべての増分ステップの両端で、変更されていない検証済みの親スナップショットを保持することです。

サポートとヒント

もっと読む

Get More Builds Like This

Stay in the Loop

Get updates from Zima - new products, exclusive deals, and real builds from the community.

Stay in the Loop preferences

We respect your inbox. Unsubscribe anytime.