Windows Serverバックアップに基づいたLinuxのバックアップネットワークボール(samba)

アーカイブへの便利なアクセス(およびこれらのアーカイブの作成)をWindowsで実行しているクライアントのネットワークボールにします。



はじめに



Windows Serverバックアップとシャドウコピーが優れているのはなぜですか? これらはWindows Serverの配信に含まれており、追加料金を必要とせず(クラウドアーカイブを使用しない場合)、割り当てられたタスクにも十分に対応できます。 シンプルなユースケースには、非常に価値のあるソリューションです。 また、ファイルプロパティダイアログを介したシャドウコピーへのアクセスは、一般的に非常に便利です。 次に、Sambaを使用してLinuxファイルサーバーに対して同じことを試してみましょう。



ファイルの以前のバージョンにアクセスする



この機会は、Samba shadow_copy2モジュールによって提供されます。 smb.confファイルのネットワークリソースセクションに記述する必要があります。



[share] vfs objects = shadow_copy2 shadow:snapdir = /mnt/.share path = /mnt/share
      
      





最初のバージョンのモジュールとは異なり、このモジュールでは、異なる場所に異なる名前でコピーしたフォルダーを配置できます。



ここで、path = /mnt/.shareフォルダー内にサブフォルダー@ GMT-2016.12.25-10.17.52を作成します

その後、何もうまくいきません。 [general]セクションに次の設定を追加します。



  wide links = yes #  samba     unix extensions = no #  *nix     (   , #     ) allow insecure wide links = no #     yes    unix extensions #  wide links  ,      
      
      





これで、以前のバージョンセクションのネットワークボールのプロパティに、「コピー」が表示されます。 時刻はUTCで示され、タイムゾーンによってローカルに変換されることに注意してください。



アーカイブとスナップショットの作成



コピーを作成するためのメカニズムなしでコピーにアクセスするためのメカニズムを持つことは無意味です。 次のスクリプトはこれに役立ちます( 公式の類似物もあります)。



thin_lv_backup.sh
 #!/bin/bash # # LVM-ThinVolume BackUp with rsync script set # # (c) 2016 - # Andrew Leshkevich (magicgts@gmail.com) # # # This script set is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 2 of the license or, at your # option, any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see <http://www.gnu.org/licenses/>. # # For a list of supported commands, type 'thin_lv_backup help' # # !!! Please forgive me for bad english !!! # ################################################################################################ ################################################################################################ #Mount the snapshot to the specified mount point, if a snapshot is not active, then activate it # Arguments: # ${1} - Short path to Volume (in VG/LV format) # ${2} - Mount point # ${3} - Optional LMV Volume attribute # Returns: # Return 0 if no errors ################################################################################################ mount_snapshot(){ local SRC=${1} local MNT_TGT=${2} [ "$#" -lt 2 ] && echo 'Error: expected <VOLUME GROUP>/<LOGICAL VOLUME SNAPSHOT> <MOUNT POINT> [<VOLUME ATTRIBUTES>]' && return 1 if [ "$#" -eq 2 ]; then local ATTR=$(lvs --noheadings -o lv_attr ${SRC}) else local ATTR=${3} fi findmnt -nf --source /dev/${SRC} >/dev/null 2>&1 && echo "Skip: LV ${SRC} is already mounted!" && return 0 findmnt -nf --target ${MNT_TGT} >/dev/null 2>&1 | grep -v -q ${MNT_TGT} && echo "Skip: the directory ${MNT_TGT} is already a mount point" && return 3 if [ ! -d "${MNT_TGT}" ]; then mkdir -p "${MNT_TGT}" || echo "Error: Creating directory ${MNT_TGT}" || return 4 echo "Info: directory ${MNT_TGT} has been created" fi find ${MNT_TGT} -prune -empty | grep -v -q ${MNT_TGT} && echo "Skip: ${MNT_TGT} directory is not empty" && return 5 [[ ${ATTR} =~ .*a.* ]] || lvchange -ay -K ${SRC} || echo "Error: Volume Activation ${SRC}" || return 6 mount -o ro,nouuid /dev/${SRC} ${MNT_TGT} || echo "Error: Mounting ${MNT_TGT}" || return 7 return 0 } ################################################################################################ # UnMount snaphot, deactivate volume and remove it mount point directory # Arguments: # ${1} - Short path to Volume (in VG/LV format) # Returns: # Return 0 if no errors ################################################################################################ umount_snapshot(){ local SRC=${1} local TGT [ "$#" -ne 1 ] && echo 'Error: expected <VOLUME GROUP>/<LOGICAL VOLUME SNAPSHOT>' && return 1 local _TGT=("$( findmnt -nf --source /dev/${SRC} | cut -d ' ' -f 1 )") if [ ! -z "$_TGT" ]; then umount -A /dev/${SRC} || echo "Error: Umounting ${SRC}" || return 2 for TGT in "${_TGT[@]}"; do find ${TGT} -prune -empty | grep -q "${TGT}" && rm --one-file-system -df ${TGT} [ -d "${TGT}" ] && echo "Info: Fail to remove target directory ${TGT}" done fi lvchange -an -K ${SRC} || echo "Error: Volume Deactivation ${SRC}" || return 3 return 0 } ################################################################################################ # Mount all associated snapshots of the volume to its origin mount points # All snapshots must be named on the template: <ORIGIN VOLUME NAME>-GMT-%Y.%m.%d-%H.%M.%S # Arguments: # ${1} - Short path to Origin Volume (in VG/LV format) # ${2} - Optional archive volume group, that used to mount all archive snapshots # Returns: # Return 0 if no errors ################################################################################################ mount_all_snapshot(){ local SRC=${1} local A_VG=${2} local ATTR_S local SNAP [ "$#" -lt 1 ] && echo 'Error: expected <VOLUME GROUP>/<LOGICAL VOLUME> [<ARCHIVE VOLUME GROUP>]' && exit 1 IFS=$'/' read -r -a ATTR_S <<< "${SRC}" [ "$#" -eq 2 ] && ATTR_S[0]=${A_VG} local SRC="$( findmnt -nf --source /dev/${SRC} | cut -d ' ' -f 1 )/" local DST_BASE="$( dirname ${SRC} )/.$( basename ${SRC} )/" while IFS='' read -r SNAP; do IFS=$' \t' read -r -a ATTR <<< "${SNAP}" local DST=${ATTR[0]//${ATTR_S[1]}-/} mount_snapshot ${ATTR_S[0]}/${ATTR[0]} ${DST_BASE}@${DST} ${ATTR[1]} || echo "Error: mounting ${ATTR_S[0]}/${ATTR[0]}" done < <( lvs --noheadings -o lv_name,lv_attr -S Origin=${ATTR_S[1]} ${ATTR_S[0]} ) } ################################################################################################ # UnMount and Remove snapshot # Arguments: # ${1} - Short path to Snapshot Volume (in VG/LV format) # Returns: # Return 0 if no errors ################################################################################################ remove_snaphot(){ local TGT=${1} local ATTR_S [ "$#" -ne 1 ] && echo 'Error: expected <VOLUME GROUP>/<LOGICAL VOLUME SNAPSHOT>' && return 1 IFS=$'/' read -r -a ATTR_S <<< "${TGT}" [ -z $(lvs --noheadings -o Origin -S lv_name=${ATTR_S[1]} ${ATTR_S[0]}) ] && echo "Error: not a snapshot ${TGT}" && return 2 umount_snapshot ${TGT} || echo "Error: umounting snapshot ${TGT}" || return 3 lvremove -f /dev/${TGT} || echo "Error: removing snapshot ${TGT}" || return 4 return 0 } ################################################################################################ # Create and Mount it to hidden folder on top level with same name as Original mount point # Arguments: # ${1} - Short path to Origin Volume (in VG/LV format) # ${2} - Optional postfix, that replace default postfix GMT-%Y.%m.%d-%H.%M.%S # Returns: # Return 0 if no errors ################################################################################################ create_snaphot(){ local TGT=${1} local ATTR_S [ "$#" -lt 1 ] && echo 'Error: expected <VOLUME GROUP>/<LOGICAL VOLUME> [<POSTFIX>]' && exit 1 local DATE=$(date -u +GMT-%Y.%m.%d-%H.%M.%S) [ "$#" -eq 2 ] && DATE="${2}" IFS=$'/' read -r -a ATTR_S <<< "${TGT}" lvcreate -n ${ATTR_S[1]}-${DATE} -s /dev/${TGT} || echo "Error: Creating snapshot of ${TGT}" || return 2 local SRC="$( findmnt -nf --source /dev/${TGT} | cut -d ' ' -f 1 )/" local DST_BASE="$( dirname $SRC )/.$( basename $SRC )/" mount_snapshot ${TGT}-${DATE} ${DST_BASE}@${DATE} || echo "Error: Mounting snapshot ${TGT}-${DATE}" || return 3 } ################################################################################################ # Remove old snaphots and keep last N snapshot # Arguments: # ${1} - Short path to Origin Volume (in VG/LV format) # ${2} - Number of keeping snapshot # Returns: # Return 0 if no errors ################################################################################################ remove_old_snapshot_copy(){ local TGT=${1} local NUM=${2} local SNAP local ATTR_S local ATTR [ "$#" -ne 2 ] && echo 'Error: expected <VOLUME GROUP>/<LOGICAL VOLUME> <NUMBER OF KEEP>' && return 1 IFS=$'/' read -r -a ATTR_S <<< "${TGT}" while IFS='' read -r SNAP; do IFS=$' \t' read -r -a ATTR <<< "${SNAP}" local DST=${ATTR[0]//${ATTR_S[1]}-/} remove_snaphot ${ATTR_S[0]}/${ATTR[0]} || echo "Error: removing snapshot ${ATTR_S[0]}/${ATTR[0]}" done < <( (lvs --noheadings -O -lv_name -o lv_name -S Origin=${ATTR_S[1]} ${ATTR_S[0]}) | head -n -${NUM} ) return 0 } ################################################################################################ # Prepare archive operation # Arguments: # ${1} - Short path to Origin Volume (in VG/LV format) # ${2} - Mount point for ${1} # Returns: # Return 0 if no errors ################################################################################################ pre_archive(){ [ "$#" -ne 2 ] && echo 'Error: expected <VOLUME GROUP>/<LOGICAL VOLUME> <MOUNT POINT>' && return 1 local VOL_SRC=${1} local MNT_TGT=${2} mkdir -p ${MNT_TGT} mount /dev/${VOL_SRC} ${MNT_TGT} || echo "Error: Mounting ${MNT_TGT}" || return 7 } ################################################################################################ # Post archive operation: unmount target volume, remove its mount point, create its snaphot # Arguments: # ${1} - Short path to Origin Volume (in VG/LV format) # ${2} - Mount point for ${1} # Returns: # Return 0 if no errors ################################################################################################ post_archive(){ [ "$#" -ne 3 ] && echo 'Error: expected <VOLUME GROUP>/<LOGICAL VOLUME> <MOUNT POINT> <VOLUME GROUP>/<LOGICAL VOLUME>' && return 1 local VOL_SRC=${1} local MNT_TGT=${2} local TGT=${3} umount /dev/${VOL_SRC} && rm -rd ${MNT_TGT} && lvcreate -n ${TGT} -s /dev/${VOL_SRC} && return 0 return 1 } ################################################################################################ # Create rsync archive # Arguments: # ${1} - Short path to Origin Volume (in VG/LV format) # ${2} - Name of archive Volume Group # ${3} - Optional connection string in <user name>@<host name> format # ${4} - Optional path to this script on remote machine # ${5} - Optional prefix name for volume name on remote machine (<PREFIX>-<VOLUME NAME>-GMT-%Y.%m.%d-%H.%M.%S) # ${6} - Optional also make local archive # Returns: # Return 0 if no errors ################################################################################################ create_archive(){ local SRC=${1} local TGT=${2} local CONN=${3} local CALL=${4} local PREFIX=${5} local ATTR_S local ATTR_D local RESULTS local RET [ "$#" -lt 2 ] && echo 'Error: expected <ORIG VOLUME GROUP>/<ORIG LOGICAL VOLUME> <DST VOLUME GROUP> [<SSH CONNECT> <SCRIPT CALL> <PREFIX> [<LOCAL COPY?>]]' && return 1 IFS=$'/' read -r -a ATTR_S <<< "${SRC}" IFS=$'/' read -r -a ATTR_D <<< "${TGT}" local SRC="$( findmnt -nf --source /dev/${ATTR_S[0]}/${ATTR_S[1]} | cut -d ' ' -f 1 )/" local DST_BASE="$( dirname $SRC )/.$( basename $SRC )/" create_snaphot ${ATTR_S[0]}/${ATTR_S[1]} archive_orig local DATE=$(date -u +GMT-%Y.%m.%d-%H.%M.%S) if [ "$#" -ge 5 ]; then RESULTS=$(ssh ${CONN} "${CALL} pre_archive ${TGT}/${PREFIX}-${ATTR_S[1]} ${DST_BASE}@archive_dst") RET=$? echo "$RESULTS" [ "${RET}" -ne 0 ] && return ${RET} rsync -aAXx --delete --inplace --no-whole-file ${DST_BASE}@archive_orig/ ${CONN}:${DST_BASE}@archive_dst &&\ RESULTS=$(ssh ${CONN} "${CALL} post_archive ${TGT}/${PREFIX}-${ATTR_S[1]} ${DST_BASE}@archive_dst ${PREFIX}-${ATTR_S[1]}-${DATE}") RET=$? echo "$RESULTS" [ "${RET}" -ne 0 ] && return ${RET} fi if [ "$#" -eq 2 ] || [ "$#" -eq 6 ]; then pre_archive ${TGT}/${ATTR_S[1]} ${DST_BASE}@archive_dst rsync -aAXx --delete ${DST_BASE}@archive_orig/ ${DST_BASE}@archive_dst &&\ post_archive ${TGT}/${ATTR_S[1]} ${DST_BASE}@archive_dst ${ATTR_S[1]}-${DATE} RET=$? [ "${RET}" -ne 0 ] && return ${RET} mount_snapshot ${TGT}/${ATTR_S[1]}-${DATE} ${DST_BASE}@${DATE} else echo 'Error: expected <ORIG VOLUME GROUP>/<ORIG LOGICAL VOLUME> <DST VOLUME GROUP> [<SSH CONNECT> <SCRIPT CALL> <PREFIX> [<LOCAL COPY?>]]>' && return 1 fi remove_snaphot ${ATTR_S[0]}/${ATTR_S[1]}-archive_orig } case ${1} in 'help') [ -z "${2}" ] && echo -e "create - create snapshot and mount it\nmount - mount snapshot\numount unmount snapshot\nmount_all - mount all snapshot\n\ remove - remove snapshot\nremove_old - keep last n snapshot\ncreate_archive - create archive" case ${2} in 'create') echo 'thin_lv_backup.sh create <VOLUME GROUP>/<LOGICAL VOLUME> [<POSTFIX>]' ;; 'mount') echo 'thin_lv_backup.sh mount <VOLUME GROUP>/<LOGICAL VOLUME SNAPSHOT> <MOUNT POINT> [<VOLUME ATTRIBUTES>]' ;; 'umount') echo 'thin_lv_backup.sh umount <VOLUME GROUP>/<LOGICAL VOLUME SNAPSHOT>' ;; 'mount_all') echo 'thin_lv_backup.sh mount_all <VOLUME GROUP>/<LOGICAL VOLUME> [<ARCHIVE VOLUME GROUP>]' ;; 'remove') echo 'thin_lv_backup.sh remove <VOLUME GROUP>/<LOGICAL VOLUME SNAPSHOT>' ;; 'remove_old') echo 'thin_lv_backup.sh remove_old <VOLUME GROUP>/<LOGICAL VOLUME> <NUMBER OF KEEP>' ;; 'create_archive') echo 'thin_lv_backup.sh create_archive <ORIG VOLUME GROUP>/<ORIG LOGICAL VOLUME> <DST VOLUME GROUP> [<SSH CONNECT> <SCRIPT CALL> <PREFIX> [<LOCAL COPY?>]]' ;; esac ;; 'create') create_snaphot $2 $3 ;; 'mount') mount_snapshot $2 $3 $4 ;; 'umount') umount_snapshot $2 ;; 'mount_all') mount_all_snapshot $2 $3 ;; 'remove') remove_snaphot $2 ;; 'remove_old') remove_old_snapshot_copy $2 $3 ;; 'create_archive') create_archive $2 $3 $4 $5 $6 $7 ;; 'pre_archive') pre_archive $2 $3 ;; 'post_archive') post_archive $2 $3 $4 ;; esac
      
      







免責事項
スクリプトは(私が私の手を満たす限り)完全ではなく、あなたの誠意に依存しています(引数の正確さの検証はなく、量だけがあります)。 ただし、データを可能な限り安全にしようとしました(ボリュームは削除せず、スナップショットのみを削除し、空のディレクトリのみを削除します)。 改善と修正のためのあなたの提案は大歓迎です。


作業には、LVM ThinVolumesを使用する必要があります。 通常のボリュームと比較して、そのパフォーマンスはスナップショットの数にわずかに依存します(COWは、「新しい」ブロックを変更するときにパフォーマンスを2〜3倍低下させます。スナップショットが2つ以上ある場合、作業はフリーズします)。



アーカイブコピーを作成する原則:



  1. ソースボリュームのスナップショットを作成してマウントする
  2. マウント先ボリューム
  3. rsyncを使用してコピーする
  4. 宛先ボリュームをアンマウントし、スナップショットにします
  5. ソーススナップショットをアンマウントして削除する
  6. ローカルアーカイブの場合、アーカイブボリュームの最後のスナップショットをマウントします


したがって、通常の増分バックアップを取得します。 オプションで、btrfsまたはZFSに適合させることができます。



使用する



スナップショットを作成し、ボール(ボールを含むフォルダー)という名前の隠しディレクトリにマウントします。



 /usr/local/bin/thin_lv_backup.sh create vg_system/share
      
      





別のボリュームグループでrsyncを使用してアーカイブを作成します。



 /usr/local/bin/thin_lv_backup.sh create_archive vg_system/share vg_archive
      
      





rsyncを使用してリモートアーカイブを作成します。



 /usr/local/bin/thin_lv_backup.sh create_archive vg_system/share vg_archive archive@archive.localdomain 'sudo /usr/local/bin/thin_lv_backup.sh' srv1
      
      





rsyncを使用してリモートおよびローカルアーカイブを作成します。



 /usr/local/bin/thin_lv_backup.sh create_archive vg_system/share vg_archive archive@archive.localdomain 'sudo /usr/local/bin/thin_lv_backup.sh' srv1 true
      
      





古いコピーを削除する(Nを最後に残す):



 /usr/local/bin/thin_lv_backup.sh remove_old vg_system/share 5
      
      





オンラインヘルプ:



 /usr/local/bin/thin_lv_backup.sh help
      
      





 /usr/local/bin/thin_lv_backup.sh help mount_all
      
      






All Articles