Бэкап сервер на linux для windows сетей

Бэкап сетевой шары (samba) в Linux по мотивам Windows Server Backup

Чем хороша служба Windows Server Backup и теневые копии? Они входят в поставку Windows Server и не требуют доплаты (если не использовать облачную архивацию), а также хорошо справляются с возложенными на них задачами. Для простых сценариев использования — очень достойное решение. А доступ к теневым копиям через диалог свойств файла — вообще очень удобен. Теперь попробуем сделать аналогично для файлового сервера Linux с Samba.

Доступ к предыдущим версиям файлов

Эту возможность нам дает модуль 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 и преобразуется в локальное по часовому поясу.

Создание архивов и snapshot

Иметь механизм доступа к копиям без механизма их создания — бесполезно. В этом нам поможет следующий скрипт (есть и официальный аналог):

#!/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 . # # 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: # $ - Short path to Volume (in VG/LV format) # $ - Mount point # $ - Optional LMV Volume attribute # Returns: # Return 0 if no errors ################################################################################################ mount_snapshot() < local SRC=$local MNT_TGT=$ [ "$#" -lt 2 ] && echo 'Error: expected /  []' && return 1 if [ "$#" -eq 2 ]; then local ATTR=$(lvs --noheadings -o lv_attr $) else local ATTR=$ fi findmnt -nf --source /dev/$ >/dev/null 2>&1 && echo "Skip: LV $ is already mounted!" && return 0 findmnt -nf --target $ >/dev/null 2>&1 | grep -v -q $ && echo "Skip: the directory $ is already a mount point" && return 3 if [ ! -d "$" ]; then mkdir -p "$" || echo "Error: Creating directory $" || return 4 echo "Info: directory $ has been created" fi find $ -prune -empty | grep -v -q $ && echo "Skip: $ directory is not empty" && return 5 [[ $ =~ .*a.* ]] || lvchange -ay -K $ || echo "Error: Volume Activation $" || return 6 mount -o ro,nouuid /dev/$ $ || echo "Error: Mounting $" || return 7 return 0 > ################################################################################################ # UnMount snaphot, deactivate volume and remove it mount point directory # Arguments: # $ - Short path to Volume (in VG/LV format) # Returns: # Return 0 if no errors ################################################################################################ umount_snapshot() < local SRC=$local TGT [ "$#" -ne 1 ] && echo 'Error: expected /' && return 1 local _TGT=("$( findmnt -nf --source /dev/$ | cut -d ' ' -f 1 )") if [ ! -z "$_TGT" ]; then umount -A /dev/$ || echo "Error: Umounting $" || return 2 for TGT in "$"; do find $ -prune -empty | grep -q "$" && rm --one-file-system -df $ [ -d "$" ] && echo "Info: Fail to remove target directory $" done fi lvchange -an -K $ || echo "Error: Volume Deactivation $" || return 3 return 0 > ################################################################################################ # Mount all associated snapshots of the volume to its origin mount points # All snapshots must be named on the template: -GMT-%Y.%m.%d-%H.%M.%S # Arguments: # $ - Short path to Origin Volume (in VG/LV format) # $ - Optional archive volume group, that used to mount all archive snapshots # Returns: # Return 0 if no errors ################################################################################################ mount_all_snapshot() < local SRC=$local A_VG=$ local ATTR_S local SNAP [ "$#" -lt 1 ] && echo 'Error: expected / []' && exit 1 IFS=$'/' read -r -a ATTR_S <<< "$" [ "$#" -eq 2 ] && ATTR_S[0]=$ local SRC="$( findmnt -nf --source /dev/$ | cut -d ' ' -f 1 )/" local DST_BASE="$( dirname $ )/.$( basename $ )/" while IFS='' read -r SNAP; do IFS=$' \t' read -r -a ATTR " local DST=$-/> mount_snapshot $/$ $@$ $ || echo "Error: mounting $/$" done < <( lvs --noheadings -o lv_name,lv_attr -S Origin=$$ ) > ################################################################################################ # UnMount and Remove snapshot # Arguments: # $ - Short path to Snapshot Volume (in VG/LV format) # Returns: # Return 0 if no errors ################################################################################################ remove_snaphot() < local TGT=$local ATTR_S [ "$#" -ne 1 ] && echo 'Error: expected /' && return 1 IFS=$'/' read -r -a ATTR_S <<< "$" [ -z $(lvs --noheadings -o Origin -S lv_name=$ $) ] && echo "Error: not a snapshot $" && return 2 umount_snapshot $ || echo "Error: umounting snapshot $" || return 3 lvremove -f /dev/$ || echo "Error: removing snapshot $" || return 4 return 0 > ################################################################################################ # Create and Mount it to hidden folder on top level with same name as Original mount point # Arguments: # $ - Short path to Origin Volume (in VG/LV format) # $ - Optional postfix, that replace default postfix GMT-%Y.%m.%d-%H.%M.%S # Returns: # Return 0 if no errors ################################################################################################ create_snaphot() < local TGT=$local ATTR_S [ "$#" -lt 1 ] && echo 'Error: expected / []' && exit 1 local DATE=$(date -u +GMT-%Y.%m.%d-%H.%M.%S) [ "$#" -eq 2 ] && DATE="$" IFS=$'/' read -r -a ATTR_S <<< "$" lvcreate -n $-$ -s /dev/$ || echo "Error: Creating snapshot of $" || return 2 local SRC="$( findmnt -nf --source /dev/$ | cut -d ' ' -f 1 )/" local DST_BASE="$( dirname $SRC )/.$( basename $SRC )/" mount_snapshot $-$ $@$ || echo "Error: Mounting snapshot $-$" || return 3 > ################################################################################################ # Remove old snaphots and keep last N snapshot # Arguments: # $ - Short path to Origin Volume (in VG/LV format) # $ - Number of keeping snapshot # Returns: # Return 0 if no errors ################################################################################################ remove_old_snapshot_copy() < local TGT=$local NUM=$ local SNAP local ATTR_S local ATTR [ "$#" -ne 2 ] && echo 'Error: expected / ' && return 1 IFS=$'/' read -r -a ATTR_S <<< "$" while IFS='' read -r SNAP; do IFS=$' \t' read -r -a ATTR " local DST=$-/> remove_snaphot $/$ || echo "Error: removing snapshot $/$" done < <( (lvs --noheadings -O -lv_name -o lv_name -S Origin=$$) | head -n -$ ) return 0 > ################################################################################################ # Prepare archive operation # Arguments: # $ - Short path to Origin Volume (in VG/LV format) # $ - Mount point for $ # Returns: # Return 0 if no errors ################################################################################################ pre_archive()< [ "$#" -ne 2 ] && echo 'Error: expected / ' && return 1 local VOL_SRC=$ local MNT_TGT=$ mkdir -p $ mount /dev/$ $ || echo "Error: Mounting $" || return 7 > ################################################################################################ # Post archive operation: unmount target volume, remove its mount point, create its snaphot # Arguments: # $ - Short path to Origin Volume (in VG/LV format) # $ - Mount point for $ # Returns: # Return 0 if no errors ################################################################################################ post_archive()< [ "$#" -ne 3 ] && echo 'Error: expected /  /' && return 1 local VOL_SRC=$ local MNT_TGT=$ local TGT=$ umount /dev/$ && rm -rd $ && lvcreate -n $ -s /dev/$ && return 0 return 1 > ################################################################################################ # Create rsync archive # Arguments: # $ - Short path to Origin Volume (in VG/LV format) # $ - Name of archive Volume Group # $ - Optional connection string in @ format # $ - Optional path to this script on remote machine # $ - Optional prefix name for volume name on remote machine (--GMT-%Y.%m.%d-%H.%M.%S) # $ - Optional also make local archive # Returns: # Return 0 if no errors ################################################################################################ create_archive() < local SRC=$local TGT=$ local CONN=$ local CALL=$ local PREFIX=$ local ATTR_S local ATTR_D local RESULTS local RET [ "$#" -lt 2 ] && echo 'Error: expected /  [   []]' && return 1 IFS=$'/' read -r -a ATTR_S <<< "$" IFS=$'/' read -r -a ATTR_D <<< "$" local SRC="$( findmnt -nf --source /dev/$/$ | cut -d ' ' -f 1 )/" local DST_BASE="$( dirname $SRC )/.$( basename $SRC )/" create_snaphot $/$ archive_orig local DATE=$(date -u +GMT-%Y.%m.%d-%H.%M.%S) if [ "$#" -ge 5 ]; then RESULTS=$(ssh $ "$ pre_archive $/$-$ $@archive_dst") RET=$? echo "$RESULTS" [ "$" -ne 0 ] && return $ rsync -aAXx --delete --inplace --no-whole-file $@archive_orig/ $:$@archive_dst &&\ RESULTS=$(ssh $ "$ post_archive $/$-$ $@archive_dst $-$-$") RET=$? echo "$RESULTS" [ "$" -ne 0 ] && return $ fi if [ "$#" -eq 2 ] || [ "$#" -eq 6 ]; then pre_archive $/$ $@archive_dst rsync -aAXx --delete $@archive_orig/ $@archive_dst &&\ post_archive $/$ $@archive_dst $-$ RET=$? [ "$" -ne 0 ] && return $ mount_snapshot $/$-$ $@$ else echo 'Error: expected /  [   []]>' && return 1 fi remove_snaphot $/$-archive_orig > case $ in 'help') [ -z "$" ] && 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 $ in 'create') echo 'thin_lv_backup.sh create / []' ;; 'mount') echo 'thin_lv_backup.sh mount /  []' ;; 'umount') echo 'thin_lv_backup.sh umount /' ;; 'mount_all') echo 'thin_lv_backup.sh mount_all / []' ;; 'remove') echo 'thin_lv_backup.sh remove /' ;; 'remove_old') echo 'thin_lv_backup.sh remove_old / ' ;; 'create_archive') echo 'thin_lv_backup.sh create_archive /  [   []]' ;; 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 

Скрипт не идеален (пока я набиваю руку) и опирается на вашу добросовестность (нет проверки на корректность аргументов, только на количество). Однако, я постарался сделать его максимально безопасным для данных (он не удаляет тома, только snapshot, удаляет только пустые каталоги). Ваши предложения, по улучшению и исправлению, только приветствуются.

Для работы необходимо использовать LVM ThinVolumes. По сравнению с обычными томами, их производительность слабо зависит от числа snapshot (COW снижает производительность в 2-3 раза, пока вы модифицируете «свежие» блоки, а если снимков 2 и более, то работа просто замирает).

Принцип создания архивных копий:

  1. Создать snapshot исходного тома и смонтировать его
  2. Смонтировать том назначения
  3. Провести копирование с помощью rsync
  4. Отмонтировать том назначения и сделать его snaphot
  5. Отмонтировать snapshot источника и удалить его
  6. При локальном архивировании, подмонтировать последний snapshot тома с архивом

Использование

Создать snapshot и примонтировать его в скрытый каталог с именем шары (папки содержащей шару):

/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

Источник

Читайте также:  Альт линукс общие папки
Оцените статью
Adblock
detector