しかし、ZVOL 直上の ext4 ならば fstrim が使えるのですが、cryptsetup を挟んだ場合は fstrim を利用できず、使いまわしていると、ZVOL が肥大化してしまいます。ZVOL を再作成するという運用もできますが、ZVOL の解放 (zfs destroy) に結構な時間がかかるようです。わたしの環境では、100GiB 解放するのに 7 分程度かかるようでした。
というわけで、別の方法に切り替えることにしました。
いろいろと調べ、考えた挙句に辿りついた方式は、sparse file + losetup + cryptsetup + xfs です。 sparse file の作成には、truncate コマンドが利用できます。操作手順は、次のようになります。
# truncate -s $((65*1024*1024*1024)) /tank1/backup/vault-2013-06-11 # losetup /dev/loop0 /tank1/backup/vault-2013-06-11 # cryptsetup create -y vault-2013-06-11 /dev/loop0 # mkfs -t xfs /dev/mapper/vault-2013-06-11 # mkdir /mnt_vault-2013-06-11 # mount /dev/mapper/vault-2013-06-11 /mnt_vault-2013-06-11ファイルシステムには、mkfs が高速で、スペース効率が良い xfs を使うことにしました。
わたしの当該バックアップ運用では、1回のバックアップデータ量が 60GiB ほどで、過去3世代保存できればよいので、毎回、上記操作で 65GiB の暗号化スペースを作って利用することにしました。
なお、バックアップ後には、次の操作を行います。
# umount /mnt_vault-2013-06-11 # cryptsetup remove /dev/mapper/vault-2013-06-11 # losetup -d /dev/loop0比較的多くのコマンドを、順序を違えずに実行する必要があり、実際やってみると誤操作しがちでしたので、簡単な支援スクリプトを3つ作成しました。ご参考まで。
#!/bin/bash # # Name: my-vault-setup # # Authors: luna2 <blue3waters at gmail dot com> # # This file is subject to the GNU General Public License. # It comes with NO WARRANTY. # usage_exit() { echo "Usage: my-vault-setup [-d dir] [-t fs-type] size" 1>&2 exit 1 } FS_TYPE=xfs TARGET_DIR=. while getopts ":d:t:" opt do case $opt in d) TARGET_DIR=${OPTARG%/} ;; t) FS_TYPE=$OPTARG ;; *) usage_exit esac done shift $((OPTIND - 1)) if [ $# -ne 1 ] ; then usage_exit elif expr "$1" : '[0-9]*' > /dev/null ; then TARGET_SIZE=$1 else usage_exit fi if [ ! -d $TARGET_DIR ] ; then usage_exit fi TARGET_NAME=vault-`date +%F-%H%M` TARGET=$TARGET_DIR/$TARGET_NAME echo "TARGET=$TARGET SIZE=$TARGET_SIZE (GiB)" truncate -s $((${TARGET_SIZE}*1024*1024*1024)) $TARGET if [ $? -ne 0 ] ; then echo "ERROR: truncate fail" 1>&2 exit 1 fi losetup -f $TARGET if [ $? -ne 0 ] ; then echo "ERROR: losetup fail" 1>&2 exit 1 fi LOOP_DEV=`losetup -j $TARGET | egrep -o '/dev/loop[0-9]+'` echo "LOOP_DEV=$LOOP_DEV" cryptsetup create -y $TARGET_NAME $LOOP_DEV if [ $? -ne 0 ] ; then echo "ERROR: cryptsetup fail" 1>&2 exit 1 fi mkfs -t $FS_TYPE /dev/mapper/$TARGET_NAME >/dev/null 2>&1 if [ $? -ne 0 ] ; then echo "ERROR: mkfs fail" 1>&2 exit 1 fi mkdir /mnt_$TARGET_NAME mount /dev/mapper/$TARGET_NAME /mnt_$TARGET_NAME if [ $? -ne 0 ] ; then echo "ERROR: mount fail" 1>&2 exit 1 fi echo "/mnt_$TARGET_NAME is usable for your backup" exit 0
#!/bin/bash # # Name: my-vault-umount # # Authors: luna2 <blue3waters at gmail dot com> # # This file is subject to the GNU General Public License. # It comes with NO WARRANTY. # usage_exit() { echo "Usage: my-vault-umount target_dir" 1>&2 exit 1 } if [ $# -ne 1 ] ; then usage_exit fi TARGET=${1%/} if [[ $TARGET != /mnt_vault-* ]] ; then usage_exit fi TARGET_NAME=${TARGET#/mnt_} if ! grep -wq $TARGET /proc/mounts ; then echo "ERROR: $TARGET is not a mount point" 1>&2 exit 1 fi umount $TARGET if [ $? -ne 0 ] ; then echo "ERROR: umount fail" 1>&2 exit 1 fi LOOP_DEV=`cryptsetup status /dev/mapper/$TARGET_NAME | awk '$1 == "device:" {print $2}'` cryptsetup remove /dev/mapper/$TARGET_NAME if [ $? -ne 0 ] ; then echo "ERROR: cryptsetup fail" 1>&2 exit 1 fi VAULT_FILE=`losetup $LOOP_DEV | awk '{print $NF}'` VAULT_FILE=${VAULT_FILE#(} VAULT_FILE=${VAULT_FILE%)} losetup -d $LOOP_DEV if [ $? -ne 0 ] ; then echo "ERROR: losetup fail" 1>&2 exit 1 fi rmdir $TARGET echo "$VAULT_FILE was locked" exit 0
#!/bin/bash # # Name: my-vault-mount # # Authors: luna2 <blue3waters at gmail dot com> # # This file is subject to the GNU General Public License. # It comes with NO WARRANTY. # usage_exit() { echo "Usage: my-vault-mount vault_file" 1>&2 exit 1 } if [ $# -ne 1 ] ; then usage_exit fi TARGET=$1 if [ ! -f $TARGET ] ; then usage_exit fi TARGET_NAME=${TARGET##*/} losetup -f $TARGET if [ $? -ne 0 ] ; then echo "ERROR: losetup fail" 1>&2 exit 1 fi LOOP_DEV=`losetup -j $TARGET | egrep -o '/dev/loop[0-9]+'` echo "LOOP_DEV=$LOOP_DEV" cryptsetup create $TARGET_NAME $LOOP_DEV if [ $? -ne 0 ] ; then echo "ERROR: cryptsetup fail" 1>&2 exit 1 fi mkdir /mnt_$TARGET_NAME mount /dev/mapper/$TARGET_NAME /mnt_$TARGET_NAME if [ $? -ne 0 ] ; then echo "ERROR: mount fail" 1>&2 exit 1 fi echo "/mnt_$TARGET_NAME is usable" exit 0
2013-06-22追記
上に書いたバックアップ運用に加えて、圧縮処理について、最終格納先 ZFS の透過圧縮 (compression=on) に期待するとうまく行きません。暗号化後のデータは圧縮しにくいためです。そこで、dm-crypt デバイスの上で使うファイルシステムを xfs から Btrfs に変更して、compress=lzo オプションで圧縮を試みました。しかし、残念ながら現状の Btrfs では全くといっていいほど圧縮できませんでした(圧縮オプションを zlib に変えても結果は同じ)。
他に透過圧縮できるファイルシステムは何があるだろ?とサーチしてみて、ntfs-3g でも透過圧縮できるようなので、試してみました。
# mkntfs -Q -C /dev/mapper/vault-xxx # mount -t ntfs -o compression /dev/mapper/vault-xxx /mnt # mkdir /mnt/compress_folder # setfattr -h -v 0x10080000 -n system.ntfs_attrib /mnt/compress_folderntfs-3g の場合、こんな具合にセットアップするようです。実際動かしてみると、圧縮はそこそこ出来たのですが、処理スピードは相当に遅めでした。Windows で NTFS 圧縮した経験からも遅いだろうとは予想してましたが、ちょっと、自分の運用には耐えらないほど遅かったです。
2013-06-23追記
ZFS 二段重ねは重いような気がしてましたが、dm-crypt デバイス上で使うファイルシステムも ZFS にして、compression=lz4 を使うとなかなか良好な結果でした。一時もうそれで十分と思いましたが、さらに調べたところ、Btrfs には compress-force というオプションもあることを知りました。試してみると、ZFS 二段重ねよりも高速に処理可能で、compress-force=zlib が最も良好な結果(処理時間が短くて圧縮率高い)でした。compress-force=lzo も試しましたが、処理時間はさほど短くならず、圧縮率も ZFS (compression=lz4) より下でした。なお、Btrfs (compress-force=zlib) の圧縮率は、ZFS (compression=gzip-1) とほぼ同じでした。
以上から、Btrfs (compress-force=zlib) を利用しようかと思います。初めて Btrfs に利点を感じました。
0 件のコメント:
コメントを投稿