UEFIブートでファイルシステムがZFSなFreeBSDのバックアップと復元

# 初めに

UEFIブートでファイルシステムがZFSなFreeBSDのシステムの、バックアップと復元の手順をまとめてみました。

# 前提

* UEFIによるブート
* OSはFreeBSD 13.0-RELEASE amd64
* ディスクはSATA接続
* ZFSは単独ディスクによるRAID 0(ストライプ)構成
* バックアップ用のディスクにデータをバックアップして、後にそのデータを使ってシステムを復元

# システムのバックアップ

バックアップの手順は以下の通りです。

1. データバックアップ用のディスクをシステムに接続
1. ブートメディアでシステムを起動
1. データバックアップ用のディスクにZFSのプールとファイルシステムを作成してマウント
1. バックアップ対象のディスクのZFSのプールをインポート
1. バックアップ対象のディスクのZFSのデータをデータバックアップ用のディスクにバックアップ
1. バックアップ対象のディスクのESP(EFIシステムパーティション)のデータをデータバックアップ用のディスクにバックアップ
1. バックアップ対象のディスクのパーティション情報をデータバックアップ用のディスクにバックアップ
1. ZFSのプールをエクスポート
1. システムをシャットダウン

以下、各手順の詳細を説明します。

## ブートメディアでシステムを起動

13.0-RELEASE amd64のブートメディアでシステムを起動し、FreeBSDのインストーラーが起動されたら`Shell`を選択します。起動後のデバイスファイルは以下の通りです。

```shell-session
# ls -l /dev/ada?
crw-r-----  1 root  operator  0x5c 12月  5 10:44 /dev/ada0
crw-r-----  1 root  operator  0x5d 12月  5 10:44 /dev/ada1
```

`/dev/ada0`がバックアップ対象のディスクで、`/dev/ada1`がデータバックアップ用のディスクです。

## データバックアップ用のディスクにZFSのプールとファイルシステムを作成してマウント

バックアップデータ保存先のディスクのファイルシステムは、FreeBSDが読み書きできるものなら何でもよいのですが、ここではZFSを使うことにします。

まず`/dev/ada1`にパーディションを作成します。

```shell-session
# gpart create -s GPT ada1
ada1 created
# gpart add -t freebsd-zfs ada1
ada1p1 added
# gpart show ada1
=>       40  209715120  ada1  GPT  (100G)
         40  209715120     1  freebsd-zfs  (100G)
```

作成されたパーティション(`/dev/ada1p1`)にZFSのプールとファイルシステムを作成してマウントします。インストールメディアからブートした場合`/`はread-onlyなので、`/tmp`の下にディレクトリを作成してそこにマウントします.


```shell-session
# mkdir /tmp/zbackup
# zpool create -R /tmp/zbackup zbackup /dev/ada1p1
```

## バックアップ対象のディスクのZFSのプールをインポート

バックアップ対象のZFSのプールをインポートします。このプールも同様に`/tmp`の下にディレクトリを作成してそこにマウントします。

```shell-session
# mkdir /tmp/zroot
# zpool import -R /tmp/zroot zroot
```

## バックアップ対象のディスクのZFSのデータをデータバックアップ用のディスクにバックアップ

まずバックアップを取るスナップショットを作成します。

```shell-session
# zfs snapshot -r zroot@backup
```

作成したスナップショットのデータを`zfs send -R`で`/tmp/zbackup`の下にバックアップします。後でこのデータから復元するためには`-R`オプションを指定することが重要です。

```shell-session
# zfs send -R -v zroot@backup > /tmp/zbackup/zbackup/zroot@backup.zfs-send.dat
```
## バックアップ対象のディスクのESP(EFIシステムパーティション)のデータをデータバックアップ用のディスクにバックアップ

ESPを`/tmp/esp`の下にマウントします。

```shell-session
# mkdir /tmp/esp
# mount -t msdosfs /dev/ada0p1 /tmp/esp
```

バックアップ対象のディスクのESPのデータを`tar`でバックアップします。

```shell-session
# cd /tmp/esp
# tar cfv /tmp/zbackup/zbackup/efi.tar .
```

## バックアップ対象のディスクのパーティション情報をデータバックアップ用のディスクにバックアップ

バックアップ対象のディスクのパーティション情報を`gpart`を使ってバックアップします。

```shell-session
# gpart backup ada0 > /tmp/zbackup/zbackup/gpart-backup-ada0.log
```

## ZFSのプールをエクスポート

バックアップ対象とバックアップ先と双方のZFSのプールをエクスポートします。

```shell-session
# zfs unmount -a
# zpool export -a
```

# システムの復元

復元の手順は以下の通りです。

1. ブートメディアでシステムを起動
1. バックアップ用ディスクのZFSのプールをインポート
1. 復元対象のディスクにパーティション情報を復元
1. ZFS用のパーティションに空のプールを作成
1. バックアップされたZFSのデータを復元
1. ZFSのプールの`bootfs`プロパティを設定
1. EPSを初期化
1. バックアップされたEPSのデータを復元
1. ZFSのプールをエクスポート
1. システムをシャットダウンしてデータバックアップ用のディスクをシステムから外す
1. 新しいブートディスクからシステムを起動

以下、各手順の詳細を説明します。

## ブートメディアでシステムを起動

バックアップの時と同様にブートメディアでシステムを起動します。`/dev/ada0`はまっさらなディスクだとして、これに`/dev/ada1`に保存してあるデータを復元していきます。

## バックアップ用ディスクのZFSのプールをインポート

前述の通りこの状態では`/`はread-onlyなので、`-R`オプションを指定して`/tmp/zbackup`の下にインポートします。

```shell-session
# mkdir /tmp/zbackup
# zpool import -R /tmp/zbackup zbackup
```

## 新しいディスクにパーティションを復元

バックアップ時に保存したパーティション情報を使って`gpart`で`/dev/ada0`にパーティション情報を復元します。

```shell-session
# gpart restore -l ada0 < /tmp/zbackup/zbackup/gpart-backup-ada0.log
```

## ZFS用のパーティションに空のプールを作成

`/dev/ada0s3`に空のZFSのプールを作成します。作成されたプールは`/tmp/zroot`の下にマウントします。

```shell-session
# mkdir /tmp/zroot
# zpool create -R /tmp/zroot zroot /dev/ada0p3
```

## バックアップされたZFSのデータを新しいディスクに復元

`zfs recv`を実行してバックアップデータを新たに作成したプールに書き込みます。

```shell-session
# zfs recv -F zroot < /tmp/zbackup/zbackup/zroot@backup.zfs-send.dat
```

## ZFSのプールの`bootfs`プロパティを設定

以下のコマンドを実行して新しいプールの`bootfs`プロパティを設定します。

```shell-session
# zpool set bootfs=zroot/ROOT/default zroot
```
## ESPを初期化

`newfs_msdos`コマンドを用いてESPを初期化します。

```shell-session
# newfs_msdos -F 32 -c 1 -L EFISYS /dev/ada0p1
```

## バックアップされたEPSのデータを復元

まず初期化したESPを`/tmp/esp`にマウントします

```shell-session
# mkdir /tmp/esp
# mount -t msdosfs /dev/ada0p1 /tmp/esp
```

そしてバックアップしたESPのデータを`tar`で復元します。

```shell-session
# cd /tmp/esp
# tar xfpv /tmp/zbackup/zbackup/efi.tar
``` 

## インポートしたZFSのプールをエクスポート

バックアップデータのプールと新規に作成したプールの両方をエクスポートします。

```shell-session
# zfs unmount -a
# zpool export -a
```

# 参考文献

* [gpart(8)](https://www.freebsd.org/cgi/man.cgi?query=gpart&sektion=8&apropos=0&manpath=FreeBSD+13.0-RELEASE+and+Ports)
* [newfs_msdos(8)](https://www.freebsd.org/cgi/man.cgi?query=newfs_msdos&sektion=8&apropos=0&manpath=FreeBSD+13.0-RELEASE+and+Ports)
* [zfs(8)](https://www.freebsd.org/cgi/man.cgi?query=zfs&apropos=0&sektion=0&manpath=FreeBSD+13.0-RELEASE+and+Ports&arch=default&format=html)
* [zfs-recv(8)](https://www.freebsd.org/cgi/man.cgi?query=zfs-recv&apropos=0&sektion=8&manpath=FreeBSD+13.0-RELEASE+and+Ports&arch=default&format=html)
* [zfs-send(8)](https://www.freebsd.org/cgi/man.cgi?query=zfs-send&sektion=8&apropos=0&manpath=FreeBSD+13.0-RELEASE+and+Ports)
* [zfs-snapshot(8)](https://www.freebsd.org/cgi/man.cgi?query=zfs-snapshot&sektion=8&apropos=0&manpath=FreeBSD+13.0-RELEASE+and+Ports)
* [zpool(8)](https://www.freebsd.org/cgi/man.cgi?query=zpool&apropos=0&sektion=0&manpath=FreeBSD+13.0-RELEASE+and+Ports&arch=default&format=html)
* [zpool-create(8)](https://www.freebsd.org/cgi/man.cgi?query=zpool-create&sektion=8&apropos=0&manpath=FreeBSD+13.0-RELEASE+and+Ports)
* [zpool-export(8)](https://www.freebsd.org/cgi/man.cgi?query=zpool-export&sektion=8&apropos=0&manpath=FreeBSD+13.0-RELEASE+and+Ports)
* [zpool-import(8)](https://www.freebsd.org/cgi/man.cgi?query=zpool-import&sektion=8&apropos=0&manpath=FreeBSD+13.0-RELEASE+and+Ports)
* [zpool-set(8)](https://www.freebsd.org/cgi/man.cgi?query=zpool-set&sektion=8&apropos=0&manpath=FreeBSD+13.0-RELEASE+and+Ports)