FreeBSD で ZFS を利用する – send/recv を使い倒す

ZFS

前回は ZFS ファイルシステムを色々使ってみて最後にクローンを行った所まで実施しました.
今回はプール間のクローン・レプリケーション技術の send / recv に焦点を絞って説明を行っていきます.

今回は自ホスト内(ローカル)のプール間クローンと,ホスト間のプール間クローンの二種を扱っていきます.
構成はこんな感じの環境を用意しました.

前回は pool0/data を pool1 にクローンしました.おさらいとして改めて以下に記載します.

ローカル内のプール間クローン

前回のおさらい

別プールに作成する場合は zfs send と zfs recv を利用します.

# zfs send pool0/data@snap-9 | zfs recv pool1/clone

# zfs list
NAME               USED  AVAIL     REFER  MOUNTPOINT
pool0             10.0G   375G     32.0K  /pool0
pool0/data        53.3K  10.0G     34.0K  /data
pool0/data-clone     0B   375G     34.0K  /pool0/data-clone
pool0/share       30.6K   385G     30.6K  /pool0/share
pool1              154K  96.4G       24K  /pool1
pool1/clone       26.5K  96.4G     26.5K  /pool1/clone

pool1 に clone というファイルシステムが無事作成されました.この中身を見てみましょう.

# ls /pool1/clone
data1.txt       data2.txt       data3.txt

# zfs list -t snapshot pool1/clone
NAME                 USED  AVAIL     REFER  MOUNTPOINT
pool1/clone@snap-9     0B      -     26.5K  -

このようにデータはクローンされています.スナップショットも指定した物がクローン先に残っています.
これは zfs clone と zfs send / recv での動きが違うためとなります.
スナップショットは不必要であれば削除してもらっても大丈夫です.

バックアップとしてのクローン戦略

初回バックアップなど,全体をまずはクローン/レプリケーションしたい場合は先にも書いたような方法となります.
特定のスナップショットを指定して zfs send で送信,zfs recv で受信させます.

次のような環境 (スナップショットは全部消しました) からバックアップとして取るには.を改めて解説していきます.

# zfs list
NAME          USED  AVAIL     REFER  MOUNTPOINT
pool0        10.0G   375G     30.6K  /pool0
pool0/data   34.0K  10.0G     34.0K  /data
pool0/share  30.6K   385G     30.6K  /pool0/share
pool1         154K  96.4G       24K  /pool1

# zfs list -t snapshot
no datasets available

初回バックアップ

初回バックアップについては特にありません.一番最初に持っていきたい状態のスナップショットを指定する形になります.例えば次のようなスナップショット状況の場合があったとします.

# zfs list -t snapshot
NAME                    USED  AVAIL     REFER  MOUNTPOINT
pool0/data@2023120110     0B      -     34.0K  -
pool0/data@2023120112     0B      -     34.0K  -
pool0/data@2023120114     0B      -     34.0K  -
pool0/data@2023120116     0B      -     34.0K  -
pool0/data@2023120118     0B      -     34.0K  -
pool0/data@2023120120     0B      -     34.0K  -
pool0/data@2023120122     0B      -     34.0K  -

どの時点でもいいです.であればどの時点を指定してもらっても構いません.今回は一番最初の時点のスナップショットを起点として実施してみます.

# zfs send pool0/data@2023120110 | zfs recv pool1/data-backup

# zfs list
NAME                USED  AVAIL     REFER  MOUNTPOINT
pool0              10.0G   375G     30.6K  /pool0
pool0/data         34.0K  10.0G     34.0K  /data
pool0/share        30.6K   385G     30.6K  /pool0/share
pool1               184K  96.4G       24K  /pool1
pool1/data-backup  26.5K  96.4G     26.5K  /pool1/data-backup

# zfs list -t snapshot pool1/data-backup
NAME                           USED  AVAIL     REFER  MOUNTPOINT
pool1/data-backup@2023120110     0B      -     26.5K  -

これは何度も言いますが先の説明となんら変更はありません.

増分バックアップを行っていく

大事なのはここからになります.
2回目以降は全部をクローンするのではなく,変更点のみをクローンで転送ができればかかる転送量と時間を節約できます.

変更点を転送する場合も zfs send を用いますがオプションが追加されます.

途中のスナップショットは維持しない

増分のクローンにおいて,最終状態のみ保持出来ればよいという場合は途中のスナップショットがクローン側に存在する必要はありません.そのような場合は次のコマンドになります.

# zfs send -i pool0/data@2023120110 pool0/data@2023120122 | zfs recv pool1/data-backup

# zfs list -t snapshot pool1/data-backup
NAME                           USED  AVAIL     REFER  MOUNTPOINT
pool1/data-backup@2023120110     0B      -     26.5K  -
pool1/data-backup@2023120122     0B      -     26.5K  -

初回に送ったスナップショット (正確には zfs send で前回送信したスナップショット) と,次に送りたいスナップショットを指定することで,その間の変更点のみと指定できます.

-i オプションはその間のスナップショットを含まない.になりますので,受け側は初回と2回目のスナップショットのみが保存されている状態となります.

毎日これが継続するとした場合で翌日のスナップショット状況がこうなっていたとします.

# zfs list -t snapshot pool0/data
NAME                    USED  AVAIL     REFER  MOUNTPOINT
pool0/data@2023120110     0B      -     34.0K  -
pool0/data@2023120112     0B      -     34.0K  -
pool0/data@2023120114     0B      -     34.0K  -
pool0/data@2023120116     0B      -     34.0K  -
pool0/data@2023120118     0B      -     34.0K  -
pool0/data@2023120120     0B      -     34.0K  -
pool0/data@2023120122     0B      -     34.0K  -
pool0/data@2023120200     0B      -     34.0K  -
pool0/data@2023120202     0B      -     34.0K  -
pool0/data@2023120204     0B      -     34.0K  -
pool0/data@2023120208     0B      -     34.0K  -
pool0/data@2023120210     0B      -     34.0K  -
pool0/data@2023120212     0B      -     34.0K  -
pool0/data@2023120214     0B      -     34.0K  -
pool0/data@2023120216     0B      -     34.0K  -
pool0/data@2023120218     0B      -     34.0K  -
pool0/data@2023120220     0B      -     34.0K  -
pool0/data@2023120222     0B      -     34.0K  -

前回送信した際の終了点は「pool0/data@2023120122」ですので今回の起点が「pool0/data@2023120122」になります.そこからの差分の最新点の「pool0/data@2023120222」までを送りたい場合は次のようになります.

# zfs send -i pool0/data@2023120122 pool0/data@2023120222 | zfs recv pool1/data-backup

# zfs list -t snapshot pool1/data-backup
NAME                           USED  AVAIL     REFER  MOUNTPOINT
pool1/data-backup@2023120110     0B      -     26.5K  -
pool1/data-backup@2023120122     0B      -     26.5K  -
pool1/data-backup@2023120222     0B      -     26.5K  -

このように,前回送ったスナップショットおよび新しく送りたいスナップショットを指定することで例えば毎日バックアップを行うということが可能になります.

この例では日付・時間をスナップショット名としましたが,バックアップの為の専用のスナップショット名を用いるなどをする方がスクリプト化はしやすいかと思います.

スナップショットを維持したままクローンする

維持の必要の有無はバックアップの用途によりますが,メインと同じ状態を維持したいというケースも当然あります.そんな場合でも対応可能です.
初回のクローンが完了しており,2回目以降のクローンを行う所から記載します.
(先の維持しないクローンの状態をクリアした所から実施していますので混乱しないでください)

# zfs send -I pool0/data@2023120110 pool0/data@2023120122 | zfs recv pool1/data-backup

# zfs list -t snapshot pool1/data-backup
NAME                           USED  AVAIL     REFER  MOUNTPOINT
pool1/data-backup@2023120110     0B      -     26.5K  -
pool1/data-backup@2023120112     0B      -     26.5K  -
pool1/data-backup@2023120114     0B      -     26.5K  -
pool1/data-backup@2023120116     0B      -     26.5K  -
pool1/data-backup@2023120118     0B      -     26.5K  -
pool1/data-backup@2023120120     0B      -     26.5K  -
pool1/data-backup@2023120122     0B      -     26.5K  -

実際はオプションを -i から -I に変えただけですが,これによって間のスナップショットも維持したままクローンが行われます.

翌日にも同様に増分をクローンした場合はこのようになります.

# zfs send -I pool0/data@2023120122 pool0/data@2023120222 | zfs recv pool1/data-backup

# zfs list -t snapshot pool1/data-backup
NAME                           USED  AVAIL     REFER  MOUNTPOINT
pool1/data-backup@2023120110     0B      -     26.5K  -
pool1/data-backup@2023120112     0B      -     26.5K  -
pool1/data-backup@2023120114     0B      -     26.5K  -
pool1/data-backup@2023120116     0B      -     26.5K  -
pool1/data-backup@2023120118     0B      -     26.5K  -
pool1/data-backup@2023120120     0B      -     26.5K  -
pool1/data-backup@2023120122     0B      -     26.5K  -
pool1/data-backup@2023120200     0B      -     26.5K  -
pool1/data-backup@2023120202     0B      -     26.5K  -
pool1/data-backup@2023120204     0B      -     26.5K  -
pool1/data-backup@2023120208     0B      -     26.5K  -
pool1/data-backup@2023120210     0B      -     26.5K  -
pool1/data-backup@2023120212     0B      -     26.5K  -
pool1/data-backup@2023120214     0B      -     26.5K  -
pool1/data-backup@2023120216     0B      -     26.5K  -
pool1/data-backup@2023120218     0B      -     26.5K  -
pool1/data-backup@2023120220     0B      -     26.5K  -
pool1/data-backup@2023120222     0B      -     26.5K  -

ホスト間のクローン

先ほどまでは同一ホスト内でのクローンを行っていました.遠隔地のバックアップを実施したいなどホスト間のクローンを持ちたいケースは多いと思います.
ここでは,ホスト間のクローンについて説明します.

環境整備

ホスト間ですので,基本はネットワーク経由になります.方法は RSH や SSH などになりますが,WAN を超えた場合を想定して SSH での zfs send / recv を例に環境の整備の例を記載します.

送信側の SSH の準備

cron などで実施することが想定されるため,公開鍵認証でパスフレーズ無しで行うことになると思います.
ですので,その準備を行います.

# ssh-keygen -f /root/.ssh/zfs
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/zfs
Your public key has been saved in /root/.ssh/zfs.pub
The key fingerprint is:
SHA256:t7h8H2HD5dYDEQHR/syNOOjNOe1uMEKTz356TyduHzo root@bsd13-1.seichan.local
The key's randomart image is:
+---[RSA 3072]----+
|           o++o  |
|             ..  |
|           ....  |
|          +. +.. |
|        S..==.*oo|
|         oooB+.+o|
|        ...=.*..o|
|       . .o *EBoo|
|        o. .o@=oo|
+----[SHA256]-----+

ZFS で使用するための鍵として /root/.ssh/zfs を指定しました.受け側に渡す公開鍵は /root/.ssh/zfs.pub になります.公開鍵を受け側ホストに設定をしていきます.

受信側の SSH の準備

送信側の公開鍵を /root/.ssh/authorized_keys にセットします.

echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDxXlxhbPVYeu7afXOuOjl6imlbZ23HiCiyktSUGb1liOtJOTK0xKqMkOX3d03UJP43GZW1B8ASHaMV0MJj0gVaSv54mN5Kwi7cczKYVfVs5SsLNieLgclTZ3Hes7qbFmxH5+FrSccsJFrcjs4Mjdhdn6UBzPwNDll9Y/YHWCdGcwUiAvfJJZQH+K88A8X/Yv0kGNF82kuQE7xjW+GQPYfhTFMaFEPZF/tfiI55VxevdDoox52CaHFWrEIDPQHRmrrxvU3dcR88bpdKhO/8CnI7vbOYmfi5OYBOVJJ+5l9YWih9pEBhofBvrrhP5rB0C4O5jhojfv2F+lG0MkDep4AwcrpgQ8EQlahbKozJ8pdE1VDDEYkzCaE1yJzY8R6o5QFSXcSocBBQpMnLde1EiaMVP/w1e3p4OMhAMlUi3MkdtXLDT1r6r98v3KiQEp/ZQCfSnvrEapO0E5LCco00yoUY6uxu5XPi2pLTjcLFcucQQGxQiJfzdhAK4+kEAqUu3nU= root@bsd13-1" >> /root/.ssh/authorized_keys

その後,鍵を利用してパスフレーズ無しでログインができることを確認します.

root@bsd13-1:~ # ssh -i /root/.ssh/zfs root@192.168.241.43
The authenticity of host '192.168.241.43 (192.168.241.43)' can't be established.
ED25519 key fingerprint is SHA256:UfCmkkApPp8jkMDabQUvzazpTuIzbK8LOxaUqtMVQYg.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.241.43' (ED25519) to the list of known hosts.
Last login: Wed Dec 20 10:03:51 2023 from 192.168.241.192
FreeBSD 13.2-RELEASE releng/13.2-n254617-525ecfdad597 GENERIC

Welcome to FreeBSD!

root@bsd13-2:~ #

受信側の ZFS プールの準備

受信側の ZFS プールを作成します.詳細な手順は省いていますので「FreeBSD で ZFS を利用する – ZFS プールの作成」を参照ください.

# zpool create pool0 da1

# zpool status
  pool: pool0
 state: ONLINE
config:

        NAME        STATE     READ WRITE CKSUM
        pool0       ONLINE       0     0     0
          da1       ONLINE       0     0     0

errors: No known data errors

初回バックアップ

ローカルとの違いは特にありません.一番最初に持っていきたい状態のスナップショットを指定する形になります.先に使用した環境ですので,持っているスナップショットの状態はこのような所から実施していきます.

# zfs list -t snapshot pool0/data
NAME                    USED  AVAIL     REFER  MOUNTPOINT
pool0/data@2023120110     0B      -     34.0K  -
pool0/data@2023120112     0B      -     34.0K  -
pool0/data@2023120114     0B      -     34.0K  -
pool0/data@2023120116     0B      -     34.0K  -
pool0/data@2023120118     0B      -     34.0K  -
pool0/data@2023120120     0B      -     34.0K  -
pool0/data@2023120122     0B      -     34.0K  -
pool0/data@2023120200     0B      -     34.0K  -
pool0/data@2023120202     0B      -     34.0K  -
pool0/data@2023120204     0B      -     34.0K  -
pool0/data@2023120208     0B      -     34.0K  -
pool0/data@2023120210     0B      -     34.0K  -
pool0/data@2023120212     0B      -     34.0K  -
pool0/data@2023120214     0B      -     34.0K  -
pool0/data@2023120216     0B      -     34.0K  -
pool0/data@2023120218     0B      -     34.0K  -
pool0/data@2023120220     0B      -     34.0K  -
pool0/data@2023120222     0B      -     34.0K  -

この中の一番最初のスナップショットを起点に初回のクローンを行ってみます.

送信側はこのように,パイプの後に SSH を実行させ,コマンドとして zfs recv を実行する形で行います.

root@bsd13-1:~ # zfs send pool0/data@2023120110 | ssh -i /root/.ssh/zfs root@192.168.241.43 "zfs recv pool0/data-backup"

受信側でどのようになっているかを確認します.指定したファイルシステムが作成されたことと,スナップショットが存在している事が確認できます.

# cd
root@bsd13-2:~ # zfs list
NAME                USED  AVAIL     REFER  MOUNTPOINT
pool0               154K  96.4G       24K  /pool0
pool0/data-backup  26.5K  96.4G     26.5K  /pool0/data-backup

# zfs list -t snapshot pool0/data-backup
NAME                           USED  AVAIL     REFER  MOUNTPOINT
pool0/data-backup@2023120110     0B      -     26.5K  -

ホスト間の増分バックアップを行っていく

大事なのはここからになります.
ホスト間であればなおさら2回目以降は全部をクローンするのではなく,変更点のみを送信したいと思います.

実行するコマンドはホスト内のクローンと同様です.SSH 経由で実行するのが違いとなります.

途中のスナップショットは維持しない

増分のクローンにおいて,最終状態のみ保持出来ればよいという場合は途中のスナップショットがクローン側に存在する必要はありません.そのような場合は次のコマンドになります.

# zfs send -i pool0/data@2023120110 pool0/data@2023120122 | ssh -i /root/.ssh/zfs root@192.168.241.43 "zfs recv pool0/data-backup"

# zfs list -t snapshot pool0/data-backup
NAME                           USED  AVAIL     REFER  MOUNTPOINT
pool0/data-backup@2023120110     0B      -     26.5K  -
pool0/data-backup@2023120122     0B      -     26.5K  -

初回に送ったスナップショット (正確には zfs send で前回送信したスナップショット) と,次に送りたいスナップショットを指定することで,その間の変更点のみと指定できます.

-i オプションはその間のスナップショットを含まない.になりますので,受け側は初回と2回目のスナップショットのみが保存されている状態となります.

前回送信した際の終了点は「pool0/data@2023120122」ですので今回の起点が「pool0/data@2023120122」になります.そこからの差分の最新点の「pool0/data@2023120222」までを送りたい場合は次のようになります.

# zfs send -i pool0/data@2023120122 pool0/data@2023120222 | ssh -i /root/.ssh/zfs root@192.168.241.43 "zfs recv pool0/data-backup"

# zfs list -t snapshot pool0/data-backup
NAME                           USED  AVAIL     REFER  MOUNTPOINT
pool0/data-backup@2023120110     0B      -     26.5K  -
pool0/data-backup@2023120122     0B      -     26.5K  -
pool0/data-backup@2023120222     0B      -     26.5K  -

このように,前回送ったスナップショットおよび新しく送りたいスナップショットを指定することで例えば毎日バックアップを行うということが可能になります.

このように,ローカル間でもホスト間でも実施の方式に大きな違いが無く出来ることが理解できたかと思います.

スナップショットを維持したままクローンする

維持の必要の有無はバックアップの用途によりますが,メインと同じ状態を維持したいというケースも当然あります.そんな場合でも対応可能です.
初回のクローンが完了しており,2回目以降のクローンを行う所から記載します.
(先の維持しないクローンの状態をクリアした所から実施していますので混乱しないでください)

# zfs send -I pool0/data@2023120110 pool0/data@2023120122 | ssh -i /root/.ssh/zfs root@192.168.241.43 "zfs recv pool0/data-backup"

# zfs list -t snapshot pool0/data-backup
NAME                           USED  AVAIL     REFER  MOUNTPOINT
pool0/data-backup@2023120110     0B      -     26.5K  -
pool0/data-backup@2023120112     0B      -     26.5K  -
pool0/data-backup@2023120114     0B      -     26.5K  -
pool0/data-backup@2023120116     0B      -     26.5K  -
pool0/data-backup@2023120118     0B      -     26.5K  -
pool0/data-backup@2023120120     0B      -     26.5K  -
pool0/data-backup@2023120122     0B      -     26.5K  -

実際はオプションを -i から -I に変えただけですが,これによって間のスナップショットも維持したままクローンが行われます.

翌日にも同様に増分をクローンした場合はこのようになります.

# zfs send -I pool0/data@2023120122 pool0/data@2023120222 | ssh -i /root/.ssh/zfs root@192.168.241.43 "zfs recv pool0/data-backup"

# zfs list -t snapshot pool0/data-backup
NAME                           USED  AVAIL     REFER  MOUNTPOINT
pool0/data-backup@2023120110     0B      -     26.5K  -
pool0/data-backup@2023120112     0B      -     26.5K  -
pool0/data-backup@2023120114     0B      -     26.5K  -
pool0/data-backup@2023120116     0B      -     26.5K  -
pool0/data-backup@2023120118     0B      -     26.5K  -
pool0/data-backup@2023120120     0B      -     26.5K  -
pool0/data-backup@2023120122     0B      -     26.5K  -
pool0/data-backup@2023120200     0B      -     26.5K  -
pool0/data-backup@2023120202     0B      -     26.5K  -
pool0/data-backup@2023120204     0B      -     26.5K  -
pool0/data-backup@2023120208     0B      -     26.5K  -
pool0/data-backup@2023120210     0B      -     26.5K  -
pool0/data-backup@2023120212     0B      -     26.5K  -
pool0/data-backup@2023120214     0B      -     26.5K  -
pool0/data-backup@2023120216     0B      -     26.5K  -
pool0/data-backup@2023120218     0B      -     26.5K  -
pool0/data-backup@2023120220     0B      -     26.5K  -
pool0/data-backup@2023120222     0B      -     26.5K  -

いかがでしょうか.スナップショットを維持する・しないにかかわらず,ホスト内・ホスト間の ZFS クローンが簡単にできることが分かったかと思います.

番外編 (ZFS クローンをファイルとして保存する)

番外編という書き方にしていますが,外部メディアにバックアップとして保存するためにイメージをファイルに保存するということも可能です.
ファイルに保存の他,直接テープに書きだしたり DVD/BD に書きだすこともやりようによっては可能です.

ファイルに書き出す (バックアップ)

ここでは,ファイルに書き込む形を紹介します.
(元データは pool1/data で,書き出す先は pool1 の中に置きます)

# zfs send pool0/data@2023120110 > /pool1/pool0_data@2023120110.img

リダイレクトを使ってファイルに出力をしています.拡張子はなんでもよいのですが,イメージファイルですので .img を拡張子としました.
このような形でファイルに書き出すことが可能です.

増分も同様です.間のスナップショット込みの情報をファイルに書き出す場合は以下のとおりです.

# zfs send -I pool0/data@2023120110 pool0/data@2023120122 > /pool1/pool0_data@2023120110-data@2023120122.img

いかがでしょうか.コマンドはほぼ変わらずにファイルに書き出すことを実現できています.

ファイルから書き戻す (リストア)

ファイルに書き出したイメージファイルをもとにファイルシステムを復元してみます.
ここでは pool0/data-restore として復元してみます.

# cat /pool1/pool0_data@2023120110.img | zfs recv pool0/data-restore

# zfs list
NAME                 USED  AVAIL     REFER  MOUNTPOINT
pool0               10.0G   375G     32.0K  /pool0
pool0/data          34.0K  10.0G     34.0K  /data
pool0/data-restore  34.0K   375G     34.0K  /pool0/data-restore
pool0/share         30.6K   385G     30.6K  /pool0/share
pool1                330K  96.4G     82.5K  /pool1
pool1/data-backup   26.5K  96.4G     26.5K  /pool1/data-backup

# zfs list -t snapshot pool0/data-restore
NAME                            USED  AVAIL     REFER  MOUNTPOINT
pool0/data-restore@2023120110     0B      -     34.0K  -

このように,イメージファイルを読み込み,zfs recv に渡すことでリストアすることができます.

増分データも同様にリストアすることが可能です.

# cat /pool1/pool0_data@2023120110-data@2023120122.img | zfs recv pool0/data-restore

# zfs list -t snapshot pool0/data-restore
NAME                            USED  AVAIL     REFER  MOUNTPOINT
pool0/data-restore@2023120110     0B      -     34.0K  -
pool0/data-restore@2023120112     0B      -     34.0K  -
pool0/data-restore@2023120114     0B      -     34.0K  -
pool0/data-restore@2023120116     0B      -     34.0K  -
pool0/data-restore@2023120118     0B      -     34.0K  -
pool0/data-restore@2023120120     0B      -     34.0K  -
pool0/data-restore@2023120122     0B      -     34.0K  -

と,このように増分データのリストアも可能です.

先に紹介したホスト間クローンの時に,相手先が ZFS ではない場合はこのようにファイルとして書き出すことでリモートへのバックアップを行う.ということが可能になります.

以上,zfs send / recv の紹介でした.質問があればコメント欄で質問頂ければと思います.

コメント

タイトルとURLをコピーしました