FreeBSD Continuous ZFS Replication

(2015.11 新規作成。)

FreeBSD 10.2-RELEASE で, 2台の間で, Continuous ZFS Replication をおこなう方法について。リアルタイムに連続してレプリケーションをおこなうのは、なかなか難しい。

スナップショット

ZFS は, copy-on-write の仕組みを持っていて, ファイルシステムの snapshot を一瞬で作ることができる。

snapshot を作っただけではディスク容量も消費しない。snapshot 作成後にファイルシステムの変更があると, そこでデータが複製される。

スナップショットの作成

スナップショットの作成は zfs snapshot コマンド。

# zfs snapshot datatank/share@now
# zfs list -t snapshot
NAME                 USED  AVAIL  REFER  MOUNTPOINT
datatank/share@now      0      -  19.5K  -

スナップショットは, 明示的にマウントしなくても,「マウントポイント/.zfs/snapshot/スナップショット名」でアクセスできる。

スナップショットを作った後, ファイル fuga を作ってみる。その後, ls すると...

% ls -l /usr/home/share/u/
total 2
-rw-r--r--  1 hori  hori  5 11月 22 20:53 fuga
-rw-r--r--  1 hori  hori  5 11月 22 20:51 hoge

% ls -l /usr/home/share/.zfs/snapshot/now/u/
total 1
-rw-r--r--  1 hori  hori  5 11月 22 20:51 hoge

スナップショットのほうは、古い状態が表示される。

スナップショットの破壊

スナップショットの破壊は zfs destroy. 確認メッセージも何も表示されない。危ない。

# zfs snapshot datatank/share@s2
# zfs list -t snapshot
NAME                 USED  AVAIL  REFER  MOUNTPOINT
datatank/share@now     9K      -  19.5K  -
datatank/share@s2       0      -    21K  -
# zfs destroy datatank/share@now

# zfs list -t snapshot
NAME                USED  AVAIL  REFER  MOUNTPOINT
datatank/share@s2      0      -    21K  -

単に zfs list ではスナップショットは表示されない。-t snapshot-t all を付ける.

リモートバックアップ

一つのファイルシステムのバックアップ。

事前準備

リモート (バックアップ先) のほうで, sudo をインストール。

# pkg install sudo

ユーザが sudoers になければならない。/usr/local/etc/sudoers ファイルで設定。(設定方法は略.)

send & recv

ZFS は, スナップショットをストリームに出力できる。HEAD をいきなり送信することはできない。2 steps.

zfs send コマンドでスナップショットをストリーム送信し, zfs recv コマンドで受信する。

次の例は, スナップショット datatank/share@s2 を別ホスト 192.168.241.52 に送信し、そこでファイルシステムを再構築する。

# zfs send -p datatank/share@s2 | ssh zfsrecv@192.168.241.52 sudo zfs recv -u datatank/share

受信側には datatank zpool が存在しなければならず, 逆に datatank/share ZFS が存在すると失敗する。成功すると, datatank/share ZFS とスナップショット datatank/share@s2 が作られる。

受信側の引数が, スナップショット名ではなく ZFS 名になっているのが, 紛らわしい。

zfs send-p オプションでプロパティがコピーされることになっているが、atime はコピーされない。全部がコピーされるわけではないようだ。

zfs recv-u オプションで, 自動マウントされない。基本的にいつでもこのオプションを指定する。--ならデフォルトにしてほしい。

子孫も含める

ZFSのファイルシステムは, zroot/usr, zroot/usr/home, ... のように, 名前上, 親子関係を持てる。

ファイルシステムの中身のデータ(ファイル)が共有されるわけではなく、プロパティが親から継承される。

zfs snapshot -r オプションで, 子孫も含めたデータセットのスナップショットを作る。mountpoint ではなく, ZFS名で子孫の方向にまとめて, という点に注意。

# zfs snapshot -r myzpool/fs@snap1

子孫もまとめてストリーム送信するには, zfs send -R とする。

# zfs send -R myzpool/fs@snap1

send -R の場合は, 受信側では recv -d とする.

差分バックアップ

2回目以降は, 差分だけを送信するようにする。zfs send のオプションに -I-i があって, ややこしい。

zfs send -I @snapA pool/fs@snapD
snapA の次からsnapDまでのすべてのスナップショットが送信される。
zfs send -i @snapA pool/fs@snapD
snapDだけが送信される。

バックアップ用途では, 大文字の -I を使うこと。

recv のほうは, -d -F を付けて,

# zfs recv -d -F pool/fs

外部ツール

レプリケーションを自動化するには, 車輪の再発明はせずに, 支援ツールを使うのがいい。

pkg search zfs ぐらいで表示すると, いろいろある;

zfs-periodic-1.0.20130213 Simple way of maintaining zfs snapshots using the periodic system. -- Webサイトが消失していて, メンテされていないか?
zfs-replicate-0.7_1 ZFS Snapshot Replication Script
zfs-snapshot-clean-0.2.0 Tool to sieve ZFS snapshots as per given spec a la 'pdumpfs-clean'. -- pdumpfs は Plan9 の dumpfs モドキ?
zfs-snapshot-mgmt-20090201_2 Automatic ZFS snapshot management tool
zfsnap-1.11.1 Simple sh script to make zfs rolling snaphosts with cron. -- Webサイト: zfsnap/zfsnap ・ GitHub
zfstools-0.3.6 OpenSolaris-compatible auto snapshotting for ZFS -- Webサイト: bdrewery/zfstools ・ GitHub; Rubyで作られている. => レプリケーションはscope 外か?

どれがいいのかなぁ.

ほかにもいくつかある;

https://github.com/lazy404/zfs-tools GitHub - Rudd-O/zfs-tools: ZFS synchronization and snapshotting tools
Python で作られている。zreplicate コマンド. => これは目的に合いそう.

(2016.11) Rudd-O氏のリポジトリのほうが開発が進んでいる。バグfixもされている。

zrep - zfs based replication and failover system
シェルスクリプト。asynchronous (but continuous) replication.

pkgパッケージのはどれも違うようだ。zfs-tools (ハイフンが入っているほう) か zrep が良さそうに見える。

zfs-tools によるレプリケーション

以下では, パックアップ元を master, バックアップ先を backup 機という。

事前準備

zfs-tools は ZFS on Linux を重視しているみたい。

master 側に bashsudo コマンドが必要。'bash' package, 'sudo' package をインストールしておく.

zfs-tools のインストール

master機, backup機の両方で, 上の github から git clone する。

バグがあるので, 少し修正. (2016.11) Rudd-O氏のリポジトリでは修正ずみ。

root になって, python setup.py install.

専用ユーザ

zfs-tools の zreplicate コマンドは pull 型. master機のほうに専用のユーザを作る.

README.md の手順は FreeBSDではない。標準コマンドのオプションが違う。Linux のようだ。

/etc/shells ファイルに /usr/local/bin/zfs-shell を追加する。

ユーザを追加。su はしないので, wheel グループには参加させない.

# adduser
Username: zfssend
Full name: ZFS replication sender
Uid (Leave empty for default): 
Login group [zfssend]: 
Login group is zfssend. Invite zfssend into other groups? []: 
Login class [default]: 
Shell (sh csh tcsh git-shell zfs-shell nologin) [sh]: zfs-shell
Home directory [/home/zfssend]: /var/lib/zfssend
Home directory permissions (Leave empty for default): 
Use password-based authentication? [yes]: no
Lock out the account after creation? [no]: 
Username   : zfssend
Password   : <disabled>
Full Name  : ZFS replication sender
Uid        : 1002
Class      : 
Groups     : zfssend 
Home       : /var/lib/zfssend
Home Mode  : 
Shell      : /usr/local/bin/zfs-shell
Locked     : no
OK? (yes/no): yes
adduser: INFO: Successfully added (zfssend) to the user database.

/usr/local/etc/sudoers ファイルを編集し, パスワードなしで sudo して /sbin/zfs 'だけ'が実行できるようにする。

zfssend ALL= NOPASSWD: /sbin/zfs

root から su zfssend list して, 動くか確認。

backup機

README.md は, 単に SSHのための公開鍵認証, で済ましている。backup機からmaster機にログインするので, backup機で鍵ペアを作って, うち公開鍵を master に保存する。

# ssh-keygen -t rsa

パスワードは空 (no passphrase) にする。

scp コマンドで, 公開鍵をmaster機へ. /var/lib/zfssend/.ssh/authorized_keys ファイルとして保存。

backup機からmaster機に, パスワードなしで zfssend としてログインできるか, 確認

テスト

1) master機でスナップショットを取る.

# zsnap datatank/share

スナップショットができているか。

# zfs list -t all
NAME                                            USED  AVAIL  REFER  MOUNTPOINT
datatank                                        146K  9.63G    19K  none
datatank/share                                 21.5K  9.63G  21.5K  /usr/home/share
datatank/share@autosnapshot-2015-11-26-220419      0      -  21.5K  -
zroot                                          5.03G  12.3G    96K  none
以下略

うまくいったか分かりやすいように, /usr/home/share 以下に, 何かファイルを作っておく.

2) backup機では, 'datatank/share' ZFS を作っておく. destination dataset がないと, zreplicate が失敗する。

atime は off にしておく。

backup機のほうで zreplicate を実行。192.168.241.51 は master のIPアドレス.

# zreplicate -v zfssend@192.168.241.51:datatank/share datatank/share
Replicating dataset zfssend@192.168.241.51:datatank/share into localhost:datatank/share...
Assessing that the source dataset exists...
Assessing that the destination dataset exists...
=================================
Replicating (full_recursive) datatank/share to datatank/share
Base snapshot available in destination: None
Target snapshot available in source:    <Snapshot: datatank/share@autosnapshot-2015-11-26-221849>
send from @ to datatank/share@autosnapshot-2015-11-26-221849 estimated size is 11.5K
total estimated size is 11.5K
TIME        SENT   SNAPSHOT
receiving full stream of datatank/share@autosnapshot-2015-11-26-221849 into datatank/share@autosnapshot-2015-11-26-221849
received 46.8KB stream in 2 seconds (23.4KB/sec)
=================================
Replication complete.

できたか確認。

# zfs list -t all
NAME                                            USED  AVAIL  REFER  MOUNTPOINT
datatank                                        156K  9.63G    19K  none
datatank/share                                 21.5K  9.63G  21.5K  /usr/home/share
datatank/share@autosnapshot-2015-11-26-221849      0      -  21.5K  -
zroot                                          5.02G  12.3G    96K  none
以下略

受け側の /usr/home/share には, master機の HEAD のファイルがない。つまり, スナップショットの状態と一致しているはず。

3) もう一度 master でスナップショットを作る。

# zsnap datatank/share

4) backup機で zreplicate.

# zreplicate -v zfssend@192.168.241.51:datatank/share datatank/share
Replicating dataset zfssend@192.168.241.51:datatank/share into localhost:datatank/share...
Assessing that the source dataset exists...
Assessing that the destination dataset exists...
=================================
Replicating (incremental_recursive) datatank/share to datatank/share
Base snapshot available in destination: <Snapshot: datatank/share@autosnapshot-2015-11-26-221849>
Target snapshot available in source:    <Snapshot: datatank/share@autosnapshot-2015-11-26-222430>
send from @autosnapshot-2015-11-26-221849 to datatank/share@autosnapshot-2015-11-26-222430 estimated size is 5.50K
total estimated size is 5.50K
TIME        SENT   SNAPSHOT
receiving incremental stream of datatank/share@autosnapshot-2015-11-26-222430 into datatank/share@autosnapshot-2015-11-26-222430
received 11.0KB stream in 1 seconds (11.0KB/sec)
=================================
Replication complete.

できた!!!