ZFSのバックアップの基本
ZFSはスナップショットを取得し、バックアップをストリームで書き出すことができます。
吐き出されたストリームはZFSに書き戻すことができるため、バックアップや引っ越しに利用できます。
書き出しには zfs send
コマンドを利用し、書き戻しには zfs recv
コマンドを利用します。
# スナップショットの作成
sudo zfs snapshot dataset01/data@20211223
# スナップショットの書き出し
sudo zfs send dataset01/data@20211223 > data@20211223.bin
# スナップショットの書き戻し
sudo zfs recv dataset02/data < data@20211223.bin
zfs recv する先にすでにファイルシステムが存在する場合にはエラーとなります。
-F オプションを利用すると強制的に書き戻しが実行されます。
また、ストリームで吐き出す時には、スナップショットとスナップショットの差分を出力することもできるため、容量を節約したバックアップもできます。
sudo zfs snapshot dataset01/data@20211223-2
# スナップショットの書き出し (20211223 から 20211223-2 への差分)
sudo zfs send -i dataset01/data@20211223 dataset01/data@20211223-2 > data@20211223-2.bin
# スナップショットの書き戻し
sudo zfs recv dataset02/data < data@20211223.bin
sudo zfs recv dataset01/data < data@20211223-2.bin
適切でない増分ストリームを zfs recv するとエラーになります。
ZFSの基本的な使い方は、わたしが大昔に書いた How to ZFS がそこそこわかりやすいと思うので、よかったら参照してください。
オブジェクトストレージへのバックアップ
rclone
コマンドには rclone rcat
コマンドがあり、標準入力から受けたデータをオブジェクトストレージに保存することができます。
(オブジェクトストレージに限らず、 rclone
が対応するストレージ種別が利用できます)
ZFSがスナップショットを標準出力へ出力できるということは、オブジェクトストレージに保存することができるということです。
たとえば、次のようなコマンドを実行することで、lz4で圧縮しながらオブジェクトストレージへ保存することができます。
zfs send dataset01/data@20211223 | lz4 | \
rclone rcat --s3-chunk-size 1000000 --s3-upload-concurrency 5 --retries 10 -P objstorage:bucketname/dataset01/data@20211223.lz4
スナップショットのストリームが大きい場合、 --s3-chunk-size
を大きめに設定することが重要です。
オブジェクトストレージへは、分割アップロード (マルチパートアップロード) が行われており、チャンクサイズが小さすぎる場合分割数が制限を超えてしまうためです。
S3の場合、チャンクサイズは 5MB ~ 5GB、チャンク数は最大10,000個になるように調整する必要があります。
ストリームの分割保存
オブジェクトストレージにおいて、一つのオブジェクトにはサイズの制限があります。
S3では5TBまでです。
つまり、5TB以上のファイルシステムのスナップショットはオブジェクトストレージに保存できません。
標準入力から受けたストリームを規定の容量毎に分割し、 rclone rcat
コマンドを個別に実行して保存するためのコマンド splitexec
を書きました。
このコマンドを利用することで、次のように分割しながらオブジェクトストレージに保存することができます。
zfs send dataset01/data@20211223 | lz4 | \
splitexec -s 107374182400 rclone rcat --s3-chunk-size 1000000 --s3-upload-concurrency 5 --retries 10 -P objstorage:bucketname/dataset01/data@20211223.lz4.%05d
このコマンド例は 100GB毎に分割し、 rclone rclone
コマンドを実行して標準入力で流し込みます。
こうすることで、5TBを超えるストリームも保存できます。
あんまり一つのオブジェクトが大きすぎるとダウンロードする時に困るため、そこそこのサイズで分割しておくのが良いだろうと思っています。
暗号化など
わたしはさらに openssl
コマンドで暗号化したり、送信中の容量を pv
コマンドで見たりするため、次のようなスクリプトを書いて利用しています。
#!/bin/bash -xe
OPENSSL_ENC_OPTIONS="enc -e -aes-256-cbc -salt -pass file:password.txt -pbkdf2"
ENC_SUFFIX="enc_aes256_pbkdf2"
FILESYSTEM="$1"
SNAPSHOT1="$2"
SNAPSHOT2="$3"
RCLONE_STORAGE="objstorage"
BUCKET="bucketname"
function usage () {
echo "usage: $0 FILESYSTEM SNAPSHOT1 [SNAPSHOT2]"
}
if [ -z "${FILESYSTEM}" ]; then
usage
exit 1
fi
if [ -z "${SNAPSHOT1}" ]; then
usage
exit 1
fi
FSNAME=`basename ${FILESYSTEM}`
if [ -z "${SNAPSHOT2}" ]; then
zfs send -R ${FILESYSTEM}@${SNAPSHOT1} | lz4 | \
openssl ${OPENSSL_ENC_OPTIONS} | pv -c | \
~/splitexec -s 107374182400 rclone rcat --s3-chunk-size 1000000 --s3-upload-concurrency 5 --retries 10 -P ${RCLONE_STORAGE}:${BUCKET}/${FILESYSTEM}@${SNAPSHOT1}/${FSNAME}@${SNAPSHOT1}.lz4.${ENC_SUFFIX}.%05d
else
zfs send -RI ${FILESYSTEM}@${SNAPSHOT1} ${FILESYSTEM}@${SNAPSHOT2} | lz4 | \
openssl ${OPENSSL_ENC_OPTIONS} | pv -c | \
rclone rcat -v ${RCLONE_STORAGE}:${BUCKET}/${FILESYSTEM}@${SNAPSHOT1}-${SNAPSHOT2}.lz4.${ENC_SUFFIX}
fi
sudo zfs snapshot dataset01/data@20210727
sudo ./zfssend.sh dataset01/data 20210727
sudo zfs snapshot dataset01/data@20211224
sudo ./zfssend.sh dataset01/data 20210727 20211224
差分はあまり大きくしないことを前提に、スナップショット全体を送信するときは100GBで分割し、差分を送信するときは分割せずに送信する手段をとっています。
さくらのクラウド オブジェクトストレージ
さくらインターネットのさくらのクラウドでもS3互換のオブジェクトストレージを提供しています。
~/.config/rclone/rclone.conf
に以下のように設定を記述することで rclone
が利用できます。
[objstorage]
type = s3
env_auth = false
access_key_id = "アクセスキー"
secret_access_key = "シークレットキー"
region = ""
endpoint = https://s3.isk01.sakurastorage.jp
location_constraint = ""
ぜひご利用ください。